__vic's C++ library (POSIX) v1.0 [Draft]

Contents
1 Introduction
1.1 Why this library was created?
1.2 General structure and usage
 
2 Library components reference
2.1 __vic/defs.h
2.1.1 nullptr [C++98 only]
2.1.2 noexcept [C++98 only]
2.1.3 array_size()
2.1.4 non_copyable
2.1.5 non_heap_allocatable
2.1.6 std::move(), std::forward(), std::swap() [C++11]
2.1.7 __VIC_SWAP_HEADER
2.1.8 Platform-dependent macros
2.2 __vic/algorithm.h
2.2.1 skip_if_front()
2.2.2 skip_if_back()
2.3 __vic/ascii.h
2.3.1 ascii::is-functions
2.3.2 ascii::todigit()
2.3.3 ascii::toxdigit_upper(), ascii::toxdigit_lower()
2.3.4 ascii::digit_to_number()
2.3.5 ascii::xdigit_to_number()
2.3.6 ascii::tolower(char), ascii::toupper(char)
2.3.7 ascii::equal_icase(char,char)
2.4 __vic/ascii_string.h
2.4.1 ascii::tolower()
2.4.2 ascii::toupper()
2.4.3 ascii::equal_icase()
2.5 __vic/base16.h
2.5.1 base16
2.5.2 base16::bad_format
2.5.3 base16::bad_digit
2.5.4 base16::bad_length
2.5.5 base16::status
2.5.6 base16::encode_upper()
2.5.7 base16::encode_lower()
2.5.8 base16::encode_byte_lower()
2.5.9 base16::encode_byte_upper()
2.5.10 base16::decode()
2.5.11 base16::try_decode()
2.6 __vic/base64.h
2.6.1 base64
2.6.2 base64::bad_format
2.6.3 base64::bad_digit
2.6.4 base64::bad_length
2.6.5 base64::status
2.6.6 base64::encode()
2.6.7 base64::decode()
2.6.8 base64::try_decode()
2.6.9 base64::encoded_length()
2.6.10 base64::max_decoded_length()
2.7 __vic/bin_file.h
2.7.1 bin_file
2.8 __vic/bits.h
2.8.1 lo_nibble(), hi_nibble()
2.8.2 msb_ones(), lsb_ones()
2.8.3 get_lsbs()
2.8.4 ord()
2.8.5 popcount()
2.8.6 msb_position()
2.8.7 ispow2()
2.8.8 ceil2()
2.8.9 floor2()
2.8.10 ceil_log2()
2.8.11 floor_log2()
2.8.12 rotl(), rotr()
2.8.13 swapped_nibbles()
2.9 __vic/bounded_vector.h
2.9.1 bounded_vector
2.10 __vic/date_time.h
2.10.1 is_leap_year()
2.10.2 days_in_month()
2.10.3 days_between_years()
2.10.4 invalid_date
2.10.5 validate_date(), validate_time(), validate_date_time()
2.11 __vic/endian.h
2.11.1 endianness
2.11.2 endian::from_...()
2.11.3 endian::to_...()
2.11.4 swab16(), swab32(), swab64()
2.12 __vic/error.h
2.12.1 exception
2.12.2 libc_error
2.13 __vic/fs.h
2.13.1 path_exists(), file_exists(), dir_exists()
2.13.2 mkdir(), mkdir_if_absent()
2.13.3 rmdir(), rmdir_if_exists()
2.13.4 get_current_dir()
2.13.5 remove_file(), remove_file_if_exists(), remove_file_nt()
2.13.6 copy_file(), copy_file_if_exists(), copy_file_replace(), copy_file_replace_if_exists()
2.13.7 move_file(), move_file_if_exists(), move_file_replace(), move_file_replace_if_exists()
2.13.8 rename_file(), rename_file_if_exists(), rename_file_replace(), rename_file_replace_if_exists()
2.13.9 file_size()
2.14 __vic/ip_addr.h
2.14.1 ipv4_addr
2.14.2 ipv6_addr
2.15 __vic/iterator.h
2.15.1 begin(T[]), end(T[]), cbegin(T[]), cend(T[])
2.15.2 advance()
2.15.3 next(), prev()
2.16 __vic/logger.h
2.16.1 logger
2.17 __vic/memory.h
2.17.1 load_unaligned()
2.17.2 store_unaligned()
2.18 __vic/mutex.h
2.18.1 mutex
2.18.2 mutex_lock
2.19 __vic/packon.h & __vic/packoff.h
2.20 __vic/readonly_cstring.h
2.20.1 readonly_cstring
2.21 __vic/set_of_chars.h
2.21.1 set_of_chars
2.22 __vic/stdint.h
2.22.1 Exact-width integer types
2.22.2 Minimum-width integer types
2.22.3 Fastest minimum-width integer types
2.22.4 Greatest-width integer types
2.22.5 Integer types capable of holding object pointers
2.22.6 int_exactly_bytes<>, uint_exactly_bytes<>
2.23 __vic/stdio_file.h
2.23.1 stdio_file
2.23.2 read(std::FILE)
2.23.3 write(std::FILE)
2.23.4 getline(std::FILE)
2.24 __vic/str2num.h
2.24.1 decimal_to_number()
2.24.2 decimal_to_number_range()
2.24.3 parse_decimal()
2.24.4 decimal_parser
2.24.5 number_parse_status
2.24.6 number_parse_result
2.25 __vic/string_buffer.h
2.25.1 string_buffer
2.26 __vic/string_ref.h
2.26.1 string_ref
2.27 __vic/string_utils.h
2.27.1 trim functions
2.27.2 sift()
2.27.3 sift_if()
2.27.4 pad_front()
2.27.5 pad_back()
2.27.6 starts_with()
2.27.7 ends_with()
2.28 __vic/tchar.h
2.28.1 tchar::length()
2.28.2 tchar::empty()
2.28.3 tchar::end()
2.28.4 tchar::compare()
2.28.5 tchar::equal()
2.28.6 tchar::copy()
2.28.7 tchar::move()
2.28.8 tchar::concat()
2.28.9 tchar::find()
2.28.10 tchar::rfind()
2.28.11 tchar::find_if()
2.28.12 tchar::find_if_not()
2.28.13 tchar::rfind_if()
2.28.14 tchar::rfind_if_not()
2.28.15 tchar::find_first_of()
2.28.16 tchar::find_first_not_of()
2.28.17 tchar::find_last_of()
2.28.18 tchar::find_last_not_of()
2.28.19 tchar::skip()
2.29 __vic/thread.h
2.29.1 thread
2.29.2 thread::id
2.29.3 this_thread
2.30 __vic/throw_errno.h
2.30.1 throw_errno()
2.31 __vic/to_text.h
2.31.1 to_text_append()
2.32 __vic/type_traits.h
2.32.1 integral_constant
2.32.2 true_type
2.32.3 false_type
2.32.4 is_same
2.32.5 is_const
2.32.6 is_byte
2.32.7 byte_cast()
2.32.8 is_signed_integer
2.32.9 is_unsigned_integer
2.32.10 conjunction [C++11]
2.32.11 disjunction [C++11]
2.32.12 negation
2.32.13 remove_const
2.32.14 remove_volatile
2.32.15 remove_cv
2.32.16 remove_reference
2.32.17 remove_cvref
2.32.18 remove_pointer
2.32.19 conditional
2.32.20 enable_if, disable_if
2.32.21 index_sequence, make_index_sequence [C++11]
2.33 __vic/unicode.h
2.33.1 unicode_t
2.33.2 utf_transcode()
2.33.3 Code point constants
2.34 __vic/utf8/status.h
2.34.1 utf8::status
2.34.2 utf8::is_error()
2.35 __vic/utf8/exceptions.h
2.36 __vic/utf8/read_result.h
2.36.1 utf8::read_result
2.36.2 utf8::convert_or_throw()
2.37 __vic/utf8/reader.h
2.37.1 utf8::reader
2.38 __vic/utf8/writer.h
2.38.1 utf8::writer
2.39 __vic/utf16/defs.h
2.39.1 utf16::code_unit_t
2.40 __vic/utf16/status.h
2.40.1 utf16::status
2.40.2 utf16::is_error()
2.41 __vic/utf16/exceptions.h
2.42 __vic/utf16/read_result.h
2.42.1 utf16::read_result
2.42.2 utf16::read_unit_result
2.42.3 utf16::convert_or_throw()
2.43 __vic/utf16/reader.h
2.43.1 utf16::reader
2.44 __vic/utf16/writer.h
2.44.1 utf16::writer
2.45 __vic/waitable_event.h
2.45.1 waitable_event
2.46 __vic/posix/cond_variable.h
2.46.1 posix::cond_variable
2.47 __vic/posix/daemon_control.h
2.47.1 posix::daemon_control
2.48 __vic/posix/dir_entries.h
2.48.1 posix::dir_entries
2.49 __vic/posix/dir_files.h
2.49.1 posix::dir_files
2.50 __vic/posix/error.h
2.50.1 posix::is_EAGAIN(), posix::is_ENOENT()
2.51 __vic/posix/file.h
2.51.1 posix::file
2.52 __vic/posix/file_stat.h
2.52.1 posix::file_stat
2.53 __vic/posix/fs.h
2.53.1 posix::basename(), posix::dirname()
2.53.2 posix::add_trailing_slash(), posix::with_trailing_slash()
2.54 __vic/posix/iov.h
2.54.1 posix::ovectors
2.54.2 posix::total(iovec[])
2.54.3 posix::cut_prefix(iovec[])
2.54.4 posix::writev_all()
2.55 __vic/posix/mutex.h
2.55.1 posix::mutex
2.55.2 posix::mutex_lock
2.56 __vic/posix/pidfile.h
2.56.1 posix::pidfile
2.57 __vic/posix/process.h
2.57.1 posix::daemon()
2.57.2 posix::ignore_signals()
2.57.3 posix::process_alive()
2.58 __vic/posix/sigset.h
2.58.1 posix::sigset
2.59 __vic/posix/thread.h
2.59.1 posix::this_thread
2.59.2 posix::this_thread::sigwait(), posix::this_thread::sigwait_at_most()
2.59.3 posix::this_thread::sigwaitinfo(), posix::this_thread::sigwaitinfo_at_most()
2.59.4 posix::this_thread::block_signals(), posix::this_thread::unblock_signals(), posix::this_thread::set_sigmask()
2.60 __vic/posix/time.h
2.60.1 posix::time_spec
2.60.2 posix::nanoseconds_since_epoch()
2.60.3 posix::realtime_clock, posix::monotonic_clock
 
3 S-readers
3.1 __vic/sreaders/defs.h
3.1.1 sreader [C++20]
3.1.2 byte_sreader [C++20]
3.1.3 sreader_result [C++20]
3.1.4 sreader_value_t
3.1.5 uchar_value()
3.2 __vic/sreaders/result.h
3.2.1 sread_result
3.2.2 sread_eof
3.3 Concrete sreaders
3.3.1 iterator_sreader
3.3.2 iterator_sreader_n
3.3.3 container_sreader
3.3.4 cstring_sreader
3.3.5 string_sreader
3.3.6 cstream_sreader
 
4 S-writers
4.1 __vic/swriters/defs.h
4.1.1 swriter [C++20]
4.2 Concrete swriters
4.2.1 null_swriter
4.2.2 push_back_swriter
4.2.3 iterator_swriter
4.2.4 string_swriter
4.2.5 cstream_swriter
 
5 Config library [C++11]
5.1 File format description
5.2 Representation in code
5.3 Implemetation details and additional features
5.4 __vic/config/parser.h [C++11]
5.4.1 config::parser [C++11]
5.5 __vic/config/value.h [C++11]
5.5.1 config::value [C++11]
5.5.2 config::list_traits [C++11]
5.6 Additional value parsers
5.6.1 config::value<std::optional<T>> [C++17]
5.6.2 config::value<__vic::ipv4_addr>
5.6.3 config::complex_value<std::optional<T>> [C++17]
5.6.4 config::list_traits<std::vector<T>>
5.6.5 config::list_traits<std::list<T>>
5.6.6 config::list_traits<std::forward_list<T>> [C++11]
5.6.7 config::bytes_value_parser
 
6 Build and install
 

1Introduction

1.1Why this library was created?

This library contains the features I'm missing in the Standard C++ library. It's a kind of my personal Boost.

Additionally, it's an abstraction layer that hides implementation details, quirks and idiosyncrasies of OS'es, compilers and the standard library implementations.

1.2General structure and usage

The topmost structural units of the library are headers and the library file (or archive) - lib__vic.a or __vic.lib. Usually the library file has some suffix like lib__vic14.a. All the headers are located in the __vic/ subdirectory. One should include them like this:

#include <__vic/header.h>

Where header.h is a name of the desired header.

Almost all the code is placed within __vic namespace, including other namespaces.

During program linking, the library file must be given to the linker. Example:

$ g++ -std=c++14 prog.cpp -l__vic14

The library can be built using one of the ISO C++ standards: C++98, C++11, C++14, C++17, C++20 or C++23. The standard suffix is used as a suffix for the library file (archive).

Some features require a specific minimal standard version to be available, e.g. many of them require at least C++11. These features are marked with [C++11] badge that means "C++11 or later".

Some features are available only in particular standard mode and not available otherwise. Such features are marked with [C++98 only] badge.

Detailed description of the library components is provided in the subsequent chapters. Descriptions are grouped by headers. C++23 language syntax is mainly used as a more complete and expressive one.

2Library components reference

2.1__vic/defs.h

Misc. fundamental definitions.

2.1.1nullptr [C++98 only]

Null pointer literal. Can be used instead of NULL or 0. In ISO C++ 98 mode defined as

const int nullptr = 0;

This definition allows to write C++11-style code using C++98 standard.

It is one of the few global definitions inroduced by the library. Definition can be prevented by definition __VIC_NO_NULLPTR_DEF macro before inclusion.

Example
int *p = nullptr;
pthread_create(&tid, nullptr, thread_func, nullptr);

2.1.2noexcept [C++98 only]

A macro in C++98 mode, synonym for throw(). In other standard modes the definition is absent.

2.1.3array_size()

template<class T, size_t N>
constexpr size_t array_size(T (&array)[N]);

Returns number of elements in the array. Can be used as a compile-time expression.

Example
int m[] = { 1, 2, 3, 5, 7 };

size_t n = __vic::array_size(m); // n == 5

int *dup = new int[n];

2.1.4non_copyable

class non_copyable
{
    non_copyable(const non_copyable &) = delete;
    non_copyable &operator=(const non_copyable &) = delete;
protected:
    non_copyable() = default;
};

Inheriting of this class suppresses generation of copy constructor and copy assignment. Same as boost::noncopyable.

Example
class C : private __vic::non_copyable
{
};

C c1;
C c2 = c1; // Error! Non-copyable object

2.1.5non_heap_allocatable

class non_heap_allocatable
{
    void *operator new(std::size_t ) = delete;
    void *operator new(std::size_t , const std::nothrow_t & ) = delete;
    void *operator new[](std::size_t ) = delete;
    void *operator new[](std::size_t , const std::nothrow_t & ) = delete;
protected:
    non_heap_allocatable() = default;
};

Inheriting of this class prevents creation of the class object on a free store using operator new.

Example
class C : private __vic::non_heap_allocatable
{
};

C c; // Ok. Allocation on stack
C *p = new C; // Error! Attempt to allocate on heap

2.1.6std::move(), std::forward(), std::swap() [C++11]

The header always includes this utilities in C++11 mode.

2.1.7__VIC_SWAP_HEADER

A macro for #include. Expands to the header name that contains std::swap() definition, dependig on the used language standard.

Example
#include __VIC_SWAP_HEADER

2.1.8Platform-dependent macros

The library provides set of compiler-independent macros that help to determine the target platform and some platform-specific traits by checking macro presence using #ifdef.

List of hardware platforms (processors):

Other macros:

2.2__vic/algorithm.h

Generic algorithms.

2.2.1skip_if_front()

template<
    std::forward_iterator Iter,
    std::predicate<std::iter_value_t<Iter>> Pred
>
Iter skip_if_front(Iter begin, Iter end, Pred pred);

Skips all leading elements that match the given predicate and returns new begin iterator.

2.2.2skip_if_back()

template<
    std::bidirectional_iterator Iter,
    std::predicate<std::iter_value_t<Iter>> Pred
>
Iter skip_if_back(Iter begin, Iter end, Pred pred);

Skips all trailing elements that match the given predicate and returns new end iterator.

2.3__vic/ascii.h

Fast, compact and locale-independent tools for ASCII-characters processing. All the tools are located within __vic::ascii namespace.

2.3.1ascii::is-functions

namespace ascii {

constexpr bool isdigit(char c);
constexpr bool isxdigit(char c);
constexpr bool islower(char c);
constexpr bool isupper(char c);
constexpr bool isalpha(char c);
constexpr bool isalnum(char c);
constexpr bool isspace(char c);
constexpr bool isblank(char c);
constexpr bool isprint(char c);
constexpr bool isgraph(char c);
constexpr bool ispunct(char c);
constexpr bool iscntrl(char c);
constexpr bool isascii(char c);

}

Counterparts of the corresponding <cctype> functions.

2.3.2ascii::todigit()

constexpr char ascii::todigit(int d);

Converts integer value from 0 to 9 to the decimal digit. The result is undefined if the input value goes beyond the range.

Precondition: 0 <= d && d <= 9

2.3.3ascii::toxdigit_upper(), ascii::toxdigit_lower()

namespace ascii {

constexpr char toxdigit_upper(int d);
constexpr char toxdigit_lower(int d);

}

Converts integer value from 0 to 15 to the hexadecimal digit. The first one uses upper case for A-F, the latter - lower. The result is undefined if the input value goes beyond the range.

Precondition: 0 <= d && d <= 15

2.3.4ascii::digit_to_number()

constexpr int ascii::digit_to_number(char d);

Converts the given decimal digit to the number if ascii::isdigit(d). -1 is returned otherwise.

2.3.5ascii::xdigit_to_number()

constexpr int ascii::xdigit_to_number(char d);

Converts the given hexadecimal digit to the number if ascii::isxdigit(d). -1 is returned otherwise.

2.3.6ascii::tolower(char), ascii::toupper(char)

namespace ascii {

constexpr char tolower(char c);
constexpr char toupper(char c);
constexpr char upper_to_lower(char upper);
constexpr char lower_to_upper(char lower);

}
constexpr char tolower(char c)
constexpr char toupper(char c)

Counterparts of the corresponding <cctype> functions.

constexpr char upper_to_lower(char upper)

More restricted counterpart of tolower(). The result is undefined if the argument is not an ASCII capital letter.

Precondition: ascii::isupper(upper)
constexpr char lower_to_upper(char lower)

More restricted counterpart of toupper(). The result is undefined if the argument is not an ASCII small letter.

Precondition: ascii::islower(lower)

2.3.7ascii::equal_icase(char,char)

constexpr bool ascii::equal_icase(char ch1, char ch2);

Checks equality of the two ASCII-characters ignoring the case.

2.4__vic/ascii_string.h

ASCII-strings processing tools.

2.4.1ascii::tolower()

namespace ascii {

char *tolower(char *str);
std::string &tolower(std::string &str);

}

Translates all Latin capital letters of str to the small ones. Returns str. C-string must not be nullptr!

2.4.2ascii::toupper()

namespace ascii {

char *toupper(char *str);
std::string &toupper(std::string &str);

}

Translates all Latin small letters of str to the capital ones. Returns str. C-string must not be nullptr!

2.4.3ascii::equal_icase()

namespace ascii {

bool equal_icase(const char *s1, const char *s2);
bool equal_icase(const char *s1, size_t s1_len,
                 const char *s2, size_t s2_len);

#if __cpp_lib_string_view // C++17

bool equal_icase(std::string_view s1, std::string_view s2);

#else // until C++17

bool equal_icase(const std::string &s1, const std::string &s2);
bool equal_icase(const std::string &s1, const char *s2);
bool equal_icase(const char *s1, const std::string &s2);

#endif
}

Checks equality of two ASCII-strings ignoring the case. The pointers must not be nullptr!

2.5__vic/base16.h

Base16 encoder and decoder.

2.5.1base16

A class used as a namespace. Contains only types, constants and static functions. No objects of this class are supposed to be created.

2.5.2base16::bad_format

struct base16::bad_format : public std::exception {};

Abstract base exception class.

2.5.3base16::bad_digit

struct base16::bad_digit : public base16::bad_format
{
    const char *what() const noexcept;
};

Exception class thrown by base16::decode() when the input sequence contains character that is not a valid HEX digit.

2.5.4base16::bad_length

struct base16::bad_length : public base16::bad_format
{
    const char *what() const noexcept;
};

Exception class thrown by base16::decode() when the input sequence length is odd.

2.5.5base16::status

enum class base16::status
{
    ok,
    invalid_length,
    invalid_digit
};
using base16::status_t = base16::status; // for C++98

Input sequence parsing outcome status codes returned by base16::try_decode().

2.5.6base16::encode_upper()

// Bytes -> Text
template<class ByteSReader, class CharSWriter>
void base16::encode_upper(ByteSReader reader, CharSWriter writer);

Encodes bytes from reader and writes the resulting characters to writer. Upper case is used for hexadecimal digits.

ByteSReader has to model sreader<unsigned char> concept. See S-readers.

CharSWriter has to model swriter<char> concept. See S-writers.

Example
#include<__vic/sreaders/string.h>
#include<__vic/swriters/string.h>

using bytes = std::string;
using bytes_sreader = __vic::string_sreader;

std::string encode_base16(const bytes &s)
{
    std::string res;
    res.reserve(s.length() * 2);
    __vic::base16::encode_upper(bytes_sreader(s), __vic::string_swriter(res));
    return res;
}

2.5.7base16::encode_lower()

// Bytes -> Text
template<class ByteSReader, class CharSWriter>
void base16::encode_lower(ByteSReader reader, CharSWriter writer);

Same as base16::encode_upper() but lower case is used for hexadecimal digits.

2.5.8base16::encode_byte_lower()

// Byte -> Text
template<class CharSWriter>
void base16::encode_byte_lower(unsigned char byte, CharSWriter writer);

Same as base16::encode_lower() but encodes only single byte.

2.5.9base16::encode_byte_upper()

// Byte -> Text
template<class CharSWriter>
void base16::encode_byte_upper(unsigned char byte, CharSWriter writer);

Same as base16::encode_upper() but encodes only single byte.

2.5.10base16::decode()

// Text -> Bytes
template<class CharSReader, class ByteSWriter>
void base16::decode(CharSReader reader, ByteSWriter writer);

Decodes characters from reader and writes the resulting bytes to writer. Exception derived from base16::bad_format is thrown if the input sequence has invalid Base16 format.

CharSReader has to model sreader<char> concept. See S-readers.

ByteSWriter has to model swriter<unsigned char> concept. See S-writers.

Example
#include<__vic/sreaders/string.h>
#include<__vic/swriters/string.h>

using bytes = std::string;
using bytes_swriter = __vic::string_swriter;

bytes decode_base16(const std::string &s)
{
    bytes res;
    res.reserve(s.length() / 2);
    __vic::base16::decode(__vic::string_sreader(s), bytes_swriter(res));
    return res;
}

2.5.11base16::try_decode()

// Text -> Bytes
template<class CharSReader, class ByteSWriter>
base16::status_t base16::try_decode(CharSReader reader, ByteSWriter writer);

Same as base16::decode() but returns base16::status different from base16::status::ok in case of invalid input sequence instead of throwing exception.

2.6__vic/base64.h

Base64 encoder and decoder.

2.6.1base64

A class used as a namespace. Contains only types, constants and static functions. No objects of this class are supposed to be created.

2.6.2base64::bad_format

struct base64::bad_format : public std::exception {};

Abstract base exception class.

2.6.3base64::bad_digit

struct base64::bad_digit : public base64::bad_format
{
    const char *what() const noexcept;
};

Exception class thrown by base64::decode() when the input sequence contains character that is not a valid Base64 digit.

2.6.4base64::bad_length

struct base64::bad_length : public base64::bad_format
{
    const char *what() const noexcept;
};

Exception class thrown by base64::decode() when the input sequence length is not a multiple of 4.

2.6.5base64::status

enum class base64::status
{
    ok,
    invalid_length,
    invalid_digit
};
using base64::status_t = base64::status; // for C++98

Input sequence parsing outcome status codes returned by base64::try_decode().

2.6.6base64::encode()

// Bytes -> Text
template<class ByteSReader, class CharSWriter>
void base64::encode(ByteSReader reader, CharSWriter writer);

Encodes bytes from reader and writes the resulting characters to writer.

ByteSReader has to model sreader<unsigned char> concept. See S-readers.

CharSWriter has to model swriter<char> concept. See S-writers.

Example
#include<__vic/sreaders/string.h>
#include<__vic/swriters/string.h>

using bytes = std::string;
using bytes_sreader = __vic::string_sreader;

std::string encode_base64(const bytes &s)
{
    std::string res;
    res.reserve(__vic::base64::encoded_length(s.length()));
    __vic::base64::encode(bytes_sreader(s), __vic::string_swriter(res));
    return res;
}

2.6.7base64::decode()

// Text -> Bytes
template<class CharSReader, class ByteSWriter>
void base64::decode(CharSReader reader, ByteSWriter writer);

Decodes characters form reader and writes the resulting bytes to writer. Exception derived from base64::bad_format is thrown if the input sequence has invalid Base64 format.

CharSReader has to model sreader<char> concept. See S-readers.

ByteSWriter has to model swriter<unsigned char> concept. See S-writers.

Example
#include<__vic/sreaders/string.h>
#include<__vic/swriters/string.h>

using bytes = std::string;
using bytes_swriter = __vic::string_swriter;

bytes decode_base64(const std::string &s)
{
    bytes res;
    res.reserve(__vic::base64::max_decoded_length(s.length()));
    __vic::base64::decode(__vic::string_sreader(s), bytes_swriter(res));
    return res;
}

2.6.8base64::try_decode()

// Text -> Bytes
template<class CharSReader, class ByteSWriter>
base64::status_t base64::try_decode(CharSReader reader, ByteSWriter writer);

Same as base64::decode() but returns base64::status different from base64::status::ok in case of invalid input sequence instead of throwing exception.

2.6.9base64::encoded_length()

constexpr size_t base64::encoded_length(size_t orig_len);

Calculates the length of encoded sequence of characters using the original length of the bytes sequence.

2.6.10base64::max_decoded_length()

constexpr size_t base64::max_decoded_length(size_t orig_len);

Estimates the maximum length of decoded sequence of bytes using the original length of the characters sequence. The actual value depends on trailing '=' in the encoded value.

2.7__vic/bin_file.h

2.7.1bin_file

class bin_file : private non_copyable
{
public:
    enum in_t { in };
    enum out_t { out };
    enum append_t { append };

    bin_file();
    bin_file(const char *fname, in_t);
    bin_file(const char *fname, out_t);
    bin_file(const char *fname, append_t);
    ~bin_file();

    // BEGIN C++11
    bin_file(bin_file &&o) noexcept;
    bin_file &operator=(bin_file &&o) noexcept;
    // END C++11

    bool open_in(const char *fname);
    bool open_out(const char *fname);
    bool open_append(const char *fname);

    size_t read_max(void *buf, size_t n);
    size_t read_some(void *buf, size_t n);

    void write_all(const void *buf, size_t n);

    bool is_open() const;
    void close();
    bool close_nt() noexcept;

    void swap(bin_file &o) noexcept;

    [[noreturn]] void throw_last_error(const char *msg);
    void throw_if_closed(const char *msg);
};

Unbuffered binary file. OS-independent wrapper for low-level system API.

Following open modes are available:

Class members
enum in_t { in }
enum out_t { out }
enum append_t { append }

Constructor tags.

bin_file()
Postcondition: is_open() == false()
bin_file(const char *fname, in_t)
bin_file(const char *fname, out_t)
bin_file(const char *fname, append_t)

Call open_in(fname), open_out(fname) or open_append(fname), correspondingly. is_open() or throw_if_closed() has to be called then to check the result.

~bin_file()

Closes the file if is_open() == true.

bin_file(bin_file &&o) noexcept [C++11]
bin_file &operator=(bin_file &&o) noexcept [C++11]

Move operations for C++11 mode.

bool open_in(const char *fname)
bool open_out(const char *fname)
bool open_append(const char *fname)

Open file for reading, writing or appending, correspondingly. Return is_open().

Precondition: is_open() == false
bool is_open() const

Returns true if file is open.

size_t read_max(void *buf, size_t n)

Tries to read n bytes to the specified buffer. Returns number of bytes read. Returned value can be less than requested only when end of file was reached. Throws on error.

Precondition: is_open() == true
size_t read_some(void *buf, size_t n)

Reads no more than n bytes to the specified buffer. Returns number of bytes read or 0 in case of end-of-file. The function returns after first chunk of any size was successfully received. Throws on error.

Precondition: is_open() == true
void write_all(const void *buf, size_t n)

Writes the whole buffer to the file. Throws on error.

Precondition: is_open() == true
void close()

Closes the file. Throws on error.

Precondition: is_open() == true
Postcondition: is_open() == false
bool close_nt() noexcept

A counterpart of close() but never throws, returns false instead in case of error.

void swap(bin_file &o) noexcept

Swaps the value with o.

[[noreturn]] void throw_last_error(const char *msg)

Throws exception with the last error description if available. what() will contain msg as a substring anyway.

void throw_if_closed(const char *msg)

Calls throw_last_error(msg) if !is_open().

Example
// Copy file
__vic::bin_file in("file", __vic::bin_file::in);
in.throw_if_closed("Cannot open file")
__vic::bin_file out("file.copy", __vic::bin_file::out);
out.throw_if_closed("Cannot create file")

char buf[512];
while(size_t n = in.read_some(buf, sizeof buf))
    out.write_all(buf, n);

out.close();
// in will be closed by destructor

2.8__vic/bits.h

Bits and bytes manipulation tools.

2.8.1lo_nibble(), hi_nibble()

constexpr uint8_t lo_nibble(uint8_t byte);
constexpr uint8_t hi_nibble(uint8_t byte);

Return the value of the low-order/high-order half-byte (tetrad), respectively.

2.8.2msb_ones(), lsb_ones()

template<class T> constexpr T lsb_ones(unsigned bits_num);
template<class T> constexpr T msb_ones(unsigned bits_num);

Return the value of the type T with all least/most significant bits_num bits filled with 1, respectively. All other bits are set to 0.

2.8.3get_lsbs()

template<class T> constexpr T get_lsbs(T v, unsigned bits_num);

Returns bits_num least significant bits of v. In other words, zeroes all but bits_num least significant bits.

2.8.4ord()

constexpr int ord(char ch);

Returns the character code from 0 to 255.

Postcondition: ord(ch) >= 0

2.8.5popcount()

unsigned popcount(unsigned v);
unsigned popcount(unsigned long v);
unsigned popcount(unsigned long long v);
unsigned popcount(unsigned short v);
unsigned popcount(unsigned char v);

Returns the number of one bits in the given value.

2.8.6msb_position()

unsigned msb_position(unsigned v)
unsigned msb_position(unsigned long v);
unsigned msb_position(unsigned long long v);
unsigned msb_position(unsigned short v);
unsigned msb_position(unsigned char v);
Precondition: v != 0

Returns the position of the most significant 1-bit. The result is unspecified if v == 0.

2.8.7ispow2()

template<class UInt>
bool ispow2(UInt n);
Precondition: UInt is an unsigned integer type

Returns true if n is an integral power of 2.

2.8.8ceil2()

template<class UInt>
UInt ceil2(UInt n);
Precondition: UInt is an unsigned integer type

Returns the minimal value m such that ispow2(m) && m >= n. If m is not representable as a value of type UInt, the result is an unspecified value.

2.8.9floor2()

template<class UInt>
UInt floor2(UInt n);
Precondition: UInt is an unsigned integer type

If n != 0 returns the maximal value m such that ispow2(m) && m <= n. Otherwise 0 is returned.

2.8.10ceil_log2()

template<class UInt>
unsigned ceil_log2(UInt n);
Precondition: UInt is an unsigned integer type

Returns ceil(log2(n)) if n != 0 or 0 otherwise.

2.8.11floor_log2()

template<class UInt>
unsigned floor_log2(UInt n);
Precondition: UInt is an unsigned integer type

Returns floor(log2(n)) if n != 0 or 0 otherwise.

2.8.12rotl(), rotr()

unsigned long long rotl(unsigned long long v, int shift);
unsigned long      rotl(unsigned long v, int shift);
unsigned           rotl(unsigned v, int shift);
unsigned short     rotl(unsigned short v, int shift);
unsigned char      rotl(unsigned char v, int shift);

unsigned long long rotr(unsigned long long v, int shift);
unsigned long      rotr(unsigned long v, int shift);
unsigned           rotr(unsigned v, int shift);
unsigned short     rotr(unsigned short v, int shift);
unsigned char      rotr(unsigned char v, int shift);

The functions perform circular left (rotl) or right (rotr) bitwise shift (rotation).

Precondition: 0 <= shift && shift < sizeof(v)*CHAR_BIT

2.8.13swapped_nibbles()

constexpr uint8_t swapped_nibbles(uint8_t b);

Swaps a low-order half-byte with a high-order one and returns the value.

2.9__vic/bounded_vector.h

2.9.1bounded_vector

template<class T>
class bounded_vector : private non_copyable
{
public:
    using value_type     = T;
    using iterator       = <implementation-defined>;
    using const_iterator = <implementation-defined>;

    bounded_vector();
    explicit bounded_vector(size_t max_size);
    ~bounded_vector();

    // BEGIN C++11
    bounded_vector(bounded_vector &&o) noexcept;
    bounded_vector &operator=(bounded_vector &&o) noexcept;
    template<class... Args> T &emplace_back(Args &&... args)
    // END C++11

    // size in objects
    size_t size() const;
    size_t capacity() const;
    bool full() const;
    bool empty() const;

    void recreate(size_t new_max_size, bool size_exact = false);
    void *alloc(); // returns pointer to memory for object allocation
    void push_allocated(); // adds last allocated object to the container
    void pop_back();
    void clear();
    void swap(bounded_vector &o) noexcept;

    // element access
    T &operator[](size_t i);
    iterator begin();
    iterator end();
    T &front();
    T &back();

    const T &operator[](size_t i) const;
    const_iterator begin() const;
    const_iterator end() const;
    const_iterator cbegin() const;
    const_iterator cend() const;
    const T &front() const;
    const T &back() const;
};
template<class T>
void swap(bounded_vector<T> &o1, bounded_vector<T> &o2) noexcept;

The standard containers in C++98 don't allow to store non-copiable elements. Even in C++11 elements of containers like std::vector have to be at least noexcept movable. This class solves the problem. It is a dynamic array for non-copyable objects or just std::vector without autogrowing capacity().

Without emplace_back() it is impossible to create arbitrary new object right in the container's memory. C++98 lacks forwarding references so it is ear impossible to pass arbitrary parameters to the element's constructor. bounded_vector overcomes this problem using the following mechanism. The new element is created using several phases:

  1. Requesting memory for the new element in the container - alloc(),
  2. Creation of the object using placement new - new(ptr) type(...),
  3. Fixation of the newly created object in the container - push_allocated().

See the example at the end of the article.

Maximum capacity is specified on creation of the container. Later it can be changed but all the elements has to be destroyed before. In other words, the container can be recreated (recreate() function).

When available, emplace_back() must be used for elements creation. If not, the unsafe interface described above must be used with care. It is very ugly and error-prone but solves the task. After the element is created in the container, you operate with it almost as easy as with any other copyable object in the standard container. Anyway, it is more efficient and convenient to use in general than alternative approaches like creating the objects on the free store and placing only pointers to the container, even if we have std::unique_ptr to manage lifetime of the objects.

Fundamental differences from std::vector:

  1. Elements don't have to be copyable or movable (std::vector requires at least noexcept-movability);
  2. Elements have stable addresses after addition of new element;
  3. emplace_back() has precondition (!full()).
Class members
typename value_type

Type of the elements.

typename iterator
typename const_iterator

Iterators.

bounded_vector()

Create the object without memory allocation.

Postcondition: capacity() == 0
explicit bounded_vector(size_t max_size)

Allocates memory for max_size elements.

Postcondition: capacity() == max_size
~bounded_vector()

Calls clear().

bounded_vector(bounded_vector &&o) noexcept [C++11]
bounded_vector &operator=(bounded_vector &&o) noexcept [C++11]

Move operations for C++11 mode.

size_t size() const
size_t capacity() const

Current size and capacity of the container.

bool empty() const

Returns size() == 0.

bool full() const

Returns size() == capacity().

void recreate(size_t new_max_size, bool size_exact = false)

Recreates the container. At first calls clear(), then reallocates memory buffer if new_max_size > capacity() or size_exact is true and new_max_size != capacity().

Postcondition: capacity() >= new_max_size && empty() == true (if size_exact == true then capacity() == new_max_size && empty() == true)
void *alloc()

Returns the raw memory block where new instance of value_type can be allocated.

Precondition: !full()
Note: Use emplace_back() in C++11 mode.
void push_allocated()

This call right after alloc() adds the just created object to the container.

template<class... Args> T &emplace_back(Args &&... args) [C++11]

Constructs new object and adds it to the container (alloc() + new + push_allocated() with a single call). A reference to the new object is returned.

Precondition: !full()
void pop_back()

Remove the last element from the container.

Precondition: !empty()
void clear()

Destroys the elements in the reverse order they were created.

Postcondition: size() == 0 (empty() == true)
void swap(bounded_vector &o)
template<class T> void swap(bounded_vector<T> &o1, bounded_vector<T> &o2) noexcept

Swaps the value with o.

T &operator[](size_t i)
const T &operator[](size_t i) const

Access to the elements by index.

Precondition: i < size()
T &front()
const T &front() const
T &back()
const T &back() const

Access to the first and the last elements.

Precondition: !empty()
iterator begin()
const_iterator begin() const
const_iterator cbegin() const
iterator end()
const_iterator end() const
const_iterator cend() const

Access to the elements via iterators.

Example
// Creating vector for 2 objects of class C
__vic::bounded_vector<C> v(2);

// Creating new object in C++98 mode:
new(v.alloc()) C(...); // Request memory and construct the object
v.push_allocated();    // Fixate successfully created object in the container

// Creating new object in C++11 mode:
v.emplace_back(...);

2.10__vic/date_time.h

Date and time utilies.

2.10.1is_leap_year()

constexpr bool is_leap_year(int year);

Determines if the year is a leap year according to Gregorian calendar.

2.10.2days_in_month()

int days_in_month(int month, int year);

Returns number of days in the month. Month is a number from 1 to 12. The second parameter is used only if the month is 2 (february), otherwise is just ignored.

2.10.3days_between_years()

long days_between_years(unsigned year1, unsigned year2);

Returns the difference in days between the beginning of the 2nd year and the beginning of the 1st year.

2.10.4invalid_date

class invalid_date; // : public std::exception

The exception thrown when the value of the date or time element is invalid.

2.10.5validate_date(), validate_time(), validate_date_time()

void validate_date(int yy, int mm, int dd);
void validate_time(int hh, int mi, int ss);
void validate_date_time(int yy, int mm, int dd, int hh, int mi, int ss);

Checks if the date/time value is valid. Following constraints are checked:

invalid_date is thrown in case of the constraint violation.

Note: Specific time values as 24:00:00 (midnight at the end of a day) or 59:60 (leap second) are considered as invalid!

2.11__vic/endian.h

Byte order-related utilities.

2.11.1endianness

namespace endian {
enum endianness
{
    unknown = 0,
    little  = 1234,
    big     = 4321,
    pdp     = 3412,
    native  = <one-of-the-above>
};
} // namespace

using endian::endianness;

Byte order constants. endian::native is set equal to one of the constants and represents the byte order used on the current platform (like __BYTE_ORDER__ macro on UNIX-like platforms). The values are supposed to be used for template specializations or for compile-time checks (e.g. in static_assert).

Examples
template<__vic::endianness > struct some_algo; // not implemented

// Implementation for little-endian
template<> struct some_algo<__vic::endian::little>
{
    static void doit() { ... }
};
// Implementation for big-endian
template<> struct some_algo<__vic::endian::big>
{
    static void doit() { ... }
};

// Automatically choose an appropriate implementation for the used platform
some_algo<__vic::endian::native>::doit();
static_assert(__vic::endian::native == __vic::endian:little,
    "Litte-endian is expected");

2.11.2endian::from_...()

template<class T> [[nodiscard]] constexpr T endian::from_little(T v);
template<class T> [[nodiscard]] constexpr T endian::from_big(T v);

Return a value represented in native byte order converted from litte/big endian if appropriate.

T can be any integral type or enum with size up to sizeof(long long).

Example
uint16_t v;
read_bytes(&v, 2); // serialized as big endian
std::cout << "The value is " << __vic::endian::from_big(v) << '\n';

2.11.3endian::to_...()

template<class T> [[nodiscard]] constexpr T endian::to_little(T v);
template<class T> [[nodiscard]] constexpr T endian::to_big(T v);

Return a value represented in litte/big endian byte order.

T can be any integral type or enum with size up to sizeof(long long).

Example
uint16_t v = __vic::endian::to_big(...);
write_bytes(&v, 2); // serialize as big endian

2.11.4swab16(), swab32(), swab64()

[[nodiscard]] constexpr uint16_t swab16(uint16_t v);
[[nodiscard]] constexpr uint32_t swab32(uint32_t v);
[[nodiscard]] constexpr uint64_t swab64(uint64_t v);

Fast utilities to reverse byte order (usually implemented using compiler-specific intrinsics).

Example
static_assert(__vic::swab32(0x01020304) == 0x04030201);

2.12__vic/error.h

Error handling tools.

2.12.1exception

class exception : public std::exception
{
public:
    exception();
    explicit exception(const char *message);
    const char *what() const noexcept;
protected:
    void set_message(const char *message);
};

Small extension of std::exception - the object carries message specified in the constructor, what() returns this message. Can be used either as a base or a concrete exception class. Does not use/depend on std::string as opposed to std::logic_error and std::runtime_error. You also don't have to decide which one of them you should use in the particular case.

Class members
exception()

Creates the object with an empty message.

explicit exception(const char *message)

Creates the object with the specified message.

const char *what() const noexcept

Returns the message specified before.

void set_message(const char *message)

Sets a new message.

Example
struct custom_exception : public __vic::exception
{
    explicit custom_exception(const char *msg) : __vic::exception(msg) {}
};

throw custom_exception("Error condition description");

2.12.2libc_error

class libc_error : public std::exception
{
public:
    explicit libc_error(int err_no = errno);
    explicit libc_error(const char *prompt, int err_no = errno);

    const char *what() const noexcept;
    int code() const;
    int get_errno() const;
};

This class is an easy and straightforward replacement of the standard error handling machinery used in the C-world - errno, with exceptions. The class is also suitable for usage in the multithread environment instead of not always reentrant call std::strerror().

Below you can see typical C code:

// C:

int fd;
if((fd = open("qqqq", O_RDONLY)) == -1)
{
    perror("open");
    if(errno == ENOENT) exit(1);
}

If the file is not found, the message like this

open: No such file or directory

is printed to stderr and the program exits with the status 1.

What issues are inherent in this code? Firstly, not every program has stderr, so a library function is not allowed to print error messages there. Secondly, the value of the global variable errno can be rewritten by any subsequent call unless the value is saved explicitly right after the call. Thirdly, the decision about termination of the process can only be made by the application. An ordinary library function is not allowed to do this. Fourthly, in general case C++ program cannot call std::exit(), because destructors of the live objects allocated on the stack won't be called, and program's logic can be corrupted.

The example adapted for C++ using our class:

// C++:

try
{
    int fd = open("qqqq", O_RDONLY);
    if(fd == -1) throw __vic::libc_error("open");
    // or just
    // if(fd == -1) throw __vic::libc_error();
}
catch(const __vic::libc_error &ex)
{
    std::cerr << ex.what() << '\n';
    if(ex.code() == ENOENT) return 1;
}

As it can be seen, the function handles erroneous situation correctly and reports it to the caller. Afterwards the caller can handle the error appropriately. In the elementary case it acts as the former C-program: prints the message to the standard error output stream and terminates. Moreover, error code is now saved in the exception and cannot be rewritten by accident.

Note: Usually exceptions of this class shouldn't be thrown explicitly! Use throw_errno() instead.
Class members
explicit libc_error(int err_no = errno)

err_no - error code.

Postcondition: code() == err_no
explicit libc_error(const char *prompt, int err_no = errno)

prompt - a title of the error message. The parameter has the same meaning as the parameter of std::perror().

const char *what() const noexcept

Returns error description in the std::perror() format.

int code() const
int get_errno() const

Returns stored error code.

2.13__vic/fs.h

Filesystem utilities.

Note: All paths are expected to be UTF-8 encoded!

2.13.1path_exists(), file_exists(), dir_exists()

bool path_exists(const char *path);
bool path_exists(const std::string &path);

bool file_exists(const char *path);
bool file_exists(const std::string &path);

bool dir_exists(const char *path);
bool dir_exists(const std::string &path);

path_exists() checks whether the path exists in the system. Second and third functions additionally check, besides the presence, if the path references to a regular file or to a directory, respectively.

2.13.2mkdir(), mkdir_if_absent()

void mkdir(const char *path, mode_t mode = 0777);
void mkdir(const std::string &path, mode_t mode = 0777);

bool mkdir_if_absent(const char *path, mode_t mode = 0777);
bool mkdir_if_absent(const std::string &path, mode_t mode = 0777);

Creates a directory. Throws exception in case of failure. mkdir_if_absent() returns false instead of throwing if the directory already exists.

2.13.3rmdir(), rmdir_if_exists()

void rmdir(const char *path);
void rmdir(const std::string &path);

bool rmdir_if_exists(const char *path);
bool rmdir_if_exists(const std::string &path);

Deletes an empty directory. Throws exception in case of failure. rmdir_if_exists() returns false instead of throwing if the directory doesn't exist.

2.13.4get_current_dir()

std::string get_current_dir();

Returns current working directory.

2.13.5remove_file(), remove_file_if_exists(), remove_file_nt()

void remove_file(const char *path);
void remove_file(const std::string &path);

bool remove_file_if_exists(const char *path);
bool remove_file_if_exists(const std::string &path);

bool remove_file_nt(const char *path) noexcept;
bool remove_file_nt(const std::string &path) noexcept;

Deletes the file. Throws exception in case of failure.

remove_file_if_exists() returns false instead of throwing if the file doesn't exist.

remove_file_nt() doestn't throw any exceptions at all, false is returned in case of failure.

2.13.6copy_file(), copy_file_if_exists(), copy_file_replace(), copy_file_replace_if_exists()

void copy_file(
    const char *src_path, const char *dest_path, bool replace = false);
void copy_file(
    const std::string &src_path, const std::string &dest_path,
    bool replace = false);

bool copy_file_if_exists(
    const char *src_path, const char *dest_path, bool replace = false);
bool copy_file_if_exists(
    const std::string &src_path, const std::string &dest_path,
    bool replace = false);

void copy_file_replace(
    const char *src_path, const char *dest_path);
void copy_file_replace(
    const std::string &src_path, const std::string &dest_path);

bool copy_file_replace_if_exists(
    const char *src_path, const char *dest_path);
bool copy_file_replace_if_exists(
    const std::string &src_path, const std::string &dest_path);

Creates a new file dest_path which is a copy of a file src_path. If the new file exists and replace == false, the functions fail.

copy_file_if_exists() returns false instead of throwing if src_path doesn't exist.

copy_file_replace() is the same as copy_file(..., true).

copy_file_replace_if_exists() is the same as copy_file_if_exists(..., true).

2.13.7move_file(), move_file_if_exists(), move_file_replace(), move_file_replace_if_exists()

void move_file(const char *src_path, const char *dest_path);
void move_file(const std::string &src_path, const std::string &dest_path);

bool move_file_if_exists(const char *src_path, const char *dest_path);
bool move_file_if_exists(
    const std::string &src_path, const std::string &dest_path);

void move_file_replace(const char *src_path, const char *dest_path);
void move_file_replace(
    const std::string &src_path, const std::string &dest_path);

bool move_file_replace_if_exists(
    const char *src_path, const char *dest_path);
bool move_file_replace_if_exists(
    const std::string &src_path, const std::string &dest_path);

Moves a file src_path to new location specified by dest_path.

The functions with _replace suffix overwrite existing destination file if exists, others - fail in such case.

move_file_if_exists() returns false instead of throwing if src_path doesn't exist.

2.13.8rename_file(), rename_file_if_exists(), rename_file_replace(), rename_file_replace_if_exists()

void rename_file(const char *src_name, const char *dest_name);
void rename_file(const std::string &src_name, const std::string &dest_name);

bool rename_file_if_exists(const char *src_name, const char *dest_name);
bool rename_file_if_exists(
    const std::string &src_name, const std::string &dest_name);

void rename_file_replace(const char *src_name, const char *dest_name);
void rename_file_replace(
    const std::string &src_name, const std::string &dest_name);

bool rename_file_replace_if_exists(
    const char *src_name, const char *dest_name);
bool rename_file_replace_if_exists(
    const std::string &src_name, const std::string &dest_name);

Renames a file src_path to dest_path. The new path has to be located within the same physical filesystem.

As opposed to std::rename(), the functions without _replace suffix fail if dest_path exists.

rename_file_if_exists() returns false instead of throwing if src_path doesn't exist.

2.13.9file_size()

uintmax_t file_size(const char *path);
uintmax_t file_size(const std::string &path);

Returns file size in bytes.

2.14__vic/ip_addr.h

2.14.1ipv4_addr

class ipv4_addr : public ::in_addr
{
public:
    ipv4_addr() = default;
    constexpr ipv4_addr(::in_addr a);
    constexpr explicit ipv4_addr(::in_addr_t a);
    constexpr ipv4_addr(uint8_t a, uint8_t b, uint8_t c, uint8_t d);

    static constexpr ipv4_addr any();
    static constexpr ipv4_addr loopback();

    constexpr bool is_any() const;
    constexpr bool is_loopback() const;

    static bool parse(const char *begin, const char *end, ::in_addr &res);
#if __cpp_lib_string_view // C++17
    static bool parse(std::string_view s, ::in_addr &res);
#else // until C++17
    static bool parse(const std::string &s, ::in_addr &res)
    static bool parse(const char *s, ::in_addr &res);
#endif
};

constexpr ipv4_addr operator&(ipv4_addr a1, ipv4_addr a2);

constexpr bool operator==(ipv4_addr a1, ipv4_addr a2);
constexpr bool operator!=(ipv4_addr a1, ipv4_addr a2);
constexpr bool operator< (ipv4_addr a1, ipv4_addr a2);
constexpr bool operator> (ipv4_addr a1, ipv4_addr a2);
constexpr bool operator<=(ipv4_addr a1, ipv4_addr a2);
constexpr bool operator>=(ipv4_addr a1, ipv4_addr a2);

constexpr bool operator==(ipv4_addr a1, ::in_addr a2);
constexpr bool operator!=(ipv4_addr a1, ::in_addr a2);
constexpr bool operator< (ipv4_addr a1, ::in_addr a2);
constexpr bool operator> (ipv4_addr a1, ::in_addr a2);
constexpr bool operator<=(ipv4_addr a1, ::in_addr a2);
constexpr bool operator>=(ipv4_addr a1, ::in_addr a2);

constexpr bool operator==(::in_addr a1, ipv4_addr a2);
constexpr bool operator!=(::in_addr a1, ipv4_addr a2);
constexpr bool operator< (::in_addr a1, ipv4_addr a2);
constexpr bool operator> (::in_addr a1, ipv4_addr a2);
constexpr bool operator<=(::in_addr a1, ipv4_addr a2);
constexpr bool operator>=(::in_addr a1, ipv4_addr a2);

void to_text_append(::in_addr ip, std::string &res);

template<> struct std::hash<ipv4_addr>;

An IPv4 address. A handy C++-wrapper for ::in_addr.

Class members
ipv4_addr() = default

Creates an uninitialized IPv4 address.

constexpr ipv4_addr(uint8_t a, uint8_t b, uint8_t c, uint8_t d)

Creates IPv4 address a.b.c.d.

constexpr ipv4_addr(::in_addr a)
constexpr explicit ipv4_addr(::in_addr_t a)

Converters for the system types.

static constexpr ipv4_addr any()

Returns IPv4 address 0.0.0.0.

static constexpr ipv4_addr loopback()

Returns IPv4 address 127.0.0.1.

constexpr bool is_any() const

Returns true if the address is 0.0.0.0.

constexpr bool is_loopback() const

Returns true if the address is 127.0.0.1.

static bool parse(const char *begin, const char *end, ::in_addr &res)

Parses an IPv4 address from the text representation. In case of success, returns true and res contains the parsed value.

Note: Expected input format is exactly 4 components in decimal format separated by dots.
static bool parse(std::string_view s, ::in_addr &res) [C++17]

Alternative prototype of the function with the same name for C++17.

static bool parse(const std::string &s, ::in_addr &res) [until C++17]
static bool parse(const char *s, ::in_addr &res) [until C++17]

Alternative prototypes of the function with the same name before C++17.

Free functions
constexpr ipv4_addr operator&(ipv4_addr a1, ipv4_addr a2)

Applies the specified mask to the specified address.

constexpr bool operator==(ipv4_addr a1, ipv4_addr a2)
constexpr bool operator!=(ipv4_addr a1, ipv4_addr a2)
constexpr bool operator==(ipv4_addr a1, ::in_addr a2)
constexpr bool operator!=(ipv4_addr a1, ::in_addr a2)
constexpr bool operator==(::in_addr a1, ipv4_addr a2)
constexpr bool operator!=(::in_addr a1, ipv4_addr a2)

Equality comparison operators.

constexpr bool operator< (ipv4_addr a1, ipv4_addr a2)
constexpr bool operator> (ipv4_addr a1, ipv4_addr a2)
constexpr bool operator<=(ipv4_addr a1, ipv4_addr a2)
constexpr bool operator>=(ipv4_addr a1, ipv4_addr a2)
constexpr bool operator< (ipv4_addr a1, ::in_addr a2)
constexpr bool operator> (ipv4_addr a1, ::in_addr a2)
constexpr bool operator<=(ipv4_addr a1, ::in_addr a2)
constexpr bool operator>=(ipv4_addr a1, ::in_addr a2)
constexpr bool operator< (::in_addr a1, ipv4_addr a2)
constexpr bool operator> (::in_addr a1, ipv4_addr a2)
constexpr bool operator<=(::in_addr a1, ipv4_addr a2)
constexpr bool operator>=(::in_addr a1, ipv4_addr a2)

Relational comparison operators. The resulting order may differ across platforms, but always mathematically consistent within a given platform.

void to_text_append(::in_addr ip, std::string &res)

Converts the specified IPv4 address to decimal dotted notation.

template<> struct std::hash<ipv4_addr>

Specialization for std::hash.

Example
http_connect(__vic::ipv4_addr{127,0,0,1}, 80);

std::string_view s = ..;
__vic::ipv4_addr ip;
if(__vic::ipv4_addr::parse(s, ip))
    log.info() << "Connecting to " << ip << "...";
else
    log.error("Bad IPv4 address format");

2.14.2ipv6_addr

class ipv6_addr : public ::in6_addr
{
public:
    ipv6_addr() = default;
    constexpr ipv6_addr(::in6_addr a);
    constexpr ipv6_addr(uint8_t a, uint8_t b, uint8_t c, uint8_t d,
                        uint8_t e, uint8_t f, uint8_t g, uint8_t h,
                        uint8_t i, uint8_t j, uint8_t k, uint8_t l,
                        uint8_t m, uint8_t n, uint8_t o, uint8_t p);
    constexpr ipv6_addr(uint16_t a, uint16_t b, uint16_t c, uint16_t d,
                        uint16_t e, uint16_t f, uint16_t g, uint16_t h)
    explicit ipv6_addr(const ::in_addr &ip4);

    static constexpr ipv6_addr any();
    static constexpr ipv6_addr loopback();

    bool is_any() const;
    bool is_loopback() const;
    bool is_ipv4_mapped() const;
    ipv4_addr to_ipv4() const;

    static bool parse(const char *begin, const char *end, ::in6_addr &res);
#if __cpp_lib_string_view
    static bool parse(std::string_view s, ::in6_addr &res);
#else
    static bool parse(const std::string &s, ::in6_addr &res);
    static bool parse(const char *s, ::in6_addr &res);
#endif
};

ipv6_addr operator&(const ipv6_addr &a1, const ipv6_addr &a2);

constexpr bool operator==(ipv6_addr a1, ipv6_addr a2);
constexpr bool operator!=(ipv6_addr a1, ipv6_addr a2);
constexpr bool operator< (ipv6_addr a1, ipv6_addr a2);
constexpr bool operator> (ipv6_addr a1, ipv6_addr a2);
constexpr bool operator<=(ipv6_addr a1, ipv6_addr a2);
constexpr bool operator>=(ipv6_addr a1, ipv6_addr a2);

constexpr bool operator==(ipv6_addr a1, ::in6_addr a2);
constexpr bool operator!=(ipv6_addr a1, ::in6_addr a2);
constexpr bool operator< (ipv6_addr a1, ::in6_addr a2);
constexpr bool operator> (ipv6_addr a1, ::in6_addr a2);
constexpr bool operator<=(ipv6_addr a1, ::in6_addr a2);
constexpr bool operator>=(ipv6_addr a1, ::in6_addr a2);

constexpr bool operator==(::in6_addr a1, ipv6_addr a2);
constexpr bool operator!=(::in6_addr a1, ipv6_addr a2);
constexpr bool operator< (::in6_addr a1, ipv6_addr a2);
constexpr bool operator> (::in6_addr a1, ipv6_addr a2);
constexpr bool operator<=(::in6_addr a1, ipv6_addr a2);
constexpr bool operator>=(::in6_addr a1, ipv6_addr a2);

void to_text_append(::in6_addr ip, std::string &res);

template<> struct std::hash<ipv6_addr>;

ipv4_addr analogue for IPv6/::in6_addr.

Class members missing in ipv4_addr
explicit ipv6_addr(const ::in_addr &ip4)

Creates IPv4-mapped IPv6 address.

Postcondition: is_ipv4_mapped() == true
static constexpr ipv6_addr any()

Returns IPv6 address ::.

static constexpr ipv6_addr loopback()

Returns IPv6 address ::1.

bool is_any() const

Returns true if the address is ::.

bool is_loopback() const

Returns true if the address is ::1.

bool is_ipv4_mapped() const

Returns true if the address is an IPv4-mapped IPv6 address.

ipv4_addr to_ipv4() const

Converts the IPv4-mapped IPv6 address to ipv4_addr.

Precondition: is_ipv4_mapped() == true

2.15__vic/iterator.h

Iterators-related utilities.

2.15.1begin(T[]), end(T[]), cbegin(T[]), cend(T[])

template<class T, size_t N> constexpr T *begin(T (&arr)[N]);
template<class T, size_t N> constexpr T *end(T (&arr)[N]);

template<class T, size_t N> constexpr const T *cbegin(T (&arr)[N]);
template<class T, size_t N> constexpr const T *cend(T (&arr)[N]);

Return a pointer to the beginning and past-the-end of the array.

Example
int vals[] = { 1, 2, 3 };
std::list<int> lst(__vic::begin(vals), __vic::end(vals));
assert(lst.size() == 3);

2.15.2advance()

template<class Iter>
void advance(Iter &it, Iter end, size_t n);

A counterpart of std::advance() but differs in parameters and behaviour:

  1. Allows only forward movement (++),
  2. Checks the range bounds. Returns immediately if end is reached.

2.15.3next(), prev()

template<class ForwardIterator>
ForwardIterator next(ForwardIterator it);

template<class ForwardIterator>
ForwardIterator next(ForwardIterator it, size_t n);

template<class BidirectionalIterator>
BidirectionalIterator prev(BidirectionalIterator it);

template<class BidirectionalIterator>
BidirectionalIterator prev(BidirectionalIterator it, size_t n);

next() returns an iterator advanced by n positions. prev() does the same but in reverse order. As opposed to C++11 STL functions of the same name, the offset cannot be negative. The versions with single parameter just call ++it/--it and return the result.

Example
template<class Container>
void f(const Container &c)
{
    // Begin a traversal starting from the second element
    // v.begin() + 1 works only with RandomAccessIterator
    // ++v.begin() may cause a compile error
    for(auto it = __vic::next(c.begin()); it != c.end(); ++it) ...;
}

2.16__vic/logger.h

2.16.1logger

class logger : private non_copyable
{
public:
    enum class severity : unsigned char
    {
        trace,
        debug,
        info,
        notice,
        warning,
        error,
        fatal
    };
    using severity_t = severity; // use this alias as a type name
    struct output
    {
        virtual void publish_record(severity_t , const char * , size_t ) = 0;
    protected:
        ~output() = default;
    };
    class settings_t
    {
        struct output &output() const;
        severity_t level() const;
    };
    class record;

    explicit logger(output &out, severity_t = severity::info);
    explicit logger(settings_t s);
    ~logger();

    severity_t level() const;
    void level(severity_t new_level);
    settings_t settings() const;
    output &reset_output(output &out);
    output &get_output();
    const output &get_output() const;

    static constexpr size_t min_buffer_size = ...;
    void shrink_buffer(size_t limit);

    void message(severity_t severity, const char *msg, size_t msg_len);
#if __cpp_lib_string_view // C++17
    void message(severity_t severity, std::string_view msg);

    void trace(std::string_view msg);
    void debug(std::string_view msg);
    void info(std::string_view msg);
    void notice(std::string_view msg);
    void warning(std::string_view msg);
    void error(std::string_view msg);
    void fatal(std::string_view msg);
#else // until C++17
    void message(severity_t severity, const char *msg);
    void message(severity_t severity, const std::string &msg);

    void trace(const char *msg);
    void debug(const char *msg);
    void info(const char *msg);
    void notice(const char *msg);
    void warning(const char *msg);
    void error(const char *msg);
    void fatal(const char *msg);

    void trace(const std::string &msg);
    void debug(const std::string &msg);
    void info(const std::string &msg);
    void notice(const std::string &msg);
    void warning(const std::string &msg);
    void error(const std::string &msg);
    void fatal(const std::string &msg);
#endif

#if __cpp_lib_format >= 202106L // C++20 + P2508
    template<class... Args>
    void format(severity_t s,
        std::format_string<Args...> fmt, Args&&... args);

    template<class Arg1, class... Args>
    void trace(std::format_string<Arg1,Args...> fmt,
                                        Arg1 &&arg1, Args&&... args);
    template<class Arg1, class... Args>
    void debug(std::format_string<Arg1,Args...> fmt,
                                        Arg1 &&arg1, Args&&... args);
    template<class Arg1, class... Args>
    void info(std::format_string<Arg1,Args...> fmt,
                                        Arg1 &&arg1, Args&&... args);
    template<class Arg1, class... Args>
    void notice(std::format_string<Arg1,Args...> fmt,
                                        Arg1 &&arg1, Args&&... args);
    template<class Arg1, class... Args>
    void warning(std::format_string<Arg1,Args...> fmt,
                                        Arg1 &&arg1, Args&&... args);
    template<class Arg1, class... Args>
    void error(std::format_string<Arg1,Args...> fmt,
                                        Arg1 &&arg1, Args&&... args);
    template<class Arg1, class... Args>
    void fatal(std::format_string<Arg1,Args...> fmt,
                                        Arg1 &&arg1, Args&&... args);
#endif

    record trace();
    record debug();
    record info();
    record notice();
    record warning();
    record error();
    record fatal();

    bool trace_visible() const;
    bool debug_visible() const;
    bool info_visible() const;
    bool notice_visible() const;
    bool warning_visible() const;
    bool error_visible() const;
    bool fatal_visible() const;
};
class logger::record
{
public:
    record(logger &log, severity_t sev);
    ~record();

    record append(const char *str, size_t str_len);

    template<class T> record operator<<(const T &v);
};
template<class T> struct log_value
{
    static void to_text(const T &v, std::string &s);
};
const char *to_string(logger::severity_t s);
#if __cpp_lib_string_view // C++17
constexpr std::string_view to_string_view(logger::severity s);
#endif

Logging front-end. Provides building of the log records using operator <<, like iostream. Each log record has the associated severity. The logger itself can filter out the records by severity. There are 7 predefined levels of the severity (in ascending order):

  1. TRACE - detailed debug,
  2. DEBUG - debug,
  3. INFO - informational,
  4. NOTICE - normal but significant event,
  5. WARNING - insignificant error or suspicious situation,
  6. ERROR - severe error but the application can continue,
  7. FATAL - critical unrecoverable error, the application can't continue.

INFO is the default logging level but any other can be chosen. If severity of the log message (record) is below the logging level, it will be ignored and will not be published in the log's output.

For creation of messages with the required severity, the set of functions with the same name as the severity is available. For instance info() for INFO messages. Or alternatively the universal function message() can be used, in which the severity is the argument. Usually the specific functions should be used.

There are two ways of logging. The first is plain and common:

log.trace("Trace message");
log.debug("Debug message");
log.info("Info message");
log.notice("Notice");
log.warning("Warning");
log.error("Recoverable error");
log.fatal("Fatal error");

The second is slightly more complex but provides more capabilities:

log.error() << "Cannot open file " << filename << '!';
log.warning() << "Loop iteration no " << i;

The call without parameters creates the object of type logger::record with the corresponding severity. Futher, the message is formed using operators <<. The message will be output to the log at the end of the full-expression (term from the Standard).

If the message can't or shouldn't be formed with a single expression, the named object of type logger::record has to be created, and parts of the message have to be written to it. The resulting message will be output to the log by it's destructor:

{
    logger::record rec = log.info(); // Begin new record
    rec << "List elements: ";
    for(auto el : list) rec << el << ", ";
    // Constructed record will be printed to the log when the block exits
}
Note: In order to optimize the performace, use the plain functional notation when the complete message is available:
log.info("Message");
// but not
log.info() << "Message";

Output of the records with the severities DEBUG and TRACE is usually disabled. Such records will not be published in the log but the program will waste time to format it. Therefore before creating any debug message using operator << one should check if debug is enabled using debug_visible() or trace_visible() call:

if(log.debug_visible())
    log.debug() << ...; // build the message

This advice doesn't cover plain calls debug(msg) and trace(msg), which have a prepared message already and don't perform any formatting.

To use logger one has to implement abstract base class logger::output (override publish_record()). The implementation has to output the passed record somewhere, e.g. to file, terminal or DB. The output specified during logger construction can be replaced later using reset_output().

Class members
severity::trace
severity::debug
severity::info
severity::notice
severity::warning
severity::error
severity::fatal

Severity constants. Use this form for both C++11 and C++98 mode.

typename severity_t

Use this identifier as a type name if your code has to be C++98-compatible. Since C++11 it is just a synonym for severity.

class output

Logging back-end interface.

void output::publish_record(severity_t sev, const char *buf, size_t buf_len)

The implementaion of this pure virtual function has to output the content of buf to the log as one record. buf_len is the length of buf. The function is always called with sev >= level(). The implementation can rely on it.

class settings_t

Keeps the logger settings: logging level and reference to output (level() + get_output()).

explicit logger(output &out, severity_t level = severity::info)

Creates logger with the specified output and logging level. The output object must outlive the logger object!

Postcondition: this->level() == level && &this->get_output() == &out
explicit logger(settings_t s)

Creates logger using the specified settings.

severity_t level() const

Returns current logging level.

void level(severity_t new_level)

Sets the logging level.

Postcondition: level() == new_level
settings_t settings() const

Returns current logging settings.

output &reset_output(output &out)

Sets new output and returns the previous one.

Postcondition: &get_output() == &out
output &get_output()
const output &get_output() const

Returns reference to the current logging output.

static constexpr size_t min_buffer_size

Minimal size of the internal buffer in bytes.

void shrink_buffer(size_t limit)

Sets the internal buffer size to min_buffer_size if it is more than limit bytes. Allows to restrict the buffer growth when long records are formed.

void message(severity_t severity, const char *msg, size_t msg_len)
void message(severity_t severity, std::string_view msg) [C++17]
void message(severity_t severity, const char *msg) [until C++17]
void message(severity_t severity, const std::string &msg) [until C++17]

Writes the message with the specified severity.

void trace(std::string_view msg) [C++17]
void trace(const char *msg) [until C++17]
void trace(const std::string &msg) [until C++17]
void debug(std::string_view msg) [C++17]
void debug(const char *msg) [until C++17]
void debug(const std::string &msg) [until C++17]
void info(std::string_view msg) [C++17]
void info(const char *msg) [until C++17]
void info(const std::string &msg) [until C++17]
void notice(std::string_view msg) [C++17]
void notice(const char *msg) [until C++17]
void notice(const std::string &msg) [until C++17]
void warning(std::string_view msg) [C++17]
void warning(const char *msg) [until C++17]
void warning(const std::string &msg) [until C++17]
void error(std::string_view msg) [C++17]
void error(const char *msg) [until C++17]
void error(const std::string &msg) [until C++17]
void fatal(std::string_view msg) [C++17]
void fatal(const char *msg) [until C++17]
void fatal(const std::string &msg) [until C++17]

Writes the message with the corresponding severity.

template<class... Args>
void format(severity_t s,
    std::format_string<Args...> fmt, Args&&... args) [C++20]

Formats the message using the specified format string and arguments (like std::format does) then writes it with the specified severity.

template<class Arg1, class... Args>
void trace(std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args) [C++20]
template<class Arg1, class... Args>
void debug(std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args) [C++20]
template<class Arg1, class... Args>
void info(std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args) [C++20]
template<class Arg1, class... Args>
void notice(std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args) [C++20]
template<class Arg1, class... Args>
void warning(std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args) [C++20]
template<class Arg1, class... Args>
void error(std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args) [C++20]
template<class Arg1, class... Args>
void fatal(std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args) [C++20]

Formats the message using the specified format string and arguments (like std::format does) then writes it with the corresponding severity.

logger::record trace()
logger::record debug()
logger::record info()
logger::record notice()
logger::record warning()
logger::record error()
logger::record fatal()

Creates new record with the corresponding severity. Message parts can be added using operators <<.

bool trace_visible() const
bool debug_visible() const
bool info_visible() const
bool notice_visible() const
bool warning_visible() const
bool error_visible() const
bool fatal_visible() const

Returns true if a record with the corresponding severity will be published. Usage of this functions enables to avoid formatting of the messages which eventually will not be published.

record::record(logger &log, severity_t sev)

Creates the log record with the specified severity. Usually the logger's functions like info() without parameters should be used instead.

record::~record()

Outputs the constructed record to the log.

record record::append(const char *str, size_t str_len)

Appends the string to the message.

template<class T> record record::operator<<(const T &v)

The set of inserters for various data types. The specified value is converted to text using log_value<T>::to_text() call.

Value-to-text converter
template<class T> void log_value<T>::to_text(const T &v, std::string &s)

Converts a value of type T to text using unqualified to_text_append() call.

Note: This function (class with static function, to be precise) can be specialized for your T. But usually you just define to_text_append(const T &, std::string &).
Free functions
const char *to_string(logger::severity_t s)
constexpr std::string_view to_string_view(logger::severity s) [C++17]

Returns text label for the specified severity that can be printed to the log. For example, "DEBUG" will be returned for severity::debug.

Example
/////////////////////////////////////////////////////////////////////////////
// Output messages to std::clog with the severity label
class coutput : public __vic::logger::output
{
public:
    void publish_record(__vic::logger::severity_t s,
                            const char *rec, size_t rec_n)
    {
        std::clog << to_string(s) << ": ";
        std::clog.write(rec, rec_n) << std::endl;
    }
};
/////////////////////////////////////////////////////////////////////////////

int main()
{
    coutput log_output:
    __vic::logger log(log_output, __vic::logger::severity::debug);

    log.info("Application is started");

    for(int i = 0; i < 5; i++)
        log.debug() << "Loop i = " << i;

    log.warning("Application end");
}

Output:

INFO: Application is started
DEBUG: Loop i = 0
DEBUG: Loop i = 1
DEBUG: Loop i = 2
DEBUG: Loop i = 3
DEBUG: Loop i = 4
WARNING: Application end

2.17__vic/memory.h

Memory-related utilities.

2.17.1load_unaligned()

template<class T>
T load_unaligned(const void *p);

Load value from potentially unaligned address without causing bus error (SIGBUS).

Example
const void *p = ...;
// int data = *static_cast<const int *>(p); // potential bus error
int data = __vic::load_unaligned<int>(p);

2.17.2store_unaligned()

template<class T>
void store_unaligned(void *p, T v);

Store value to potentially unaligned address without causing bus error (SIGBUS).

Example
void *p = ...;
// *static_cast<int *>(p) = 123; // potential bus error
__vic::store_unaligned(p, 123);

2.18__vic/mutex.h

2.18.1mutex

class mutex : private non_copyable
{
public:
    mutex();
    ~mutex();

    void lock();
    bool try_lock();
    bool unlock() noexcept;
};

Plain non-recursive mutex.

Usage notes

In most cases explicit usage of lock() and unlock() should be avoided. Use class mutex_lock to manage locks instead. It provides exception safety and it's handy for usage.

In C++11 mode std::mutex can be a better alternative.

Class members
mutex()

Creates unlocked mutex.

~mutex()

Destroys the mutex.

void lock()

Acquires the mutex. Waits until released if acquired by other thread at the moment.

bool try_lock()

Tries to acquire the mutex. Immediately returns false if it's already acquired by another thread, without waiting.

bool unlock() noexcept

Releases the mutex acquired before. In some cases can return false in case of error, but in general error detection is not guaranteed.

Example

See mutex_lock.

2.18.2mutex_lock

class mutex_lock : private non_copyable
{
public:
    enum adopt_t { adopt };

    explicit mutex_lock(mutex &mtx);
    mutex_lock(mutex &mtx, adopt_t);
    ~mutex_lock();
};

Manages the lock on a mutex. The lock exists while the object is alive.

Class members
adopt

Constructor tag, suppresses the mutex acquisition.

explicit mutex_lock(mutex &mtx)

Acquires mtx.

~mutex_lock()

Releases mtx.

mutex_lock(mutex &mtx, adopt_t)

Adopts already acquired mtx. See the example.

Example
// Typical usage
__vic::mutex mtx;
void reentrant_function()
{
    __vic::mutex_lock lock(mtx);
    // Critical section code until the end of the block
    ...
}

// Usage of non-acquiring constructor
if(mtx.try_lock()) // Try to acquire the mutex
{
    // The mutex has been successfully acquired
    __vic::mutex_lock lock(mtx, __vic::mutex_lock::adopt);
    // Critical section code until the end of the block
    ...
}
else
{
    // The mutex is acquired by another thread
    ...
}

2.19__vic/packon.h & __vic/packoff.h

Inclusion of the first file turns off struct members alignment. In other words, turns on "structures packing" - size of the struct is strictly a sum of its members sizes. Inclusion of the second one restores the default alignment. So that the pair of #include directives forms a section in the source file where structs alignment is disabled.

Note: Each #include<__vic/packon.h> must have the corresponding #include<__vic/packoff.h>.
Example
struct unpacked
{
    bool f1;
    int f2;
};
static_assert(sizeof(unpacked) >= sizeof(bool) + sizeof(int),
    "Total struct size can exceed the sum of members sizes");

#include<__vic/packon.h> // alignment disabled starting from here

struct packed
{
    bool f1;
    int f2;
};
static_assert(sizeof(packed) == sizeof(bool) + sizeof(int),
    "Total struct size is exactly the sum of members sizes");

#include<__vic/packoff.h> // alignment enabled again

2.20__vic/readonly_cstring.h

2.20.1readonly_cstring

class readonly_cstring
{
public:
    readonly_cstring();
    readonly_cstring(const char *str);
    readonly_cstring(const char *begin, const char *end);
    readonly_cstring(const char *chars, size_t n);
    readonly_cstring(const readonly_cstring &str);
    ~readonly_cstring() noexcept;

    // BEGIN C++11
    readonly_cstring(readonly_cstring &&str) noexcept;
    readonly_cstring &operator=(readonly_cstring &&str) noexcept;
    // END C++11

    readonly_cstring &operator=(const char *str);
    readonly_cstring &operator=(const readonly_cstring &str);
    readonly_cstring &assign(const char *str);
    readonly_cstring &assign(const char *chars, size_t n);
    readonly_cstring &assign(const char *begin, const char *end);

    bool empty() const;
    const char *c_str() const;
    operator const char*() const;

    char *reserve(size_t n);
    void swap(readonly_cstring &str) noexcept;
};

int compare(const readonly_cstring &s1, const readonly_cstring &s2);
int compare(const readonly_cstring &s1, const char *s2);
int compare(const char *s1, const readonly_cstring &s2);

bool operator==(const readonly_cstring &s1, const readonly_cstring &s2);
bool operator!=(const readonly_cstring &s1, const readonly_cstring &s2);
bool operator<(const readonly_cstring &s1, const readonly_cstring &s2);
bool operator>(const readonly_cstring &s1, const readonly_cstring &s2);
bool operator<=(const readonly_cstring &s1, const readonly_cstring &s2);
bool operator>=(const readonly_cstring &s1, const readonly_cstring &s2);

bool operator==(const readonly_cstring &s1, const char *s2);
bool operator!=(const readonly_cstring &s1, const char *s2);
bool operator<(const readonly_cstring &s1, const char *s2);
bool operator>(const readonly_cstring &s1, const char *s2);
bool operator<=(const readonly_cstring &s1, const char *s2);
bool operator>=(const readonly_cstring &s1, const char *s2);

bool operator==(const char *s1, const readonly_cstring &s2);
bool operator!=(const char *s1, const readonly_cstring &s2);
bool operator<(const char *s1, const readonly_cstring &s2);
bool operator>(const char *s1, const readonly_cstring &s2);
bool operator<=(const char *s1, const readonly_cstring &s2);
bool operator>=(const char *s1, const readonly_cstring &s2);

void swap(readonly_cstring &s1, readonly_cstring &s2) noexcept;

The simple non-mutable null-terminated string class with automatic memory management. Has simple and predictable structure that can be useful when ABI compatibility/stability is required or when usage of std::string is objectionable for some reason. The functionality provided by the class is also minimal. It provides string copying and storing and read access to it. One cannot modify string parts - only replace the whole value.

If one need to store a string value in a class, usage of this class may be a good choice. It's easier-to-use, more clear and safer than array of chars (char[]) and can be more efficient than std::string, though, of course, less universal. If modifications of the string parts are expected, usage of another string class should be considered, for instance, __vic::string_buffer. Class readonly_cstring is not designed for such purposes.

Guarantees provided by the class design
Class members
readonly_cstring()

Creates an empty string.

Postcondition: empty() == true
readonly_cstring(const char *str)
readonly_cstring(const readonly_cstring &str)

Creates a copy of str.

readonly_cstring(const char *chars, size_t n)
readonly_cstring(const char *begin, const char *end)

Creates a string from characters range.

readonly_cstring &operator=(const char *str)
readonly_cstring &operator=(const readonly_cstring &str)
readonly_cstring &assign(const char *str)

Assigns str.

readonly_cstring(readonly_cstring &&str) noexcept [C++11]
readonly_cstring &operator=(readonly_cstring &&str) noexcept [C++11]

Move operations for C++11 mode.

readonly_cstring &assign(const char *begin, const char *end)
readonly_cstring &assign(const char *chars, size_t n)

Assigns the string constructed from characters range.

bool empty() const

Returns true if string is empty.

const char *c_str() const
operator const char*() const

Returns a pointer to the stored string. The pointer is never null.

char *reserve(size_t n)

Allocates internal buffer for n chars and returns the pointer to it. Can be useful in conjunction with functions like std::sprintf().

Note: Try to avoid this unsafe function!
void swap(readonly_cstring &str) noexcept

Swaps the value with str.

Free functions
int compare(const readonly_cstring &s1, const readonly_cstring &s2)
int compare(const readonly_cstring &s1, const char *s2)
int compare(const char *s1, const readonly_cstring &s2)

Compares two strings as std::strcmp does.

bool operator==(const readonly_cstring &s1, const readonly_cstring &s2)
...
bool operator>=(const char *s1, const readonly_cstring &s2)

Full set of comparators for readonly_cstring and const char * in all combinations.

void swap(readonly_cstring &s1, readonly_cstring &s2) noexcept

Specialization of the standard algorithm.

Example
class C
{
    __vic::readonly_cstring st;
public:
    explicit C(const char *str) : st(str) {}
    const char *get_str() const { return st; }
};

2.21__vic/set_of_chars.h

2.21.1set_of_chars

class set_of_chars
{
public:
    constexpr set_of_chars();
    template<class Iter> constexpr set_of_chars(Iter begin, Iter end);
    constexpr set_of_chars(std::initializer_list<char> set); // C++11
    constexpr set_of_chars(const char *c_str);

    constexpr bool contains(char ch) const;

    constexpr void add(char ch);
    constexpr void remove(char ch);

    template<class Iter> constexpr void add(Iter begin, Iter end);
    constexpr void add(const char *c_str);
    constexpr void add(std::initializer_list<char> set); // C++11

    template<class Iter> void assign(Iter begin, Iter end);
    void assign(const char *c_str)
    void assign(std::initializer_list<char> set); // C++11

    void clear();
};

Compact (only 32 bytes) and very fast implemetation of a set of chars. The cost of the contains() operation is always constant regardles of the argument and number of elements in the set.

Class members
constexpr set_of_chars()

Creates an empty set.

Postcondition: contains(char(ch)) == false for any char
template<class Iter> constexpr set_of_chars(Iter begin, Iter end)
constexpr set_of_chars(std::initializer_list<char> set) [C++11]

Creates a set filled with characters from the specified range of values.

Note: constexpr since C++14 only!
constexpr set_of_chars(const char *c_str)

Creates a set filled with characters from the specified C-string excluding NULL-terminator.

Note: constexpr since C++14 only!
bool contains(char ch) const

Checks whether the set contains ch.

constexpr void add(char ch)

Adds ch to the set.

Postcondition: contains(ch) == true
Note: constexpr since C++14 only!
constexpr void remove(char ch)

Removes ch from the set.

Postcondition: contains(ch) == false
Note: constexpr since C++14 only!
template<class Iter> constexpr void add(Iter begin, Iter end)
constexpr void add(std::initializer_list<char> set) [C++11]

Calls add(ch) for each value in the range.

Note: constexpr since C++14 only!
constexpr void add(const char *c_str)

Calls add(ch) for each character in the C-string excluding NULL-terminator.

Note: constexpr since C++14 only!
template<class Iter> void assign(Iter begin, Iter end)
void assign(const char *c_str)
void assign(std::initializer_list<char> set) [C++11]

Calls clear() then add() with the specified parameters.

void clear()

Removes all elements from the set.

Postcondition: contains(char(ch)) == false for any char

2.22__vic/stdint.h

ISO C99 <stdint.h> for C++98. Since C++11 - just a redirector to <cstdint>.

Additionally, some metafunctions for template metaprogramming are provided.

2.22.1Exact-width integer types

Following types are guaranteed to be available in the global namespace:

2.22.2Minimum-width integer types

Following types are guaranteed to be available in the global namespace:

2.22.3Fastest minimum-width integer types

Following types are guaranteed to be available in the global namespace:

2.22.4Greatest-width integer types

Following types are guaranteed to be available in the global namespace:

2.22.5Integer types capable of holding object pointers

Following types are guaranteed to be available in the global namespace:

2.22.6int_exactly_bytes<>, uint_exactly_bytes<>

template<unsigned SizeInBytes>
struct int_exactly_bytes
{
    using type = <signed-integer-type-of-the-corresponding-size>;
};

template<unsigned SizeInBytes>
struct uint_exactly_bytes
{
    using type = <unsigned-integer-type-of-the-corresponding-size>;
};

// BEGIN C++11
template<unsigned N>
using int_exact_bytes = typename int_exactly_bytes<N>::type;

template<unsigned N>
using uint_exact_bytes = typename uint_exactly_bytes<N>::type;
// END C++11

Metafunctions returning the signed/unsigned interger type of the requested exact size in bytes. Shorter aliases are available in C++11 mode and higher. Valid SizeInBytes values are 1, 2, 4, 8.

Example
typedef __vic::int_exactly_bytes< sizeof(void *) >::type my_intptr_t;
// or in C++11
using my_intptr_t = __vic::int_exact_bytes< sizeof(void *) >
assert( sizeof(my_intptr) == sizeof(intptr_t) );

2.23__vic/stdio_file.h

std::FILE-related C++ wrappers.

2.23.1stdio_file

class stdio_file : private non_copyable
{
public:
    explicit stdio_file(std::FILE *fp = nullptr);
    stdio_file(const char *name, const char *mode);
    ~stdio_file();

    // BEGIN C++11
    stdio_file(stdio_file &&o) noexcept;
    stdio_file &operator=(stdio_file &&o) noexcept;
    // END C++11

    bool open(const char *name, const char *mode);
    bool is_open() const;
    void close();
    bool close_nt() noexcept;

    void swap(stdio_file &o) noexcept;
    std::FILE *detach_handle() noexcept;
    std::FILE *attach_handle(std::FILE *fp) noexcept;
    std::FILE *handle() const;
    operator std::FILE*() const;
};

Thin RAII-wrapper for std::FILE *. Controls file's life time. Automatic conversion to std::FILE * allows usage of the object whereever the file pointer is allowed/required.

Note: Although the class destructor closes the open file, it is more safe to use explicit close() call. Errors can happen when closing file, and close() can throw exception in such cases, while destructor - can't, so the error will be unnoticed by the application.
Class members
explicit stdio_file(std::FILE *fp = nullptr)

Wraps already existing stream pointer.

Precondition: fp is either a pointer to the open file or nullptr.
stdio_file(const char *name, const char *mode)

Calls open(name, mode). The result should be checked using subsequent is_open() call!

~stdio_file()

Calls std::fclose() if is_open() == true.

stdio_file(stdio_file &&o) noexcept [C++11]
stdio_file &operator=(stdio_file &&o) noexcept [C++11]

Move operations for C++11 mode.

bool open(const char *name, const char *mode)

Calls std::fopen(name, mode). Returns true in case of success.

Precondition: is_open() == false
bool is_open() const

Returns true if file is open.

void close()

Calls std::fclose(). No preliminary checks whether the file is open are performed! Throws if std::fclose() fails.

Precondition: is_open() == true
Postcondition: is_open() == false
bool close_nt() noexcept

A counterpart of close() but never throws, returns false instead in case of error.

void swap(stdio_file &o) noexcept

Swaps the value with o.

std::FILE *detach_handle() noexcept

Releases the file out of the object's control.

Postcondition: is_open() == false
std::FILE *attach_handle(std::FILE *fp) noexcept

Takes fp under control and returns the previous handle value.

Precondition: fp is either a poiner to the open file or nullptr.
Postcondition: handle() == fp
std::FILE *handle() const

Returns the held handle value.

operator std::FILE*() const

Allows usage of the object as std::FILE *.

Example
__vic::stdio_file file("file.txt", "w");
if(!file.is_open()) throw __vic::exception("Cannot open file");
std::fprintf(file, "Message");
file.close();
// fclose() also will be called in case of exception by destructor

2.23.2read(std::FILE)

sread_result<char> read(std::FILE *fp);

Attempts to read a byte from the C-stream. Returns the succesful result on success, unsuccessful result on EOF or throws on error.

2.23.3write(std::FILE)

void write(std::FILE *fp, char ch);

Writes a byte to the C-stream. Throws on error.

2.23.4getline(std::FILE)

bool getline(std::FILE *fp, std::string &str, char delim = '\n');

A counterpart of std::getline but for C-stream. Returns false if the end of the file was reached and nothing was read.

2.24__vic/str2num.h

2.24.1decimal_to_number()

#if __cpp_lib_string_view // since C++17

void decimal_to_number(std::string_view s, long long &res);
void decimal_to_number(std::string_view s, long &res);
void decimal_to_number(std::string_view s, int &res);
void decimal_to_number(std::string_view s, short &res);
void decimal_to_number(std::string_view s, signed char &res);

void decimal_to_number(std::string_view s, unsigned long long &res);
void decimal_to_number(std::string_view s, unsigned long &res);
void decimal_to_number(std::string_view s, unsigned &res);
void decimal_to_number(std::string_view s, unsigned short &res);
void decimal_to_number(std::string_view s, unsigned char &res);

template<class Integer>
[[nodiscard]] Integer decimal_to_number(std::string_view s);

#else // until C++17

void decimal_to_number(const std::string &s, long long &res);
void decimal_to_number(const std::string &s, long &res);
void decimal_to_number(const std::string &s, int &res);
void decimal_to_number(const std::string &s, short &res);
void decimal_to_number(const std::string &s, signed char &res);

void decimal_to_number(const std::string &s, unsigned long long &res);
void decimal_to_number(const std::string &s, unsigned long &res);
void decimal_to_number(const std::string &s, unsigned &res);
void decimal_to_number(const std::string &s, unsigned short &res);
void decimal_to_number(const std::string &s, unsigned char &res);

void decimal_to_number(const char *s, long long &res);
void decimal_to_number(const char *s, long &res);
void decimal_to_number(const char *s, int &res);
void decimal_to_number(const char *s, short &res);
void decimal_to_number(const char *s, signed char &res);

void decimal_to_number(const char *s, unsigned long long &res);
void decimal_to_number(const char *s, unsigned long &res);
void decimal_to_number(const char *s, unsigned &res);
void decimal_to_number(const char *s, unsigned short &res);
void decimal_to_number(const char *s, unsigned char &res);

template<class Integer>
[[nodiscard]] Integer decimal_to_number(const std::string &s);

template<class Integer>
[[nodiscard]] Integer decimal_to_number(const char *s);

#endif

The set of functions converts a string, that represents an integer in decimal notation, to one of the standard C++ integer types. The string can be a C-string as well as std::string.

As opposed to the standard converters, like std::strtol(), strict validation of the format of the whole string and value range is performed. In particular leading spaces and non-digit characters at the end are not allowed. For unsigned types minus ('-') is disallowed, which is happily accepted by std::strtoul() by unknown reason.

In case of errors the following exceptions are thrown:

There are two kinds of the function prototypes:

  1. The result is returned via additional output parameter and
  2. The result is returned using the natural way, the type is specified using the template parameter.

2.24.2decimal_to_number_range()

template<class T, class InputIterator>
void decimal_to_number_range(InputIterator begin, InputIterator end, T &res);

template<class T, class InputIterator>
[[nodiscard]] T decimal_to_number_range(InputIterator begin, InputIterator end);

The functions are complete analogs of decimal_to_number() except they work with generic ranges of characters instead of strings.

2.24.3parse_decimal()

#if __cpp_lib_string_view // since C++17

template<class T>
[[nodiscard]] number_parse_result<T> parse_decimal(std::string_view s);

#else // until C++17

template<class T>
[[nodiscard]] number_parse_result<T> parse_decimal(const std::string &s);
template<class T>
[[nodiscard]] number_parse_result<T> parse_decimal(const char *s);

#endif

template<class T, class InputIterator>
[[nodiscard]]
number_parse_result<T> parse_decimal(InputIterator begin, InputIterator end);

A counterpart of decimal_to_number() functions but doesn't throw exceptions. The returned object is boolean-testable and indicates the success of the operation. Also it contains the resulting number in case of success, or an error code otherwise. See number_parse_result for more information.

Example
if(auto res = __vic::parse_decimal<int>("123"))
{
    int num = res.value();
    // Use num
}

2.24.4decimal_parser

template<class T>
class decimal_parser
{
    using status = number_parse_status; // for brevity only
public:
    template<class InputIterator>
    [[nodiscard]] status parse(InputIterator begin, InputIterator end);
#if __cpp_lib_string_view // since C++17
    [[nodiscard]] status parse(std::string_view str);
#else // until C++17
    [[nodiscard]] status parse(const std::string &str);
    [[nodiscard]] status parse(const char *str);
#endif
    [[nodiscard]] T result() const;
};

A counterpart of decimal_to_number() functions but doesn't throw exceptions, number_parse_status codes are returned instead by parse().

Status codes
number_parse_status::ok

Success, the result can be obtained using result() function.

number_parse_status::invalid_number

The string is not a correct decimal integer.

number_parse_status::unrepresentable

The string is probably correct but the result cannot be represented by the used type (integer overflow).

Class members
template<class InputIterator>
[[nodiscard]] status parse(InputIterator begin, InputIterator end)
[[nodiscard]] status parse(std::string_view str) [C++17]
[[nodiscard]] status parse(const std::string &str) [until C++17]
[[nodiscard]] status parse(const char *str) [until C++17]

Converts a range of characters or a string to a number.

Postcondition: The result of conversion can be obtained by result() call if number_parse_status::ok is returned.
[[nodiscard]] T result() const

Returns the result of conversion produced by the the last parse() call.

Precondition: The last parse() call returned number_parse_status::ok.
Example
template<class T>
bool to_number(const std::string &s, T &result) noexcept
{
    __vic::decimal_parser<T> p;
    if(p.parse(s) != __vic::number_parse_status::ok) return false;
    result = p.result();
    returt true; // 'result' contains the result of conversion
}

2.24.5number_parse_status

enum class number_parse_status : unsigned char
{
    ok,
    invalid_number,
    unrepresentable
};
using number_parse_status_t = number_parse_status; // for C++98

Number parsing outcome status codes.

Types
typename number_parse_status_t

Use this as a name of type if your code has to be C++98-compatible.

2.24.6number_parse_result

template<class T>
class number_parse_result
{
public:
    typedef T value_type;

    number_parse_result(number_parse_status_t s);
    explicit number_parse_result(T n);

    number_parse_status_t status() const;
    explicit operator bool() const;
    bool has_value() const;

    T value() const;
};

number_parse_status + the resulting value in case of success.

Class members
number_parse_result(number_parse_status_t s)
Precondition: s != number_parse_status::ok
Postcondition: status() == s
explicit number_parse_result(T n)
Postcondition: has_value() && value() == n
number_parse_status_t status() const

A status of the number parsing operation.

bool has_value() const
explicit operator bool() const

Returns status() == number_parse_status::ok.

T value() const

The resulting number.

Precondition: has_value() == true

2.25__vic/string_buffer.h

2.25.1string_buffer

class string_buffer : public std::string
{
public:
    string_buffer();
    explicit string_buffer(size_type n);
    string_buffer(const char *str);
    string_buffer(std::string str);
    string_buffer(string_ref sr);
    string_buffer(const std::string &str, size_type off, size_type n = npos);
    string_buffer(const char *char_buf, size_type n);
    string_buffer(const char *begin, const char *end);
    template<class InputIterator>
    string_buffer(InputIterator begin, InputIterator end);

    template<class T> string_buffer &operator<<(const T &v);

    string_buffer &operator=(string_ref sr);
    string_buffer &operator+=(string_ref sr);
    string_buffer &assign(string_ref sr);
    string_buffer &append(string_ref sr);

    // improved std::string calls
    string_buffer &assign(const std::string &str,
                            size_type off, size_type n = npos);
    string_buffer &append(const std::string &str,
                            size_type off, size_type n = npos);
    string_buffer &insert(size_type pos, const std::string &str,
                            size_type off, size_type n = npos);

    string_buffer &reserve(size_type n);
    string_buffer &clear();

    // missing container interface of std::string
    reference front();
    reference back();
    const_reference front() const;
    const_reference back() const;
    void pop_back();

    operator const char *() const;
};

string_buffer operator+(const string_buffer &s1, const string_buffer &s2);
string_buffer operator+(const string_buffer &s1, const std::string &s2);
string_buffer operator+(const std::string &s1, const string_buffer &s2);

string_buffer operator+(const string_buffer &s1, const char *s2);
string_buffer operator+(const char *s1, const string_buffer &s2);

string_buffer operator+(const string_buffer &s, char ch);
string_buffer operator+(char ch, const string_buffer &s);

using msg = string_buffer;

Class is an extended and improved std::string. It has following advantages:

  1. Left-associative append operator (<<) that allows constructions like this:
    str << "Error message: " << err_msg << "\n";
    
  2. Specific amount of bytes can be reserved using constructor as well as reserve() call. Reserving required amount of space in advance can improve performance significantly.
    __vic::string_buffer st(4096);
    
    // is same as
    std::string st;
    st.reserve(4096);
    
  3. Operator << accepts all fundamental types: numbers, chars, pointers, bool, and other types for which to_text_append() is applicable:
    for(int i=0; i<10; i++)
        str << "i = " << i << '\n';
    
  4. All input nullptr values of const char * are treated as an empty string. Such values usually cause crash with std::string.
    std::string s1("Str");
    const char *p = nullptr;
    s1.append(p); // Oops.... Null pointer access!
    
    __vic::string_buffer s2("Str");
    s2.append(p); // Ok. s2 == "Str" still
    s2 = p; // Ok. s2.empty() == true
    
  5. Automatic conversion to const char * that allows usage of the object in context requires C-string, without explicit c_str() call.
    std::string fname(...);
    FILE *fp = fopen(fname.c_str(), "r");
    
    __vic::string_buffer fname(...);
    FILE *fp = fopen(fname, "r");)
    
  6. Some design irregularities of std::string are corrected. For instance std::string is a complete container but operations front() and back() are missed in C++98. There is push_back() but no pop_back().

In spite of all these improvements, the interface of this class is completely backward compatible with std::string. Objects can be passed in contexts that require std::string. Class has no additional data-members.

Using of inserter (operator <<) provides the easiest way to convert numbers to decimal string representation. Using of std::ostringstream for this purposes is more functional (you can specify radix, formatting, etc) but too tedious and not efficient in most cases.

Additionally this type has a short synonym msg. It is very convenient for usage when one needs to construct a complex message with a single expression, without introducing unnecessary variables:

oresult res = db_open(db_name);
if(res != 0) throw __vic::exception(
    __vic::msg(64) << "Cannot open DB " << db_name << ". res = " << res
);

As you can see, the maximum size of the message expected is specified in the constructor for optimization purposes.

Class members
string_buffer()

Create an empty string.

Postcondition: empty() == true
explicit string_buffer(size_type n)

Calls reserve(n).

Postcondition: capacity() >= n
string_buffer(const char *str)
string_buffer(std::string str)

Creates the copy of str.

string_buffer(const std::string &str, size_type off, size_type n = npos)

Creates the copy of str substring.

string_buffer(const char *char_buf, size_type n)

Creates string using buffer and its length.

string_buffer(string_ref sr)
string_buffer(const char *begin, const char *end)
template<class InputIterator>
string_buffer(InputIterator begin, InputIterator end)

Creates string from the chars range.

template<class T> string_buffer &operator<<(const T &v)

Calls to_text_append(v, *this).

string_buffer &reserve(size_type n)
string_buffer &clear()

Calls the corresponding std::string operation and additionally returns the reference to itself, so the call can be used in complex expressions.

reference front()
reference back()
const_reference front() const
const_reference back() const
void pop_back()

Missed container operations in the std::string interface in C++98.

operator const char *() const

Calls std::string::c_str().

string_buffer operator+(const string_buffer &s1, const string_buffer &s2)
string_buffer operator+(const string_buffer &s1, const std::string &s2)
string_buffer operator+(const std::string &s1, const string_buffer &s2)
string_buffer operator+(const string_buffer &s1, const char *s2)
string_buffer operator+(const char *s1, const string_buffer &s2)
string_buffer operator+(const string_buffer &s, char ch)
string_buffer operator+(char ch, const string_buffer &s)

Concatenation of strings and characters.

2.26__vic/string_ref.h

2.26.1string_ref

template<class charT>
class basic_string_ref
{
public:
    using value_type = charT;
    using iterator = const value_type *;
    using const_iterator = iterator;

    // Constructors
    basic_string_ref();
    basic_string_ref(const charT *str);
    basic_string_ref(const charT *chars, size_t n);
    basic_string_ref(const charT *begin, const charT *end);
    template<class Traits, class Alloc>
    explicit basic_string_ref(
        const std::basic_string<charT,Traits,Alloc> &str);
    basic_string_ref(
        typename std::basic_string<charT>::const_iterator begin,
        typename std::basic_string<charT>::const_iterator end);
    // BEGIN C++11
    basic_string_ref(std::initializer_list<charT> );
    // END C++11

#if __cpp_lib_string_view // since C++17
    template<class Traits>
    basic_string_ref(std::basic_string_view<charT,Traits> s);
    operator std::basic_string_view<charT>() const;
#endif

    // Accessors
    iterator begin() const;
    iterator end() const;
    iterator cbegin() const;
    iterator cend() const;

    charT front() const;
    charT back() const;
    charT operator[](size_t i) const;
    const charT *data() const;

    bool empty() const;
    size_t size() const;
    size_t length() const;

    int compare(basic_string_ref s) const;

    // Converters
    std::basic_string<charT> str() const;
    template<class Traits>
    std::basic_string<charT,Traits> str() const;
    template<class Traits, class Alloc>
    std::basic_string<charT,Traits,Alloc> str(const Alloc &a = Alloc())const;

    operator std::basic_string<charT>() const;
};

using string_ref = basic_string_ref<char> ;

template<class charT>
bool operator==(basic_string_ref<charT> s1, basic_string_ref<charT> s2);
template<class charT>
bool operator!=(basic_string_ref<charT> s1, basic_string_ref<charT> s2);
template<class charT>
bool operator<(basic_string_ref<charT> s1, basic_string_ref<charT> s2);
template<class charT>
bool operator>(basic_string_ref<charT> s1, basic_string_ref<charT> s2);
template<class charT>
bool operator<=(basic_string_ref<charT> s1, basic_string_ref<charT> s2);
template<class charT>
bool operator>=(basic_string_ref<charT> s1, basic_string_ref<charT> s2);

#ifdef __VIC_DEFINE_OSTREAM_INSERTERS
template<class charT, class Traits>
std::basic_ostream<charT,Traits> &operator<<(
    std::basic_ostream<charT,Traits> &os, const basic_string_ref<charT> &sr);
#endif

The class represents a reference to the read-only continuous range of characters. When used as a return value, it is significantly more lightweight than std::string, because no string copy or memory allocation performed. But, when std::string is required, automatic conversion happens. Let's consider the example:

class C
{
    std::string v;
public:
    std::string       get_v_1() const { return v; }
    __vic::string_ref get_v_2() const { return v; }
};

As you can see, class contains one string field. Two read-only access-functions are defined. The first as usual returns std::string, the second - string_ref. When the first is used, temporay string is created every time. When the second is used, just reference is returned.

Another use case - input read-only string argument. The class is a drop-in replacement for const std::string &. In most cases, it can also be used instead of const char *. The overhead in this case is an additional scan of the string to find the NULL-terminator, which is nothing in cases when we need the string end or length anyway. Let's consider 3 sets of overloaded functions:

void f1(const std::string & );

void f2(const std::string & );
void f2(const char * );

void f3(string_ref );

Each of them can be used as

fx("Nul-terminated string");

as well as

fx(std::string("std::string"));

But with f1() we will have redundant string copying in the first case, just to read the value. With f2() several overloads are required. And while it isn't a big issue when function has single argument, with two or more string arguments it quickly becomes very tedious. The last alternative - f3() - is at the same time as short and universal as f1() and "friendlier" to the string literals and strings from the C-world - they are not copied to the heap and not converted to std::string.

Class members
basic_string_ref()
Postcondition: empty() == true
basic_string_ref(const charT *str)
template<class Traits, class Alloc>
basic_string_ref(const std::basic_string<charT,Traits,Alloc> &str)

Creates reference to str.

Postcondition: *this == str
basic_string_ref(const charT *chars, size_t n)
basic_string_ref(const charT *begin, const charT *end)
basic_string_ref(const charT *chars, size_t n)
basic_string_ref(
    typename std::basic_string<charT>::const_iterator begin,
    typename std::basic_string<charT>::const_iterator end)
basic_string_ref(std::initializer_list<charT> ) [C++11]

Create reference to the range of the characters.

template<class Traits>
basic_string_ref(std::basic_string_view<charT,Traits> s) [C++17]
operator std::basic_string_view<charT>() const [C++17]

Converters from/to std::basic_string_view.

iterator begin() const
iterator cbegin() const
const charT *data() const

Begin of the range of the characters.

iterator end() const
iterator cend() const

End of the range of the characters.

charT front() const
charT back() const

The first and the last character of the string correspondingly.

Precondition: !empty()
charT operator[](size_t i) const

i-th character of the string.

Precondition: i < length()
bool empty() const

Returns begin() == end().

size_t size() const
size_t length() const

Size of the string.

int compare(basic_string_ref s) const

Compares the string with s. Returning values are the same as for std::string::compare().

std::basic_string<charT> str() const
template<class Traits>
std::basic_string<charT,Traits> str() const
template<class Traits, class Alloc>
std::basic_string<charT,Traits,Alloc> str(const Alloc &a = Alloc()) const

Explicit converter to std::basic_string.

operator std::basic_string<charT>() const

Implicit converter to std::basic_string.

Free functions
template<class charT>
bool operator==(basic_string_ref<charT> s1, basic_string_ref<charT> s2)
template<class charT>
bool operator!=(basic_string_ref<charT> s1, basic_string_ref<charT> s2)
template<class charT>
bool operator<(basic_string_ref<charT> s1, basic_string_ref<charT> s2)
template<class charT>
bool operator>(basic_string_ref<charT> s1, basic_string_ref<charT> s2)
template<class charT>
bool operator<=(basic_string_ref<charT> s1, basic_string_ref<charT> s2)
template<class charT>
bool operator>=(basic_string_ref<charT> s1, basic_string_ref<charT> s2)

Full set of the comparison operators.

template<class charT, class Traits>
std::basic_ostream<charT,Traits> &operator<<(
    std::basic_ostream<charT,Traits> &os, const basic_string_ref<charT> &sr)

Inserter to an output stream. Defined (and <ostream> is included) only if __VIC_DEFINE_OSTREAM_INSERTERS macro was defined before the header inclusion.

Example
C c; // see the class description above
__vic::string_ref s = c. get_v_2();

// print the string using different ways
for(__vic::string_ref::iterator it = s.begin(); it != s.end(); ++it)
    std::cout << *it;

// C++11
for(auto ch : s) std::cout << ch;

std::copy(s.begin(), s.end(), std::ostream_iterator<char>(std::cout));

std::cout << s;

// automatic conversion to std::string
std::string ss = s;

2.27__vic/string_utils.h

Miscellaneous strings-related utilities.

2.27.1trim functions

char *trim(char *str);
char *trim_front(char *str);
char *trim_back(char *str);
char *trim(char *str, char ch);
char *trim_front(char *str, char ch);
char *trim_back(char *str, char ch);
char *trim(char *str, const char *set);
char *trim_front(char *str, const char *set);
char *trim_back(char *str, const char *set);

std::string &trim(std::string &str);
std::string &trim_front(std::string &str);
std::string &trim_back(std::string &str);
std::string &trim(std::string &str, char ch);
std::string &trim_front(std::string &str, char ch);
std::string &trim_back(std::string &str, char ch);
std::string &trim(std::string &str, const char *set);
std::string &trim_front(std::string &str, const char *set);
std::string &trim_back(std::string &str, const char *set);

#if __cpp_lib_string_view // C++17
std::string_view trimmed(std::string_view str);
std::string_view trimmed_front(std::string_view str);
std::string_view trimmed_back(std::string_view str);
std::string_view trimmed(std::string_view str, char ch);
std::string_view trimmed_front(std::string_view str, char ch);
std::string_view trimmed_back(std::string_view str, char ch);
std::string_view trimmed(std::string_view str, const char *set);
std::string_view trimmed_front(std::string_view str, const char *set);
std::string_view trimmed_back(std::string_view str, const char *set);
#else // until C++17
std::string trimmed(const std::string &str);
std::string trimmed_left(const std::string &str);
std::string trimmed_right(const std::string &str);
std::string trimmed(const std::string &str, char ch);
std::string trimmed_left(const std::string &str, char ch);
std::string trimmed_right(const std::string &str, char ch);
std::string trimmed(const std::string &str, const char *set);
std::string trimmed_left(const std::string &str, const char *set);
std::string trimmed_right(const std::string &str, const char *set);
#endif

The set of functions stripping unwanted characters from the string edges. Characters to strip can be specified. One can specify single character ch as well as the set of characters set. If no characters is specified, all ASCII-whitespaces are implied. Following naming rules for the functions are used:

Functions trim modify the string in-situ and return the pointer or reference to it. If the original value should be preserved, trimmed functions should be used.

The implementation is optimized for common case when the string does not have anything to trim. In such cases no modifications of the argument are performed, the function returns immediately after the checks are completed, and the call is maximally cheap.

All nullptr values are treated as an empty string.

Example
char st1[] = "\t value    \n";

// CHOICE:
__vic::trim(st1);       // result: "value"
__vic::trim_front(st1); // result: "value    \n"
__vic::trim_back(st1);  // result: "\t value"

std::string st2("...value123");

// CHOICE:
// trim dot chars
__vic::trim_front(st1, '.');        // result: "value123"
// trim all digits
__vic::trim_back(st1, "123456789"); // result: "...value"

2.27.2sift()

char *sift(char *str, const char *trash_chars);
std::string &sift(std::string &str, const char *trash_chars);

Removes all characters from the set from the string. All nullptr values are treated as an empty string.

Example
char st[] = "..ab.c..d.e.";
__vic::sift(st, ".");
assert(std::strcmp(st, "abcde") == 0);

2.27.3sift_if()

template<class Pred>
char *sift(char *str, Pred pred);
template<class Pred>
std::string &sift(std::string &str, Pred pred);

Removes all characters satify the predicate pred. All nullptr values are treated as an empty string.

2.27.4pad_front()

std::string &pad_front(std::string &str, size_t size, char pad_ch = ' ');
char *pad_front(char *str, size_t size, char pad_ch = ' ');

Complements the string up to length size by adding the required number of pad_ch chars to the beginning. Nothing happens if str length is equal or greather than size or the pointer is null. Returns str.

2.27.5pad_back()

std::string &pad_back(std::string &str, size_t size, char pad_ch = ' ');
char *pad_back(char *str, size_t size, char pad_ch = ' ');

Complements the string up to length size by adding the required number of pad_ch chars to the end. Nothing happens if str length is equal or greather than size or the pointer is null. Returns str.

2.27.6starts_with()

bool starts_with(const char *s, char pref);
bool starts_with(const char *s, const char *pref);
bool starts_with(const char *s, const char *pref, size_t pref_len);

#if __cpp_lib_string_view // C++17
bool starts_with(std::string_view s, char pref);
bool starts_with(std::string_view s, std::string_view pref);
bool starts_with(std::string_view s, const char *pref);
#else // until C++17
bool starts_with(const std::string &s, char pref);
bool starts_with(const std::string &s, const char *pref);
bool starts_with(const std::string &s, const std::string &pref);
bool starts_with(const std::string &s, const char *pref, size_t pref_len);
#endif

bool starts_with(const char *s, size_t s_len, char pref);
bool starts_with(const char *s, size_t s_len, const char *pref);
bool starts_with(const char *s, size_t s_len, const char *pref, size_t pref_len);

Returns true if string s starts with the specified prefix.

2.27.7ends_with()

#if __cpp_lib_string_view // C++17
bool ends_with(std::string_view s, char suff);
bool ends_with(std::string_view s, std::string_view suff);
#else // until C++17
bool ends_with(const char *s, char suff);
bool ends_with(const char *s, const char *suff);
bool ends_with(const char *s, const char *suff, size_t suff_len);
bool ends_with(const char *s, size_t s_len, const char *suff);

bool ends_with(const std::string &s, char suff);
bool ends_with(const std::string &s, const char *suff);
bool ends_with(const std::string &s, const std::string &suff);
bool ends_with(const std::string &s, const char *suff, size_t suff_len);
#endif

bool ends_with(const char *s, size_t s_len, char suff);
bool ends_with(const char *s, size_t s_len, const char *suff, size_t suff_len);

Returns true if string s ends with the specified suffix.

2.28__vic/tchar.h

Generic functions to manipulate C-strings regardless of the underlying char-type, like std::char_traits<>. All the functions are located within __vic::tchar namespace.

Most of the functions are just generic redirectors to calls like strcpy, wcscpy, et al. Searching functions have more intelligible names that ones in the C-library and unified parameters: they always take pointers and never indices. Also the set of the functions is complemented with "logically symmetrical" ones missed in the standard library. Searching functions return nullptr in case of failure.

Example
template<class charT>
charT *generic_dup(const charT *st)
{
    namespace tchar = __vic::tchar;

    charT *st_copy = new charT[tchar::length(st) + 1];
    tchar::copy(st_copy, st);
    return st_copy;
}

2.28.1tchar::length()

template<class charT>
size_t tchar::length(const charT *str);

String length in elements. Generic strlen / wcslen.

2.28.2tchar::empty()

template<class charT>
bool tchar::empty(const charT *str);

Checks if str is nullptr or has no characters.

2.28.3tchar::end()

namespace tchar {

template<class charT>
const charT *end(const charT *str);

template<class charT>
charT *end(charT *str);

}

Pointer to the NULL-terminator. Generic strchr(str, '\0') / wcschr(str, L'\0').

Note: Some buggy implementations of std::strchr() like MinGW return non-const char * even if the argument is const char * so this function can be used as a workaround in the similar use case.

2.28.4tchar::compare()

template<class charT>
int tchar::compare(const charT *str1, const charT *str2);

Compare two strings. Generic strcmp / wcscmp.

2.28.5tchar::equal()

template<class charT>
bool tchar::equal(const charT *str1, const charT *str2);

Checks if two strings are equal.

Precondition: str1 != nullptr && str2 != nullptr

2.28.6tchar::copy()

template<class charT>
charT *tchar::copy(charT *dest, const charT *src);

Copy string. Generic strcpy / wcscpy.

2.28.7tchar::move()

template<class charT>
charT *tchar::move(charT *dest, const charT *src);

Move the string in memory (memmove).

2.28.8tchar::concat()

template<class charT>
charT *tchar::concat(charT *dest, const charT *src);

Concatenate two strings. Generic strcat / wcscat.

2.28.9tchar::find()

namespace tchar {

template<class charT>
const charT *find(const charT *str, charT ch);

template<class charT>
charT *find(charT *str, charT ch);

template<class charT>
const charT *find(const charT *str, const charT *sub);

template<class charT>
charT *find(charT *str, const charT *sub);

}

Find the first occurrence of the character or substring. Generic strchr / wcschr / strstr / wcsstr.

2.28.10tchar::rfind()

namespace tchar {

template<class charT>
const charT *rfind(const charT *str, charT ch);

template<class charT>
charT *rfind(charT *str, charT ch);

}

Find the last occurrence of the character. Generic strrchr / wcsrchr.

2.28.11tchar::find_if()

namespace tchar {

template<class charT, class Pred>
const charT *find_if(const charT *str, Pred pred);

template<class charT, class Pred>
charT *find_if(charT *str, Pred pred);

}

Find the first occurrence of the character that satisfies the specified predicate.

2.28.12tchar::find_if_not()

namespace tchar {

template<class charT, class Pred>
const charT *find_if_not(const charT *str, Pred pred);

template<class charT, class Pred>
charT *find_if_not(charT *str, Pred pred);

}

Find the first occurrence of the character that doesn't satisfy the specified predicate.

2.28.13tchar::rfind_if()

namespace tchar {

template<class charT, class Pred>
const charT *rfind_if(const charT *str, Pred pred);

template<class charT, class Pred>
charT *rfind_if(charT *str, Pred pred);

}

Find the last occurrence of the character that satisfies the specified predicate.

2.28.14tchar::rfind_if_not()

namespace tchar {

template<class charT, class Pred>
const charT *rfind_if_not(const charT *str, Pred pred);

template<class charT, class Pred>
charT *rfind_if_not(charT *str, Pred pred);

}

Find the last occurrence of the character that doesn't satisfy the specified predicate.

2.28.15tchar::find_first_of()

namespace tchar {

template<class charT>
const charT *find_first_of(const charT *str, const charT *set);

template<class charT>
charT *find_first_of(charT *str, const charT *set);

}

Find the first occurrence of the character from the specified set. Generic strpbrk / wcspbrk.

2.28.16tchar::find_first_not_of()

namespace tchar {

template<class charT>
const charT *find_first_not_of(const charT *str, const charT *set);

template<class charT>
charT *find_first_not_of(charT *str, const charT *set);

}

Find the first occurrence of the character absent in the specified set. Generic strspn / wcsspn.

2.28.17tchar::find_last_of()

namespace tchar {

template<class charT>
const charT *find_last_of(const charT *str, const charT *set);

template<class charT>
charT *find_last_of(charT *str, const charT *set);

}

Find the last occurrence of the character from the specified set.

2.28.18tchar::find_last_not_of()

namespace tchar {

template<class charT>
const charT *find_last_not_of(const charT *str, const charT *set);

template<class charT>
charT *find_last_not_of(charT *str, const charT *set);

}

Find the last occurrence of the character absent in the specified set.

2.28.19tchar::skip()

namespace tchar {

template<class charT>
const charT *skip(const charT *str, charT ch);

template<class charT>
charT *skip(charT *str, charT ch);

}

Skip all occurrences of the specified character and return the pointer. Pointer to NULL-terminator is returned if no other characters is presented.

2.29__vic/thread.h

Threads support.

2.29.1thread

class thread : private non_copyable
{
public:
    class id;
    using native_handle_type = <implementation-defined>;

    thread();
    virtual ~thread();

    // BEGIN C++11
    thread(thread &&o) noexcept;
    thread &operator=(thread &&o) noexcept;
    // END C++11

    void start();
    void cancel();
    void join();

    bool alive() const;
    bool joinable() const;
    void kill(int signo); // POSIX only

    id get_id() const;
    native_handle_type handle() const;
protected:
    virtual void worker() = 0;
};

Abstract base class for thread objects. Implements "Active object" pattern. Inherit it and define worker() function which content will be executed in the new thread after start() call. Then at some point in your program you must call join() to free OS resources associated with the spawned thread.

Note: The object must always outlive the associated OS thread. Your program will be terminated by std::terminate() call if this usage contract is violated.
Class members
thread()
Postcondition: joinable() == false
~thread()

Calls std::terminate() if precondition is not satisfied.

Precondition: joinable() == false || alive() == false
thread(thread &&o) noexcept [C++11]

Move constructor for C++11 mode.

thread &operator=(thread &&o) noexcept [C++11]

Move assignment for C++11 mode. Calls std::terminate() if precondition is not satisfied.

Precondition: joinable() == false || alive() == false
void start()

Spawns new thread and calls worker() there.

Precondition: joinable() == false
Postcondition: joinable() == true
void cancel()

Cancels the thread execution.

Precondition: joinable() == true
Postcondition: joinable() == true
void join()

Waits for the thread termination if running and makes joinable() == false.

Precondition: joinable() == true
Postcondition: joinable() == false
bool alive() const

Returns true if the thread haven't been terminated yet (worker() function haven't returned).

Precondition: joinable() == true
bool joinable() const

Returns true if the object has a corresponding OS object (thread) created by the start() call and not yet destroyed by join() call.

void kill(int signo) [POSIX]

Sends the signal signo the thread.

Precondition: joinable() == true
id get_id() const

Returns ID of the thread.

native_handle_type handle() const

Returns a native OS-specific handle of the thread.

2.29.2thread::id

class thread::id
{
public:
    id();
    explicit operator bool() const;
    native_handle_type handle() const;
};
bool operator==(thread::id a, thread::id b);
bool operator!=(thread::id a, thread::id b);

Unique thread ID. It can hold a value associated with some thread or the special distinct value not associated with any thread.

Class members
id()

Creates the special value not associated with any thread.

Postcondition: bool(*this) == false
explicit operator bool() const

Returns true if the object holds ID of some thread.

native_handle_type handle() const

Returns a native OS-specific handle of the thread.

Precondition: bool(*this) == true
bool operator==(thread::id a, thread::id b)
bool operator!=(thread::id a, thread::id b)

Check if a and b represent the same thread.

Invariant: id() == id()

2.29.3this_thread

namespace this_thread
{
    thread::id get_id();
    void sleep_ms(unsigned msec);
}

Set of the functions to control the current (calling) thread.

thread::id get_id()

Returns ID of the calling thread.

void sleep_ms(unsigned msec)

Suspends the execution of the calling thread until the time-out interval specified in milliseconds elapses.

2.30__vic/throw_errno.h

2.30.1throw_errno()

[[noreturn]] void throw_errno(const char *prompt);
[[noreturn]] void throw_errno(const char *prompt, int err_no);

Throw an exception with global errno value or given err_no correspondingly. Default exception type is libc_error at the moment but can be changed at link time by overriding this functions. For example std::system_error can be used. Just create cpp-file with the following content in your project:

#include<__vic/throw_errno.h>
#include<system_error>

//----------------------------------------------------------------------------
// Override library functions to throw std::system_error
//----------------------------------------------------------------------------
void __vic::throw_errno(const char *prompt, int err_no)
{
    throw std::system_error(err_no, std::system_category(), prompt);
}
//----------------------------------------------------------------------------

It's enough to override only one functions because the second one just calls throw_errno(prompt, errno).

Example
ssize_t written = ::write(fd, buf, buf_size);
if(written < 0) __vic::throw_errno("write");
// ...

2.31__vic/to_text.h

Generic converters to some text representation.

2.31.1to_text_append()

void to_text_append(long long n, std::string &str);
void to_text_append(long n, std::string &str);
void to_text_append(int n, std::string &str);
void to_text_append(short n, std::string &str);
void to_text_append(signed char n, std::string &str);

void to_text_append(unsigned long long n, std::string &str);
void to_text_append(unsigned long n, std::string &str);
void to_text_append(unsigned n, std::string &str);
void to_text_append(unsigned short n, std::string &str);
void to_text_append(unsigned char n, std::string &str);

void to_text_append(long double n, std::string &str);
void to_text_append(double n, std::string &str);
void to_text_append(float n, std::string &str);

void to_text_append(bool f, std::string &str);

void to_text_append(const void *p, std::string &str);

void to_text_append(const std::string &st, std::string &s);
void to_text_append(const char *st, std::string &s);
void to_text_append(char ch, std::string &s);

#if __cpp_lib_string_view // C++17
void to_text_append(std::string_view sv, std::string &s);
#endif

Converts the specified first argument to some text representation and appends it to the second argument.

This function is a customization point (like std::swap) for the library. Users can define additional overloads for own types (in the same namespace where the type is defined) in order to "teach" the library how to create a text from the value of the specified type.

Note: This is not a replacement for such feature-rich formatting facilities as std::format or std::sprintf. For example, there is no way to represent an integer value in HEX or right-align it to the specified width. The main purpose is the ability to represent the value in debug/log/error messages in some human-readable form.
Note: signed char and unsigned char types are treated as integers not characters!
void to_text_append(long long n, std::string &str)
void to_text_append(long n, std::string &str)
void to_text_append(int n, std::string &str)
void to_text_append(short n, std::string &str)
void to_text_append(signed char n, std::string &str)
void to_text_append(unsigned long long n, std::string &str)
void to_text_append(unsigned long n, std::string &str)
void to_text_append(unsigned n, std::string &str)
void to_text_append(unsigned short n, std::string &str)
void to_text_append(unsigned  char n, std::string &str)
void to_text_append(long double n, std::string &str)
void to_text_append(double n, std::string &str)
void to_text_append(float n, std::string &str)

Converts a number to decimal representation.

void to_text_append(bool f, std::string &str)

Converts a boolean value to 0 or 1.

void to_text_append(const void *p, std::string &str)

Converts a pointer to some platform-specific representation.

void to_text_append(const std::string &st, std::string &s)
void to_text_append(const char *st, std::string &s)
void to_text_append(char ch, std::string &s)
void to_text_append(std::string_view sv, std::string &s) [C++17]

Appends the specified string or character to the output string.

Note: nullptr value in the const char * overload is threated as an empty string.
Example
int n = 5;
std::string st = "n = ";
__vic::to_text_append(n, st);
assert(st == "n = 5");

2.32__vic/type_traits.h

Template metaprogramming support.

All the predicate metafunctions have boolean member value and, usually, derived from integral_constant.

All the type transformer metafunctions have type member type containing the conversion result.

All of the template aliases are available only in C++11 mode.

2.32.1integral_constant

template<class T, T Val>
struct integral_constant
{
    using value_type = T;
    using type = integral_constant<T, Val>;

    static constexpr T value = Val;
};

The topmost base class of the most metafunctions.

2.32.2true_type

using true_type = integral_constant<bool, true>;

Base class for predicate metafunctions that have value true.

2.32.3false_type

using false_type = integral_constant<bool, false>;

Base class for predicate metafunctions that have value false.

2.32.4is_same

template<class T1, class T2> struct is_same;

A predicate. True if T1 and T2 are exactly the same type.

2.32.5is_const

template<class T> struct is_const;

A predicate. True if T has const qualifier.

2.32.6is_byte

template<class T> struct is_byte;

A predicate. True, if T is a type representing byte:

2.32.7byte_cast()

template<class To, class From>
constexpr To byte_cast(From v);

Casts value of From type to To type if both types are byte types (see is_byte).

Precondition: is_byte<From>::value && is_byte<To>::value

2.32.8is_signed_integer

template<class T> struct is_signed_integer;

A predicate. True if T is a one of the "standard signed integer types" (see the Standard).

2.32.9is_unsigned_integer

template<class T> struct is_unsigned_integer;

A predicate. True if T is a one of the "standard unsigned integer types" (see the Standard).

2.32.10conjunction [C++11]

template<class... B> struct conjunction;

A predicate. The logical conjunction of the predicates B.... False iff one of the B... is false.

2.32.11disjunction [C++11]

template<class... B> struct disjunction;

A predicate. The logical disjunction of the predicates B.... True iff one of the B... is true.

2.32.12negation

template<class B> struct negation;

A predicate. The logical negation of the predicate B.

2.32.13remove_const

template<class T> struct remove_const;
template<class T> using remove_const_t = typename remove_const<T>::type;

A type transformer. Removes the top-level const qualifier or just returns T if it doesn't have such qualifier.

2.32.14remove_volatile

template<class T> struct remove_volatile;
template<class T> using remove_volatile_t = typename remove_volatile<T>::type;

A type transformer. Removes the top-level volatile qualifier or just returns T if it doesn't have such qualifier.

2.32.15remove_cv

template<class T> struct remove_cv;
template<class T> using remove_cv_t = typename remove_cv<T>::type;

A type transformer. Removes any top-level cv-qualifier or just returns T if it doesn't have such qualifiers.

2.32.16remove_reference

template<class T> struct remove_reference;
template<class T> using remove_reference_t = typename remove_reference<T>::type;

A type transformer. Returns the type referred by T or just T if it isn't a reference type.

2.32.17remove_cvref

template<class T> struct remove_cvref;
template<class T> using remove_cvref_t = typename remove_cvref<T>::type;

A type transformer. Applies remove_reference then remove_cv to T.

2.32.18remove_pointer

template<class T> struct remove_pointer;
template<class T> using remove_pointer_t = typename remove_pointer<T>::type;

A type transformer. Returns the type pointed by T or just T if it isn't a pointer type.

2.32.19conditional

template<bool Cond, class Then, class Else> struct conditional;

template<bool Cond, class Then, class Else>
using conditional_t = typename conditional<Cond, Then, Else>;

A type transformer. Returns Then if Cond == true. Else is returned otherwise.

2.32.20enable_if, disable_if

template<bool Test, class T = void>
struct enable_if
{
    using type = T;
};
template<class T>
struct enable_if<false, T> {};

template<bool Test, class T = void>
struct disable_if : enable_if<!Test, T> {};

Classical tools for SFINAE-magic.

2.32.21index_sequence, make_index_sequence [C++11]

template<size_t... I>
struct index_sequence
{
    static constexpr size_t size() { return sizeof...(I); }
};

template<size_t Size>
using make_index_sequence = index_sequence<0, 1, ..., Size-1>;

Implementation of C++14 std::index_sequence for C++11.

Note: Unlike std::index_sequence it isn't a special case of some sort of std::integer_sequence.

2.33__vic/unicode.h

Unicode support utilities.

2.33.1unicode_t

using unicode_t = char32_t; // since C++11
// or
using unicode_t = uint_least32_t; // C++98

Type able to store any Unicode code point.

2.33.2utf_transcode()

template<class UTFReader, class UTFWriter>
void utf_transcode(UTFReader r, UTFWriter w);

An algorithm that reads all code points of type unicode_t from UTFReader using r() and writes them to UTFWriter using w().

2.33.3Code point constants

constexpr unicode_t unicode_max = 0x10FFFF;
constexpr unicode_t unicode_bom = 0xFEFF;
constexpr unicode_t unicode_replacement_char = 0xFFFD;

Named constants for some useful Unicode code points.

2.34__vic/utf8/status.h

2.34.1utf8::status

enum class utf8::status : unsigned char
{
    ok = 0,
    eof,
    // Errors
    no_leading_byte,
    truncated_code_point,
    overlong_encoding,
    code_point_too_big
};
using utf8::status_t = utf8::status; // for C++98

Values returned by utf8::reader parse() function.

2.34.2utf8::is_error()

constexpr bool utf8::is_error(utf8::status s);

Returns false for utf8::status::ok and utf8::status::eof values. true is returned otherwise.

2.35__vic/utf8/exceptions.h

namespace utf8 {

class bad_encoding; // public std::exception
    class no_leading_byte;
    class truncated_code_point;
    class overlong_encoding;
    class code_point_too_big;

} // namespace

Exception classes thrown by utf8::reader read() function. All exceptions are derived from abstract base class utf8::bad_encoding. See utf8::status for equivalent status codes.

2.36__vic/utf8/read_result.h

2.36.1utf8::read_result

class utf8::read_result
{
public:
    read_result(utf8::status_t s);
    read_result(unicode_t v);

    unicode_t value() const;
    utf8::status_t status() const;
    explicit operator bool() const;
};

A read result returned by utf8::reader::parse() function.

Class members
read_result(utf8::status_t s)
Precondition: s != utf8::status::ok
Postcondition: status() == s
unicode_t value() const

Returns the value read.

Precondition: status() == utf8::status::ok
utf8::status_t status() const

Returns the read operation status.

explicit operator bool() const

The same as status() == utf8::status::ok.

2.36.2utf8::convert_or_throw()

sread_result<unicode_t> utf8::convert_or_throw(utf8::read_result r);

Converts utf8::read_result to sread_result. Throws exception from __vic/utf8/exceptions.h if is_error(r.status()).

2.37__vic/utf8/reader.h

2.37.1utf8::reader

template<class ByteSReader>
class utf8::reader
{
public:
    using byte_reader_type = ByteSReader;
    ByteSReader &get_byte_reader();
    const ByteSReader &get_byte_reader() const;

    template<class... Args>
    explicit reader(Args&&... args); // since C++11

    reader(); // C++98 only
    explicit reader(ByteSReader r); // C++98 only

    utf8::read_result parse();
    sread_result<unicode_t> read()
    sread_result<unicode_t> operator()();
};

template<class ByteSReader>
utf8::reader<ByteSReader> utf8::make_reader(ByteSReader r);

UTF-8 code points from byte sequence reader. The sequence is accessed using ByteSReader which models sreader<unsigned char> (see S-readers).

Class members
ByteSReader &get_byte_reader()
const ByteSReader &get_byte_reader() const

Returns reference to the used byte reader.

template<class... Args>
explicit reader(Args&&... args) [C++11]

Forwards all parameters to the used byte reader.

reader() [C++98 only]
explicit reader(ByteSReader r) [C++98 only]

Constructors for C++98 mode.

utf8::read_result parse()

Tries to extract the next code point from the byte sequence using ByteSReader. Returns the code point read on success. utf8::status::eof is returned when no more bytes are available. Other statuses are returned on errors, see utf8::status for more details. ByteSReader::operator() is used to access individual bytes.

Note: The function itself doesn't throw exceptions but exception can be thrown by ByteSReader::operator().
sread_result<unicode_t> read()
sread_result<unicode_t> operator()()

The same as parse() but returns sread_result on success or on EOF. Throws an exception from __vic/utf8/exceptions.h otherwise.

Free functions
template<class ByteSReader>
utf8::reader<ByteSReader> utf8::make_reader(ByteSReader r)

Creates UTF-8 reader using the specified ByteSReader.

Example
#include<__vic/utf8/reader.h>
#include<__vic/sreaders/string.h>
#include<string>
#include<cstdint>
#include<iostream>

// C++11
using utf8_string_reader = __vic::utf8::reader<__vic::string_sreader>;

// C++98
struct utf8_string_reader : __vic::utf8::reader<__vic::string_sreader>
{
    explicit utf8_string_reader(const std::string &s)
        : __vic::utf8::reader<__vic::string_sreader>(__vic::string_sreader(s)) {}
};

void print_utf8_code_points(const string &s)
{
    utf8_string_reader r(s);
    while(__VIC_SREAD_RESULT(unicode_t) cp = r())
        std::cout << uint_least32_t(cp.value()) << '\n';
}

2.38__vic/utf8/writer.h

2.38.1utf8::writer

template<class ByteSWriter>
class utf8::writer
{
public:
    using byte_writer_type = ByteSWriter;
    ByteSWriter &get_byte_writer();
    const ByteSWriter &get_byte_writer() const;

    template<class... Args>
    explicit writer(Args&&... args); // since C++11

    writer(); // C++98 only
    explicit writer(ByteSWriter w); // C++98 only

    void write(unicode_t cp);
    void operator()(unicode_t cp);
};

template<class ByteSWriter>
utf8::writer<ByteSWriter> utf8::make_writer(ByteSWriter w);

UTF-8 code points to byte sequence writer. ByteSWriter which models swriter<unsigned char> (see S-writers) is used as a byte output.

Class members
ByteSWriter &get_byte_writer()
const ByteSWriter &get_byte_writer() const

Returns reference to the used byte writer.

template<class... Args>
explicit writer(Args&&... args) [C++11]

Forwards all parameters to the used byte writer.

writer() [C++98 only]
explicit writer(ByteSWriter r) [C++98 only]

Constructors for C++98 mode.

void write(unicode_t cp)
void operator()(unicode_t cp)

Writes the specified code point according to UTF-8 encoding rules. ByteSWriter::operator() is used to write individual bytes.

Free functions
template<class ByteSWriter>
utf8::writer<ByteSWriter> utf8::make_writer(ByteSWriter w)

Creates UTF-8 writer using specified ByteSWriter.

Example
#include<__vic/utf8/writer.h>
#include<__vic/swriters/string.h>
#include<string>
#include<vector>

// C++11
using utf8_string_writer = __vic::utf8::writer<__vic::string_swriter>;

// C++98
struct utf8_string_writer : __vic::utf8::writer<__vic::string_swriter>
{
    explicit utf8_string_writer(std::string &s)
        : __vic::utf8::writer<__vic::string_swriter>(__vic::string_swriter(s)) {}
};

std::string encode_utf8(const std::vector<__vic::unicode_t> &code_points)
{
    std::string utf8_res;
    utf8_string_writer w(utf8_res);
    for(auto cp : code_points) w(cp);
    return utf8_res;
}

2.39__vic/utf16/defs.h

2.39.1utf16::code_unit_t

namespace utf16 {

using code_unit_t = char16_t; // since C++11
// or
using code_unit_t = uint_least16_t; // C++98

} // namespace

UTF-16 code unit type.

2.40__vic/utf16/status.h

2.40.1utf16::status

enum class utf16::status : unsigned char
{
    ok = 0,
    eof,
    // Errors
    truncated_code_unit,
    truncated_code_point,
    invalid_sequence
};
using utf16::status_t = utf16::status; // for C++98

Values returned by utf16::reader parse() function.

2.40.2utf16::is_error()

constexpr bool utf16::is_error(utf16::status s);

Returns false for utf16::status::ok and utf16::status::eof values. true is returned otherwise.

2.41__vic/utf16/exceptions.h

namespace utf16 {

class bad_encoding; // public std::exception
    class truncated_code_unit;
    class truncated_code_point;
    class invalid_sequence;

} // namespace

Exception classes thrown by utf16::reader read() function. All exceptions are derived from abstract base class utf16::bad_encoding. See utf16::status for equivalent status codes.

2.42__vic/utf16/read_result.h

2.42.1utf16::read_result

class utf16::read_result
{
public:
    read_result(utf16::status_t s)
    read_result(unicode_t v);

    unicode_t value() const;
    utf16::status_t status() const;
    explicit operator bool() const;
};

A read result returned by utf16::reader::parse() function.

Class members
read_result(utf16::status_t s)
Precondition: s != utf16::status::ok
Postcondition: status() == s
unicode_t value() const

Returns the value read.

Precondition: status() == utf16::status::ok
utf16::status_t status() const

Returns the read operation status.

explicit operator bool() const

The same as status() == utf16::status::ok.

2.42.2utf16::read_unit_result

class utf16::read_unit_result
{
public:
    read_unit_result(utf16::status_t s)
    read_unit_result(utf16::code_unit_t v);

    utf16::code_unit_t value() const;
    utf16::status_t status() const;
    explicit operator bool() const;
};

The same as utf16::read_result but for utf16::code_unit_t.

2.42.3utf16::convert_or_throw()

sread_result<unicode_t> utf16::convert_or_throw(utf16::read_result r);

Converts utf16::read_result to sread_result. Throws exception from __vic/utf16/exceptions.h if is_error(r.status()).

2.43__vic/utf16/reader.h

2.43.1utf16::reader

template<class CodeUnitReader>
class utf16::reader
{
public:
    using code_unit_reader_type = CodeUnitReader;
    CodeUnitReader &get_code_unit_reader();
    const CodeUnitReader &get_code_unit_reader() const;

    template<class... Args>
    explicit reader(Args&&... args);  // since C++11

    reader(); // C++98 only
    explicit reader(CodeUnitReader r); // C++98 only

    utf16::read_result parse();
    sread_result<unicode_t> read();
    sread_result<unicode_t> operator()();
};

template<class CodeUnitReader>
utf16::reader<CodeUnitReader> utf16::make_reader(CodeUnitReader r);

UTF-16 code points from 2-byte utf16::code_unit_t sequence reader. The sequence is accessed using the special reader of the following structure:

class CodeUnitReader
{
public:
    utf16::read_unit_result operator()();
};
utf16::read_unit_result operator()()

Tries to read the next code unit. Returns the code unit read on success, utf16::status::eof if no more code units are available or utf16::status::truncated_code_unit if only partial code unit is available.

Class members
CodeUnitReader &get_code_unit_reader()
const CodeUnitReader &get_code_unit_reader() const

Returns reference to the used code unit reader.

template<class... Args>
explicit reader(Args&&... args) [C++11]

Forwards all parameters to the used code unit reader.

reader() [C++98 only]
explicit reader(CodeUnitReader r) [C++98 only]

Constructors for C++98 mode.

utf16::read_result parse()

Tries to extract the next code point from code unit sequence using CodeUnitReader. On success the code point read is returned. utf16::status::eof is returned when no more code units available. Other values are returned on errors, see utf16::status for more details. CodeUnitReader::operator() is used to access code units.

Note: The function itself doesn't throw exceptions but exception can be thrown by CodeUnitReader::operator().
sread_result<unicode_t> read()
sread_result<unicode_t> operator()()

The same as parse() but returns sread_result on success or on EOF. Throws an exception from __vic/utf16/exceptions.h otherwise.

Free functions
template<class CodeUnitReader>
utf16::reader<CodeUnitReader> utf16::make_reader(CodeUnitReader r)

Creates UTF-16 reader using the specified CodeUnitReader.

Example
#include<__vic/utf16/reader.h>
#include<__vic/sreaders/string.h>
#include<string>
#include<cstdint>
#include<iostream>

class u16string_code_unit_reader
{
    __vic::basic_string_sreader<char16_t> r;
public:
    explicit u16string_code_unit_reader(const std::u16string &s) : r(s) {}

    __vic::utf16::read_unit_result operator()()
    {
        if(__vic::sread_result<__vic::utf16::code_unit_t> u = r())
            return u.value();
        return __vic::utf16::status::eof;
    }
};

void print_utf16_code_points(const std::u16string &s)
{
    __vic::utf16::reader<u16string_code_unit_reader> r(s);
    __vic::unicode_t cp;
    while(__VIC_SREAD_RESULT(unicode_t) cp = r())
        std::cout << uint_least32_t(cp.value()) << '\n';
}

2.44__vic/utf16/writer.h

2.44.1utf16::writer

template<class CodeUnitSWriter>
class utf16::writer
{
public:
    using code_unit_writer_type = CodeUnitSWriter;
    CodeUnitSWriter &get_code_unit_writer();
    const CodeUnitSWriter &get_code_unit_writer() const;

    template<class... Args>
    explicit writer(Args&&... args); // since C++11

    writer(); // C++98 only
    explicit writer(CodeUnitSWriter w); // C++98 only

    void write(unicode_t cp);
    void operator()(unicode_t cp);
};

template<class CodeUnitSWriter>
utf16::writer<CodeUnitSWriter> utf16::make_writer(CodeUnitSWriter w);

UTF-16 code points to 2-byte utf16::code_unit_t sequence writer. CodeUnitSWriter which models swriter<utf16::code_unit_t> (see S-writers) is used as a code units output.

Class members
CodeUnitSWriter &get_code_unit_writer()
const CodeUnitSWriter &get_code_unit_writer() const

Returns reference to the used code unit writer.

template<class... Args>
explicit writer(Args&&... args) [C++11]

Forwards all parameters to the used code unit writer.

writer() [C++98 only]
explicit writer(CodeUnitSWriter r) [C++98 only]

Constructors for C++98 mode.

void write(unicode_t cp)
void operator()(unicode_t cp)

Writes the specified code point according to UTF-16 encoding rules. CodeUnitSWriter::operator() is used to write individual code units.

Free functions
template<class CodeUnitSWriter>
utf16::writer<CodeUnitSWriter> utf16::make_writer(CodeUnitSWriter w)

Creates UTF-16 writer using specified CodeUnitSWriter.

Example
#include<__vic/utf16/writer.h>
#include<__vic/swriters/string.h>
#include<string>
#include<vector>

std::u16string encode_utf16(const std::vector<__vic::unicode_t> &code_points)
{
    std::u16string utf16_res;
    __vic::utf16::writer<__vic::basic_string_swriter<char16_t>> w(utf16_res);
    for(auto cp : code_points) w(cp);
    return utf16_res;
}

2.45__vic/waitable_event.h

2.45.1waitable_event

class waitable_event : private non_copyable
{
public:
    explicit waitable_event(bool signaled = false);
    ~waitable_event();

    void set();
    void reset();
    bool signaled() const;

    void wait();
    bool wait_ms(unsigned msec);

    // BEGIN C++11
    template<class Rep, class Period>
    bool wait_for(const std::chrono::duration<Rep,Period> &d);
    template<class Clock, class Duration>
    bool wait_until(const std::chrono::time_point<Clock,Duration> &t);
    // END C++11
};

A synchronization object like Event Object in Windows. Can be in ether of two states: signaled or nonsignaled. A thread can effectively wait for the signaled state using one of the available wait-functions (with minimal system resources consumption).

Class members
explicit waitable_event(bool signaled = false)
Postcondition: signaled() == signaled
bool signaled() const

Returns true if the object is in signaled state.

void set()

Sets the signaled state.

Postcondition: signaled() == true
void reset()

Sets the nonsignaled state.

Postcondition: signaled() == false
void wait()

Waits for the signaled state with no timeout.

Postcondition: signaled() == true
bool wait_ms(unsigned msec)

Waits for the signaled state no longer than the specified amount of milliseconds. Returns signaled().

Note: wait_for() should be used in C++11 mode instead.
template<class Rep, class Period>
bool wait_for(const std::chrono::duration<Rep,Period> &d) [C++11]
template<class Clock, class Duration>
bool wait_until(const std::chrono::time_point<Clock,Duration> &t) [C++11]

Waits for the signaled state no longer than the specified timeout. Returns signaled().

2.46__vic/posix/cond_variable.h

2.46.1posix::cond_variable

class posix::cond_variable
{
public:
    constexpr cond_variable() noexcept;
    ~cond_variable();

    cond_variable(const cond_variable & ) = delete;
    cond_variable &operator=(const cond_variable & ) = delete;

    void wait(::pthread_mutex_t &m);
    void wait(posix::mutex &m);

    bool wait_until(::pthread_mutex_t &m, const ::timespec &abstime);
    bool wait_until(posix::mutex &m, const ::timespec &abstime);

    void signal();
    void broadcast();

    // C++11-compatible synonyms
    void notify_one() { signal(); }
    void notify_all() { broadcast(); }
};

POSIX condition variable.

Note: In С++11 mode std::condition_variable can be a better alternative.
Class members
cond_variable()

Creates the object.

~cond_variable()

Destroys the object.

void wait(::pthread_mutex_t &m)
void wait(posix::mutex &m)

Block the calling thread and waits for notification.

bool wait_until(::pthread_mutex_t &m, const ::timespec &abstime)
bool wait_until(posix::mutex &m, const ::timespec &abstime)

As wait() but waiting time is restricted by the timeout. Returns true if notifcation was received and false if timeout was expired.

void signal()
void notify_one()

Notifies one of the waiting threads.

void broadcast()
void notify_all()

Notifies all waiting threads.

2.47__vic/posix/daemon_control.h

2.47.1posix::daemon_control

class posix::daemon_control : private non_copyable
{
public:
    class already_running; // public std::exception

    explicit daemon_control(std::string pid_file_name);
    ~daemon_control();

    void daemonize();

    static int control(const char *cmd, const char *pid_file_name);
    static void stop_and_wait(const char *pid_file_name);
};

A class that implements start, stop, restart, status check and protection against multiple daemon-process instances launch. It is recommended to private-inherit this class by some sort of application class in your application.

Note: PID-file is used to find the process instance. It is created in CWD during process launch. If one removes this file all functions will assume that the process is not running despite the actual status! Therefore only read access to the PID-file by another tools is safe. It can be removed only if it is known for sure that the process is not running at the moment.
Class members
class already_running

An exception thrown by the constructor if the daemon already running at the moment.

explicit daemon_control(std::string pid_file_name)

Starts the application and creates PID-file named pid_file_name in CWD. already_running is thrown if the process is already running.

~daemon_control()

Deletes PID-file created by the constructor.

void daemonize()

Makes the calling process a daemon and updates PID in the PID-file.

static int control(const char *cmd, const char *pid_file_name)

Executes one of the commands specified by the first parameter and returns a status:

  • stop - send SIGTERM to the running process and return a success/unsuccess status (0/1),
  • kill - kill the process with SIGKILL signal and return a success/unsuccess status (0/1),
  • status - check the current process status:
    • print "Running" to stdout and return 0 if the process is running,
    • print "Not running" and return 1 if not,
    • print error message to stderr and return status >1 on failure.

If any other command is passed exception is thrown. The second parameter is the PID-file name passed to the constructor on start.

static void stop_and_wait(const char *pid_file_name)

Sends SIGTERM and waits while process is running. If the process is not running at the moment just returns. This function is used to restart the application, after the call new instance of daemon_control can be created and the application can start its work.

2.48__vic/posix/dir_entries.h

2.48.1posix::dir_entries

class posix::dir_entries : private non_copyable
{
public:
    dir_entries();
    explicit dir_entries(const char *dir);
    ~dir_entries();

    // BEGIN C++11
    dir_entries(dir_entries &&o) noexcept;
    dir_entries &operator=(dir_entries &&o) noexcept;
    // END C++11

    bool reopen(const char *dir);
    void close();
    bool is_open() const;

    const char *next();
#ifdef _DIRENT_HAVE_D_TYPE
    unsigned char type() const;
#endif
    void rewind();
};

Using this class one can iterate over content of the specified directory. Special links . and .. are newer included in the resulting set.

Class members
dir_entries()

Creates the closed object.

Postcondition: is_open() == false
explicit dir_entries(const char *dir)

Tries to open dir directory for listing. The result should be checked using subsequent is_open() call!. On error errno is set appropriately.

~dir_entries()

Calls close() if is_open() == true.

dir_entries(dir_entries &&o) noexcept [C++11]
dir_entries &operator=(dir_entries &&o) noexcept [C++11]

Move operations for C++11 mode.

bool reopen(const char *dir)

Initializes new listing. Calls close() before as needed. Returns true on success. On error errno is set appropriately.

void close()

Frees the resources. Throws on errors.

Precondition: is_open() == true
Postcondition: is_open() == false
bool is_open() const

Returns true if next() can be called.

const char *next()

Returns the next entry or nullptr if the end of the list was reached.

Precondition: is_open() == true
unsigned char type() const

Returns the type of the entry: DT_REG, DT_DIR, et al (see the dirent doc for your system). The member is available only if _DIRENT_HAVE_D_TYPE macro is defined. But anyway, in some situations the file type could not be determined and the value DT_UNKNOWN is returned. All applications must properly handle such situations falling back to the stat() call!

void rewind()

Rewinds the cursor of the listing to the beginning.

Precondition: is_open() == true
Example
// Prints the listing of the current directory
__vic::posix::dir_entries list(".");
if(!list.is_open())
    __vic::throw_errno("Can't open directory for listing");
while(const char *entry = list.next())
    std::cout << entry << '\n';

2.49__vic/posix/dir_files.h

2.49.1posix::dir_files

class posix::dir_files : private non_copyable
{
public:
    dir_files();
    explicit dir_files(const char *dir, const char *pattern = nullptr);
    ~dir_files();

    // BEGIN C++11
    dir_files(dir_files &&o) noexcept;
    dir_files &operator=(dir_files &&o) noexcept;
    // END C++11

    bool reopen(const char *dir, const char *pattern = nullptr);
    void close();
    bool is_open() const;

    const char *next();
    void rewind();
};

The class is similar to dir_entries but ignores all directory entries that are not a regular files. Additionally, one can specify the file mask using pattern parameter.

Example
// Prints the listing of the cpp-files in the current directory
__vic::posix::dir_files files(".", "*.cpp");
if(!files.is_open())
    __vic::throw_errno("Can't open directory for listing");
while(const char *file = files.next())
    std::cout << file << '\n';

2.50__vic/posix/error.h

POSIX-specific error handling tools.

2.50.1posix::is_EAGAIN(), posix::is_ENOENT()

namespace posix {

bool is_EAGAIN(int err_no);
bool is_ENOENT(int err_no);

#define __VIC_CASE_EAGAIN case <val1>: case <val2>: ...
#define __VIC_CASE_ENOENT case <val1>: case <val2>: ...

}

The first function checks if the code is either EAGAIN or EWOULDBLOCK. It works regardless of these codes have the same numeric value or not on the current platform.

The second function checks if the error code is ENOENT, ESTALE or any other error code that means "file not found".

The macros are meant to be used inside switch. They are expanded either to the single case with colon or to the set of cases, and have the same meaning as the corresponding functions.

Example
switch(errno)
{
    __VIC_CASE_ENOENT
        std::cout << "No file found!\n"; break;
    case EPERM:
       ...
}

2.51__vic/posix/file.h

2.51.1posix::file

class posix::file : private non_copyable
{
public:
    explicit constexpr file(int fd = -1);
    file(const char *name, int flags, ::mode_t mode = 0666);
    ~file();

    // BEGIN C++11
    file(file &&o) noexcept;
    file &operator=(file &&o) noexcept;
    // END C++11

    bool open(const char *name, int flags, ::mode_t mode = 0666);
    bool is_open() const;
    void close();
    bool close_nt() noexcept;

    void swap(file &o) noexcept;
    int detach_handle() noexcept;
    int attach_handle(int fd) noexcept;
    int handle() const;
    int descriptor() const { return handle(); }

    size_t read_max(void *buf, size_t n)
        { return read_max(handle(), buf, n); }
    size_t read_some(void *buf, size_t n)
        { return read_some(handle(), buf, n); }
    void write_all(const void *buf, size_t n)
        { write_all(handle(), buf, n); }
    size_t write_all_nt(const void *buf, size_t n) noexcept
        { return write_all_nt(handle(), buf, n); }

    static size_t read_max(int fd, void *buf, size_t n);
    static size_t read_some(int fd, void *buf, size_t n);
    static void write_all(int fd, const void *buf, size_t n);
    static size_t write_all_nt(int fd, const void *buf, size_t n) noexcept;
    static void close_reset(int &fd);
    static bool close_nt(int fd) noexcept;
};

RAII-wrapper for POSIX file descriptors and wrappers for ::read() and ::write() system calls.

Class members
explicit constexpr file(int fd = -1)

Wraps already existing descriptor.

Precondition: fd is either an open descriptor or -1.
file(const char *name, int flags, ::mode_t mode = 0666)

Calls open(). The result should be checked using subsequent is_open() call.

~file()

Calls ::close() if is_open() == true.

file(file &&o) noexcept [C++11]
file &operator=(file &&o) noexcept [C++11]

Move operations for C++11 mode.

bool open(const char *name, int flags, ::mode_t mode = 0666)

Calls ::open() with the specified parameters. Returns is_open(). errno contains the error code in case of failure.

bool is_open() const

Returns true if the file is open.

void close()

Unconditionally calls ::close(). No preliminary checks whether the file is open are performed! Correctly handles interruptions by signals. Throws in case of error. The postcondition is always satisfied, even if the function throws.

Precondition: is_open() == true
Postcondition: is_open() == false
static void close_reset(int &fd)

Unconditionally calls ::close() with the specified descriptor and assigns -1 to it. No preliminary checks are performed! Correctly handles interruptions by signals. Throws in case of error. The postcondition is always satisfied, even if the function throws.

Precondition: fd >= 0
Postcondition: fd == -1
bool close_nt() noexcept
static bool close_nt(int fd) noexcept

Counterpart of close() but newer throws. false is returned in case of error, and errno contains error code.

int detach_handle() noexcept

Releases the descriptor out of the object's control and returns it.

Postcondition: is_open() == false
int attach_handle(int fd) noexcept

Takes fd under control and returns the previous handle value.

Precondition: fd is ether an open descriptor or -1.
Postcondition: handle() == fd
void swap(file &o) noexcept

Swaps the value with o.

int handle() const
int descriptor() const { return handle(); }

Returns the wrapped descriptor.

static size_t read_max(int fd, void *buf, size_t n)
size_t read_max(void *buf, size_t n) { return read_max(handle(), buf, n); }

Tries to read n bytes to the specified buffer. Returns number of bytes read. Returned value can be less than requested only when end of file was reached. Accumulates received chunks until the buffer becomes full. Is not interrupted by signals. Calls throw_errno() on error.

static size_t read_some(int fd, void *buf, size_t n)
size_t read_some(void *buf, size_t n) { return read_some(handle(), buf, n); }

Reads no more than n bytes to the specified buffer. Returns number of bytes read or 0 in case of end-of-file. The function returns after first chunk of any size was successfully received. Is not interrupted by signals. Calls throw_errno() on error.

static void write_all(int fd, const void *buf, size_t n);
void write_all(const void *buf, size_t n) { write_all(handle(), buf, n); }

Writes the whole buffer to the descriptor. Is not interrupted by signals. Calls throw_errno() on error.

static size_t write_all_nt(int fd, const void *buf, size_t n) noexcept
size_t write_all_nt(const void *buf, size_t n) noexcept

Counterpart of write_all() but never throws, returns value less than n instead and errno contains error code.

Example
__vic::posix::file file("path/file", O_WRONLY | O_CREAT);
if(!file.is_open()) __vic::throw_errno("Cannot create file");
const char msg[] = "Hello";
file.write_all(msg, sizeof msg - 1); // write without null-terminator
file.close();

2.52__vic/posix/file_stat.h

2.52.1posix::file_stat

namespace posix {

struct file_stat : public ::stat
{
    enum for_link_t { for_link };

    file_stat() = default;
    file_stat(const struct ::stat &s);
    explicit file_stat(int fd);
    explicit file_stat(const char *path);
    explicit file_stat(const std::string &path);
    file_stat(const char *path, for_link_t);
    file_stat(const std::string &path, for_link_t);

    void get(int fd);
    void get(const char *path);
    void get(const std::string &path);
    void get_for_link(const char *path);
    void get_for_link(const std::string &path);

    bool try_get(int fd);
    bool try_get(const char *path);
    bool try_get(const std::string &path);
    bool try_get_for_link(const char *path);
    bool try_get_for_link(const std::string &path);

    bool get_if_exists(const char *path);
    bool get_if_exists(const std::string &path);

    // POSIX-defined attributes
    dev_t   dev() const { return this->st_dev; }
    ino_t   ino() const { return this->st_ino; }
    mode_t  mode() const { return this->st_mode; }
    nlink_t nlink() const { return this->st_nlink; }
    uid_t   uid() const { return this->st_uid; }
    gid_t   gid() const { return this->st_gid; }
    off_t   size() const { return this->st_size; }
    time_t  atime() const { return this->st_atime; }
    time_t  mtime() const { return this->st_mtime; }
    time_t  ctime() const { return this->st_ctime; }

    bool is_block() const { return S_ISBLK(mode()); }
    bool is_char() const { return S_ISCHR(mode()); }
    bool is_dir() const { return S_ISDIR(mode()); }
    bool is_fifo() const { return S_ISFIFO(mode()); }
    bool is_regular() const { return S_ISREG(mode()); }
    bool is_link() const { return S_ISLNK(mode()); }
    bool is_socket() const { return S_ISSOCK(mode()); }
};
inline bool is_block(const struct ::stat &s) { return S_ISBLK(s.st_mode); }
inline bool is_char(const struct ::stat &s) { return S_ISCHR(s.st_mode); }
inline bool is_dir(const struct ::stat &s) { return S_ISDIR(s.st_mode); }
inline bool is_fifo(const struct ::stat &s) { return S_ISFIFO(s.st_mode); }
inline bool is_regular(const struct ::stat &s) { return S_ISREG(s.st_mode); }
inline bool is_link(const struct ::stat &s) { return S_ISLNK(s.st_mode); }
inline bool is_socket(const struct ::stat &s) { return S_ISSOCK(s.st_mode); }

bool is_same_file(const struct ::stat &s1, const struct ::stat &s2);

}

C++ wrapper for the system structure stat. Constructors and functions get() call throw_errno() in case of error. Functions try_get() return false instead in such cases, error code is placed to errno.

Class members
enum for_link_t { for_link }

Constructor tag.

file_stat()

Creates uninitialized structure.

file_stat(const struct ::stat &s)

Copies s.

explicit file_stat(int fd)
void get(int fd)

Obtains the stat for the file descriptor fd (system call fstat()).

explicit file_stat(const char *path)
explicit file_stat(const std::string &path)
void get(const char *path)
void get(const std::string &path)

Obtains the stat by the file path (system call stat()).

file_stat(const char *path, for_link_t)
file_stat(const std::string &path, for_link_t)
void get_for_link(const char *path)
void get_for_link(const std::string &path)

Obtains the stat for the symbolic link (system call lstat()).

bool try_get(int fd)
bool try_get(const char *path)
bool try_get(const std::string &path)
bool try_get_for_link(const char *path)
bool try_get_for_link(const std::string &path)

Counterparts of get() and get_for_link() but return false instead of throwing exceptions.

bool get_if_exists(const char *path)
bool get_if_exists(const std::string &path)

Counterpart of get() but returns false in case of the file is not found instead of throwing. Throws on other errors.

dev_t   dev() const
ino_t   ino() const
mode_t  mode() const
nlink_t nlink() const
uid_t   uid() const
gid_t   gid() const
off_t   size() const
time_t  atime() const
time_t  mtime() const
time_t  ctime() const

Attributes of the stat structure defined by POSIX standard.

bool is_block() const
bool is_char() const
bool is_dir() const
bool is_fifo() const
bool is_regular() const
bool is_link() const
bool is_socket() const

Wrappers for the standard macros.

bool is_same_file(const struct ::stat &s1, const struct ::stat &s2)

Determines whether both structures refer to the same file.

2.53__vic/posix/fs.h

Tools to handle files and paths within POSIX-compliant filesystem.

2.53.1posix::basename(), posix::dirname()

namespace posix {

std::string basename(const std::string &path);
std::string dirname(const std::string &path);
void basename(const std::string &path, std::string &res);
void dirname(const std::string &path, std::string &res);
void append_basename(const std::string &path, std::string &res);
void append_dirname(const std::string &path, std::string &res);

}

The functions are counterparts of the standard shell-commands. Extract the name of the file or the directory from the given path. There are 3 variations of each function:

Example
std::cout << __vic::posix::dirname("/usr/lib") << '\n';   // "/usr"
std::cout << __vic::posix::basename("/usr/lib") << '\n';  // "lib"
std::cout << __vic::posix::dirname("/usr/lib/") << '\n';  // "/usr"
std::cout << __vic::posix::basename("/usr/lib/") << '\n'; // "lib"
std::cout << __vic::posix::dirname("lib") << '\n';        // "."
std::cout << __vic::posix::basename("lib") << '\n';       // "lib"
std::cout << __vic::posix::dirname("/") << '\n';          // "/"
std::cout << __vic::posix::basename("/") << '\n';         // "/"
std::cout << __vic::posix::dirname("") << '\n';           // "."
std::cout << __vic::posix::basename("") << '\n';          // ""

2.53.2posix::add_trailing_slash(), posix::with_trailing_slash()

namespace posix {

std::string &add_trailing_slash(std::string &path);
std::string with_trailing_slash(const std::string &s);
std::string with_trailing_slash(const char *s);

}

Add trailing slash to the path if absent. add_trailing_slash() modifies the argument and returns a reference to it, while with_trailing_slash() always creates new object and returns it.

Example
std::string path = get_directory();
__vic::posix::add_trailing_slash(path) += "file.name"; // dir/file.name
create_file(path);

2.54__vic/posix/iov.h

Vectored I/O tools.

2.54.1posix::ovectors

template<unsigned N>
class posix::ovectors
{
public:
    ovectors();

    void push_back(const void *buf, size_t buf_len);
    void pop_back();

    ::iovec *ptr();
    const ::iovec *ptr() const;
    unsigned size() const;

    bool full() const;
    bool empty() const;
    void clear();

    static constexpr unsigned max_size() { return N; }
    size_t total_bytes() const;
};

Wrapper for array of system structs iovec that serves gathered output from the set of buffers. Template argument is the maximun number of the buffers.

Class members
ovectors()
Postcondition: empty() && total_bytes() == 0
void push_back(const void *buf, size_t buf_len)

Adds the specified buffer to the set.

Precondition: !full()
Postcondition: size() is increased by 1, total_bytes() is increased by buf_len.
void pop_back()

Removes the last added buffer from the set.

Precondition: !empty()
Postcondition: size() is decreased by 1, total_bytes() is decreased by iov_len of the removed buffer.
::iovec *ptr()
const ::iovec *ptr() const

Returns the pointer to the array of the output vectors.

unsigned size() const

Returns current number of the vectors in the array.

bool full() const

Returns size() == max_size().

bool empty() const

Returns size() == 0.

void clear()

Removes all buffers from the set.

Postcondition: empty() && total_bytes() == 0
static constexpr unsigned max_size()

Returns N.

size_t total_bytes() const

Returns total amount of bytes in all buffers of the array.

Example
__vic::posix::ovectors<3> v;
v.push_back("ovectors", 8);
v.push_back(" in work", 8);
const char nl = '\n';
v.push_back(&nl, 1);

// Prints:
// ovectors in work
__vic::posix::writev_all(1, v); // ::writev(1, v.ptr(), v.size());

2.54.2posix::total(iovec[])

namespace posix {

size_t total(const ::iovec vec[], unsigned vec_len);
template<unsigned vsize> size_t total(const ::iovec (&vec)[vsize]);

}

Calculates total size of the buffers in the array vec.

2.54.3posix::cut_prefix(iovec[])

void posix::cut_prefix(::iovec *&vec, unsigned &vec_len, size_t n);

Removes first n bytes from the set of vectors vec. Returns the pointer to the modified set and the new length of the set. If n is greater than total size of the all buffers, vec_len becomes 0 and the value of vec is undefined.

The function is useful to retry the interrrupted by signal system call when only part of data was written.

2.54.4posix::writev_all()

namespace posix {

void writev_all(int fd, ::iovec vec[], unsigned vec_len, size_t total);

template<unsigned vsize>
void writev_all(int fd, ovectors<vsize> &vec);

}

The functions write contents of the all buffers in the set vec to the descriptor fd. The parameter total must contain the total size of the all buffers (can be calculated using __vic::posix::total(vec, vec_len) or __vic::posix::total(vec)). The functions are not interrupted by signals. Exceptions are thrown on errors.

2.55__vic/posix/mutex.h

2.55.1posix::mutex

class posix::mutex
{
public:
    constexpr mutex() noexcept;
    ~mutex();

    mutex(const mutex & ) = delete;
    mutex &operator=(const mutex & ) = delete;

    void lock();
    bool try_lock();
    bool unlock() noexcept;

    // System-specific handle
    ::pthread_mutex_t *handle();
    const ::pthread_mutex_t *handle() const;
};

Wrapper for plain non-recursive pthread_mutex_t. See mutex for usage notes.

Class members
constexpr mutex() noexcept

Creates unlocked mutex.

~mutex()

Destroys the mutex.

void lock()

Acquires the mutex. Waits until released if acquired by other thread at the moment.

bool try_lock()

Tries to acquire the mutex. Immediately returns false if it's already acquired by another thread, without waiting.

bool unlock() noexcept

Releases the mutex acquired before. In some cases can return false in case of error, but in general error detection is not guaranteed.

::pthread_mutex_t *handle()
const ::pthread_mutex_t *handle() const

Returns the native handle of the mutex.

Example

See posix::mutex_lock.

2.55.2posix::mutex_lock

class posix::mutex_lock : private non_copyable, private non_heap_allocatable
{
public:
    enum adopt_t { adopt };

    explicit mutex_lock(posix::mutex &mtx);
    mutex_lock(posix::mutex &mtx, adopt_t);

    explicit mutex_lock(::pthread_mutex_t &mtx);
    mutex_lock(::pthread_mutex_t &mtx, adopt_t);

    ~mutex_lock() noexcept(false);
};

Class manages the lock on a mutex. The lock exists while the object is alive. Can handle posix::mutex class objects as well as system pthread_mutex_t.

Class members
adopt

Constructor tag, suppresses the lock acquisition.

explicit mutex_lock(posix::mutex &mtx)
explicit mutex_lock(::pthread_mutex_t &mtx)

Acquires mtx.

~mutex_lock() noexcept(false)

Releases mtx. Can throw exception in case of error and when there is no other active exception!

mutex_lock(posix::mutex &mtx, adopt_t)
mutex_lock(::pthread_mutex_t &mtx, adopt_t)

Adopts already acquired mtx. See the example.

Example
// Typical usage
void reentrant_function()
{
    static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
    __vic::posix::mutex_lock lock(mtx);
    // Critical section code until the end of the block
    ...
}

// Usage of non-acquiring constructor
__vic::posix::mutex mtx;
if(mtx.try_lock()) // Try to acquire the mutex
{
    // The mutex has been successfully acquired
    using __vic::posix::mutex_lock;
    mutex_lock lock(mtx, mutex_lock::adopt);
    // Critical section code until the end of the block
    ...
}
else
{
    // The mutex is acquired by another thread
    ...
}

2.56__vic/posix/pidfile.h

2.56.1posix::pidfile

class posix::pidfile : private non_copyable
{
public:
    class already_exists; // : public std::exception

    explicit pidfile(std::string file_name);
    ~pidfile();

    void create();
    void prepare_to_daemon();
    void rewrite_pid();
};

A class to operate PID-files, i.e. files contain a PID of a process (usually daemon-process). Used to stop the daemon and to protect against running multiple simultaneous daemon instances.

Class members
class already_exists

An exception. See create() description.

explicit pidfile(std::string file_name)

Sets PID-file name.

~pidfile()

Deletes PID-file.

void create()

Creates PID-file with a name specified in the constructor. Throws already_exists if such PID-file is already created by another process instance.

void prepare_to_daemon()

This function must be called before daemon() syscall.

void rewrite_pid()

Updates PID in the PID-file. PID is changed after daemon() syscall.

2.57__vic/posix/process.h

OS processes-related tools.

2.57.1posix::daemon()

void posix::daemon(bool nochdir, bool noclose = false);

Makes the calling process a UNIX daemon. The function is just a redirector to the system call if the OS implements it, like *BSD, Linux, QNX. The function throws on errors.

2.57.2posix::ignore_signals()

namespace posix {

void ignore_signals(const int sigs[], size_t sigs_len);
template<size_t Size> void ignore_signals(const int (&sigs)[Size]);
// BEGIN C++11
void ignore_signals(std::initializer_list<int> sigs);
// END C++11

}

Ignore the specified signals (sigaction() call is used).

Example
int sigs[] = { SIGINT, SIGQUIT, SIGTERM };
__vic::posix::ignore_signals(sigs);

// or since C++11 just
__vic::posix::ignore_signals({SIGINT, SIGQUIT, SIGTERM});

2.57.3posix::process_alive()

bool posix::process_alive(pid_t pid);

Returns true if process associated with the PID exists and not a zombie.

2.58__vic/posix/sigset.h

2.58.1posix::sigset

class posix::sigset
{
public:
    sigset() = default;
    sigset(const ::sigset_t &set);
    template<size_t Size> sigset(const int (&sigs)[Size]);
    // BEGIN C++11
    sigset(std::initializer_list<int> sigs);
    sigset &operator=(std::initializer_list<int> sigs)
    // END C++11

    sigset &assign(const int *sigs, size_t n);
    template<size_t Size>
    sigset &operator=(const int (&sigs)[Size]);

    sigset &add(int signo);
    sigset &del(int signo);
    sigset &operator+=(int signo);
    sigset &operator-=(int signo);
    sigset &operator<<(int signo);
    sigset &operator>>(int signo);

    sigset &fill();
    sigset &clear();

    static sigset full();
    static sigset empty();

    bool is_member(int signo) const;
    bool contains(int signo) const;

    operator ::sigset_t &();
    operator const ::sigset_t &() const;

    ::sigset_t *operator&();
    const ::sigset_t *operator&() const;
};

Handy C++ wrapper for the system type sigset_t. Set operations are defined as C++-operators and member-functions.

Class members
sigset()

Creates the uninitialized object.

sigset(const ::sigset_t &set)

Creates the copy of set. Implicit converter from the sigset_t type.

sigset(std::initializer_list<int> sigs) [C++11]
template<size_t Size> sigset(const int (&sigs)[Size])

Creates the set filled with signals from sigs.

sigset &operator=(std::initializer_list<int> sigs) [C++11]
template<size_t Size> sigset &operator=(const int (&sigs)[Size])
sigset &assign(const int *sigs, size_t n)

Calls clear() and fills the set with signals from sigs.

sigset &add(int signo)
sigset &operator+=(int signo)
sigset &operator<<(int signo)

Adds the signal to the set.

sigset &del(int signo)
sigset &operator-=(int signo)
sigset &operator>>(int signo)

Removes the signal from the set.

sigset &fill()

Fills the set with all signals (sigfillset()).

sigset &clear()

Clears the set - removes all signals from the set (sigemptyset()).

static sigset full()

Creates the set filled with all signals.

static sigset empty()

Creates the empty set of signals.

bool is_member(int signo)
bool contains(int signo)

Checks if the set contains signo.

operator ::sigset_t &()
operator const ::sigset_t &() const

Implicit conversion to the sigset_t.

::sigset_t *operator&()
const ::sigset_t *operator&() const

Overloaded address operator.

Example
using __vic::posix::sigset;
namespace this_thread = __vic::posix::this_thread;

// Waiting for all but SIGTERM and SIGQUIT
int sig = this_thread::sigwait( sigset::full() >> SIGTERM >> SIGQUIT );

// Waiting for Ctrl+C
this_thread::sigwait( sigset::empty() << SIGINT );
// or for C++11
this_thread::sigwait( sigset{ SIGINT } );

2.59__vic/posix/thread.h

C++ wrappers for Pthreads.

2.59.1posix::this_thread

namespace posix::this_thread { ... }

Set of the functions to control the current thread.

2.59.2posix::this_thread::sigwait(), posix::this_thread::sigwait_at_most()

namespace posix::this_thread
{
    int sigwait(const ::sigset_t &set);

    int sigwait_at_most(const ::sigset_t &set, const ::timespec &timeout);
}

sigwait() suspends the current thread until the signal from set is received. Received signal is returned as a result.

sigwait_at_most() is the same but waits no longer than the specified timeout. Returns 0 on timeout or when interrupted by signal other than one of those in set.

2.59.3posix::this_thread::sigwaitinfo(), posix::this_thread::sigwaitinfo_at_most()

namespace posix::this_thread
{
    ::siginfo_t sigwaitinfo(const ::sigset_t &set);

    bool sigwaitinfo_at_most(const ::sigset_t &set,
        const ::timespec &timeout, ::siginfo_t &res);
}

sigwaitinfo() is a counterpart of sigwait() but returns an additional information about the received signal. The signal is returned in si_signo field.

Note: The function is not interrupted by signal handlers as opposed to the system call of the same name.

sigwaitinfo_at_most() is the same but waits no longer than the specified timeout. Returns false on timeout or when interrupted by signal other than one of those in set. If true is returned res contains filled siginfo_t.

Note: ::sigaction() with sa_flags containing SA_SIGINFO has to be called for each signal from set before usage of any of these functions! Otherwise the returned siginfo_t value will contain garbage!

2.59.4posix::this_thread::block_signals(), posix::this_thread::unblock_signals(), posix::this_thread::set_sigmask()

namespace posix::this_thread
{
    void block_signals(const ::sigset_t &mask,
                                ::sigset_t *oldmask = nullptr);
    void unblock_signals(const ::sigset_t &mask,
                                ::sigset_t *oldmask = nullptr);
    void set_sigmask(const ::sigset_t &mask, ::sigset_t *oldmask = nullptr);
}

block_signals() adds signals from the set to the blocked ones in the calling thread.

unblock_signals() removes the signals from the set from the blocked ones in the calling thread.

set_sigmask() sets the mask of blocked signals for the calling thread. All signals from the set are blocked, others - aren't.

2.60__vic/posix/time.h

POSIX time-related utilities.

2.60.1posix::time_spec

struct posix::time_spec : ::timespec
{
    // Unit tags
    enum sec_units { sec };
    enum msec_units { msec };
    enum usec_units { usec };
    enum nsec_units { nsec };

    time_spec() = default;
    time_spec(time_t secs, long nsecs);

    time_spec(time_t secs, sec_units);
    time_spec(time_t msecs, msec_units);
    time_spec(time_t usecs, usec_units);
    time_spec(time_t nsecs, nsec_units);

    // BEGIN C++11
    template<class Rep, class Period>
    time_spec(std::chrono::duration<Rep,Period> d);

    operator std::chrono::nanoseconds() const;

    template<class Rep, class Period>
    time_spec &operator+=(std::chrono::duration<Rep,Period> t2);
    template<class Rep, class Period>
    time_spec &operator-=(std::chrono::duration<Rep,Period> t2);
    // END C++11

    time_spec &operator+=(time_spec t2);
    time_spec &operator-=(time_spec t2);
};

bool operator==(time_spec t1, time_spec t2);
bool operator!=(time_spec t1, time_spec t2);
bool operator< (time_spec t1, time_spec t2);
bool operator> (time_spec t1, time_spec t2);
bool operator<=(time_spec t1, time_spec t2);
bool operator>=(time_spec t1, time_spec t2);

time_spec operator+(time_spec t1, time_spec t2);
time_spec operator-(time_spec t1, time_spec t2);

Handy C++ wrapper for the system type timespec. Allows to specify time using various units as well as sum up, subtract and compare the values using C++ operators.

Class members
enum sec_units { sec }
enum msec_units { msec }
enum usec_units { usec }
enum nsec_units { nsec }

Constructor tags to specify units.

time_spec()

Creates uninitialized object.

time_spec(time_t secs, long nsecs)

Fills the fields of the structure with the specified values.

time_spec(time_t secs, sec_units)
time_spec(time_t msecs, msec_units)
time_spec(time_t usecs, usec_units)
time_spec(time_t nsecs, nsec_units)

Specifies time in seconds, milliseconds, microseconds and nanoseconds, respectively.

template<class Rep, class Period>
time_spec(std::chrono::duration<Rep,Period> d) [C++11]

Creates time_spec from std::chrono::duration.

operator std::chrono::nanoseconds() const [C++11]

Converts the value to nanoseconds.

template<class Rep, class Period>
time_spec &operator+=(std::chrono::duration<Rep,Period> t2) [C++11]
time_spec &operator+=(time_spec t2)
time_spec operator+(time_spec t1, time_spec t2)

Sums up two values.

template<class Rep, class Period>
time_spec &operator-=(std::chrono::duration<Rep,Period> t2) [C++11]
time_spec &operator-=(time_spec t2)
time_spec operator-(time_spec t1, time_spec t2)

Calculates the difference between two values.

Precondition: t2 <= t1
bool operator==(time_spec t1, time_spec t2)
bool operator!=(time_spec t1, time_spec t2)
bool operator< (time_spec t1, time_spec t2)
bool operator> (time_spec t1, time_spec t2)
bool operator<=(time_spec t1, time_spec t2)
bool operator>=(time_spec t1, time_spec t2)

Comparison operators.

Example
__vic::posix::time_spec t(5, __vic::posix::time_spec::sec);
::nanosleep(&t, nullptr); // sleep for 5 sec

2.60.2posix::nanoseconds_since_epoch()

posix::time_spec posix::nanoseconds_since_epoch();

Returns the current number of seconds and nanoseconds since the Epoch (UNIX-time). Uses posix::realtime_clock::get_time() to obtain the result when available. The actual precision depends on the used platform.

2.60.3posix::realtime_clock, posix::monotonic_clock

#if _POSIX_TIMERS > 0

class posix::realtime_clock
{
public:
    static constexpr clockid_t id = CLOCK_REALTIME;
    static constexpr bool is_steady = false;
    // BEGIN C++11
    using duration   = std::chrono::nanoseconds;
    using period     = duration::period;
    using rep        = duration::rep;
    using time_point = std::chrono::time_point<realtime_clock, duration>;

    static time_point now();
    // END C++11

    static posix::time_spec get_time();
};
#ifdef _POSIX_MONOTONIC_CLOCK
class posix::monotonic_clock
{
public:
    static constexpr clockid_t id = CLOCK_MONOTONIC;
    static constexpr bool is_steady = true;
    // BEGIN C++11
    using duration   = std::chrono::nanoseconds;
    using period     = duration::period;
    using rep        = duration::rep;
    using time_point = std::chrono::time_point<monotonic_clock, duration>;

    static time_point now();
    // END C++11

    static posix::time_spec get_time();
};
#endif

#endif

POSIX system clocks (clock_gettime()) with <chrono>-clock interface. Absent in system not supporting them (check _POSIX_TIMERS macro). Additionally monotonic_clock is available only if _POSIX_MONOTONIC_CLOCK macro is defined.

Class members
static constexpr clockid_t id

System ID of the clock.

static time_spec get_time()

Returns the current time as posix::time_spec.

static time_point now() [C++11]

Returns the current time as time_point.

3S-readers

template<class T>
interface sreader
{
    sreader(sreader &&o); or sreader(const sreader &o);
    sreader_result<T> auto operator()(); // throws on errors
};

sreader is a concept used by the library algorithms to read logical sequence of elements of type T element by element. It is a generalization and rework of the input iterator concept. In particular it handles streams, NULL-terminated strings and other sequences where end-iterator is meaningless or expensive to obtain better. At the same time, a traditional [begin,end) pair of iterators is just a particular case and fully and well handled by __vic::iterator_sreader adapter.

"sreader" is pronounced as "S-reader" where S stands for "Sequential", "Sequence" or "Stream".

When the particular class meets the requirements of this concept for some T it is said to model the sreader<T> concept.

Each sreader object has to be move- or copy-constructible.

Class members (sreader)
sreader_result<T> auto operator()()

Attempts to get the next element of the sequence. On success the returned object is true and its value() member-functions returns the element read. If no element available (EOF), returns false. Throws an exception in the other cases.

Values returned by sreaders (sreader_result) provide the following interface:

template<class T>
interface sreader_result
{
    explicit operator bool() const;
    T value() const;
};

An sreader read result contains a status of the read operation (success/failure) and the value read if the read was successful. The instances are (trivially) copy-constructible and copy-assignable.

sreader result types provide structured bindings support in the following form:

auto [value, ok] = reader();

Since C++98 lacks auto type specifiers, usage of different result types is impractical. In this language mode sreaders return sread_result type (or a type implicitly convertible to it).

Class members (sreader_result)
explicit operator bool() const

Returns true if the read was successful and value() contains the value read. false usually means EOF.

T value() const

Returns the value read.

Precondition: *this == true
Examples
// Basic usage (C++11+)
while(auto res = reader())
{
    // Use res.value() ...
}
// Using structured bindings (C++17+)
for(;;)
{
    auto [value, ok] = reader();
    if(!ok) break;
    // Use value ...
}
// C++26+
while(auto [value, _] = reader())
{
    // Use value ...
}
// Legacy C++98
while(__VIC_SREAD_RESULT(T) res = reader())
{
    // Use res.value() of type T ...
}

3.1__vic/sreaders/defs.h

3.1.1sreader [C++20]

template<class R, class T>
concept sreader =
    std::movable<R> &&
    requires(R r) {
        {r()} -> sreader_result<T>;
    };

A C++ concept for sreaders.

3.1.2byte_sreader [C++20]

template<class R, class T>
concept byte_sreader = sreader<R, T> && is_byte<T>::value;

A C++ concept for sreaders that read bytes.

3.1.3sreader_result [C++20]

template<class R, class T>
concept sreader_result =
    std::semiregular<R> &&
    requires(R r) {
        bool{r};
        {r.value()} -> std::same_as<T>;
    };

A C++ concept for sreader results.

3.1.4sreader_value_t

template<class SReaderResult>
struct sreader_value
{
    typename type;
};

template<class SReaderResult>
using sreader_value_t = typename sreader_value<SReaderResult>::type;

A metafunction returning the type returned by the value() member-function of the specified SReaderResult.

Example
__vic::sreader_value<__vic::sread_result<int> >::type value; // int value;

3.1.5uchar_value()

template<class ByteSReaderResult>
unsigned char uchar_value(ByteSReaderResult r);

Returns the resulting byte value – r.value() – as an unsigned char.

This function is defined only if is_byte<sreader_value_t<ByteSReaderResult>>::value == true.

Precondition: r == true (same as for r.value())

3.2__vic/sreaders/result.h

3.2.1sread_result

template<class T>
class sread_result
{
public:
    sread_result();
    sread_result(sread_eof_t);
    sread_result(T v);

    explicit operator bool() const;
    T value() const;
};

template<>
class sread_result<unsigned char>
{
public:
    // All the members from the non-specialized version...

    // + Implicit converters:
    sread_result(sread_result<char> r);
    sread_result(sread_result<char8_t> r);
    sread_result(sread_result<std::byte> r);
};
unsigned char uchar_value(sread_result<unsigned char> r);

#if __cplusplus >= 201103L // C++11
#define __VIC_SREAD_RESULT(T) auto
#else // C++98
#define __VIC_SREAD_RESULT(T) ::__vic::sread_result<T>
#endif

A concrete type (template) that models sreader_result [C++20].

The sread_result<unsigned char> specialization is compatible (implicitly convertible) with any byte result type representation including:

Example (unsigned char specialization)
__vic::sread_result<char> char_reader();

__vic::sread_result<unsigned char> res = char_reader(); // OK

The __VIC_SREAD_RESULT(T) macro is used in a code that is required to be C++98-compable to specify the return type instead of auto:

__VIC_SREAD_RESULT(char) result = chars_reader();
Class members
sread_result()
sread_result(sread_eof_t)
Postcondition: !*this
sread_result(T v)
Postcondition: *this && value() == v
explicit operator bool() const

Returns the read operation status.

T value() const

Returns the value read.

Precondition: *this == true
Free functions
unsigned char uchar_value(sread_result<unsigned char> r)

Returns r.value().

Precondition: r == true

3.2.2sread_eof

struct sread_eof_t;
inline constexpr sread_eof_t sread_eof;

The special value used to (implicitly) construct an unsuccessfull sread_result of any value type.

3.3Concrete sreaders

3.3.1iterator_sreader

#include<__vic/sreaders/iterator.h>

template<class InputIterator,
         class T = typename std::iterator_traits<InputIterator>::value_type>
class iterator_sreader
{
public:
    iterator_sreader(InputIterator begin, InputIterator end);
    sread_result<T> operator()();
    InputIterator position() const;
};

template<class InputIterator> iterator_sreader<InputIterator>
make_iterator_sreader(InputIterator begin, InputIterator end);

template<class T, class InputIterator> iterator_sreader<InputIterator,T>
make_iterator_sreader_for(InputIterator begin, InputIterator end);

An adapter for a traditional [begin,end) pair of iterators.

Additional position() function returns the current iterator position.

Can be created using constructor or one of make_... functions.

3.3.2iterator_sreader_n

#include<__vic/sreaders/iterator.h>

template<class InputIterator,
         class T = typename std::iterator_traits<InputIterator>::value_type>
class iterator_sreader_n
{
public:
    iterator_sreader_n(InputIterator begin, size_t n);
    sread_result<T> operator()();
    InputIterator position() const;
};

template<class InputIterator> iterator_sreader_n<InputIterator>
make_iterator_sreader_n(InputIterator begin, size_t n);

template<class T, class InputIterator> iterator_sreader_n<InputIterator,T>
make_iterator_sreader_n_for(InputIterator begin, size_t n);

An adapter for iterator + elements counter.

Additional position() function returns the current iterator position.

Can be created using constructor or one of make_... functions.

3.3.3container_sreader

#include<__vic/sreaders/container.h>

template<class Cont, class T = typename Cont::value_type>
class container_sreader
{
public:
    explicit container_sreader(const Cont &c);
    sread_result<T> operator()();
    typename Cont::const_iterator position() const;
};

template<class Cont>
container_sreader<Cont> make_scontainer_sreader(const Cont &c);

template<class T, class Cont>
container_sreader<Cont,T> make_container_sreader_for(const Cont &c);

An adapter for STL-style container classes with begin() and end() members.

Additional position() function returns the current iterator position.

Can be created using constructor or one of make_... functions.

3.3.4cstring_sreader

#include<__vic/sreaders/cstring.h>

template<class charT>
class basic_cstring_sreader
{
public:
    explicit basic_cstring_sreader(const charT *s);
    sread_result<charT> operator()();
    const charT *position() const;
};
using cstring_sreader = basic_cstring_sreader<char>;

template<class charT>
basic_cstring_sreader<charT> make_cstring_sreader(const charT *s);

An adapter for NULL-terminated C-style strings.

Additional position() function returns the current pointer position.

Can be created using constructor or make_... function.

3.3.5string_sreader

#include<__vic/sreaders/string.h>

template<class charT>
class basic_string_sreader
{
public:
    template<class Tr, class Al>
    explicit basic_string_sreader(const std::basic_string<charT,Tr,Al> &s);
    sread_result<charT> operator()();
    const charT *position() const;
};
using string_sreader = basic_string_sreader<char>;

template<class charT, class Tr, class Al>
basic_string_sreader<charT>
    make_string_sreader(const std::basic_string<charT,Tr,Al> &s);

An adapter for std::basic_string.

Additional position() function returns the current pointer position.

Can be created using constructor or make_... function.

3.3.6cstream_sreader

#include<__vic/sreaders/cstream.h>

class cstream_sreader
{
public:
    explicit cstream_sreader(std::FILE *fp);
    sread_result<char> operator()() { return __vic::read(fp); }
};

cstream_sreader make_cstream_sreader(std::FILE *fp);

Models sreader<char> for std::FILE.

Can be created using constructor or make_... function.

4S-writers

template<class T>
class swriter
{
public:
    swriter(swriter &&o); or swriter(const swriter &o);
    void operator()(T v); // throws on errors
};

swriter is a concept used by the library algorithms to write logical sequence of elements of type T element by element. It is a generalization and rework of the OutputIterator concept. In particular it handles streams and other output sequences where end-iterator is meaningless or expensive to obtain better. At the same time, a traditional output iterators are just a particular case and fully and well handled by __vic::iterator_swriter adapter.

"swriter" is pronounced as "S-write" where S stands for "Sequential", "Sequence" or "Stream".

When the particular class meets the requirements of this concept for some T it is said to model the swriter<T> concept.

Each instance of the class has to be move- or copy-constructible.

Class members
void operator()(T v)

Writes the element or throws an exception on error.

4.1__vic/swriters/defs.h

4.1.1swriter [C++20]

template<class W, class T>
concept swriter =
    std::movable<W> &&
    requires(W w, const T v) {
        w(v);
    };

A C++ concept for swriters.

4.2Concrete swriters

4.2.1null_swriter

#include<__vic/swriters/null.h>

class null_swriter
{
public:
    template<class T> void operator()(T v) {}
};

null_swriter make_null_swriter();

Fake writer that accepts any value and does nothing with it (like UNIX /dev/null).

4.2.2push_back_swriter

#include<__vic/swriters/push_back.h>

template<class Cont, class T = typename Cont::value_type>
class push_back_swriter
{
public:
    explicit push_back_swriter(Cont &c);
    void operator()(T v) { c->push_back(v); }
};

template<class Cont>
push_back_swriter<Cont> make_push_back_swriter(Cont &c);

template<class T, class Cont>
push_back_swriter<Cont,T> make_push_back_swriter_for(Cont &c);

An adapter. Uses push_back() member function to write elements. Can be created using constructor or one of make_... functions.

4.2.3iterator_swriter

#include<__vic/swriters/iterator.h>

template<class OutputIterator,
         class T = typename std::iterator_traits<OutputIterator>::value_type>
class iterator_swriter
{
public:
    explicit iterator_swriter(OutputIterator it);
    void operator()(T v);
};

template<class OutputIterator>
iterator_swriter<OutputIterator> make_iterator_swriter(OutputIterator it);

template<class T, class OutputIterator>
iterator_swriter<OutputIterator,T> make_iterator_swriter_for(OutputIterator it);

Output iterator writer. Can be created using constructor or one of make_... functions.

4.2.4string_swriter

#include<__vic/swriters/string.h>

template<
    class charT,
    class Tr = std::char_traits<charT>,
    class Al = std::allocator<charT>
>
class basic_string_swriter
{
public:
    explicit basic_string_swriter(std::basic_string<charT,Tr,Al> &s);
    void operator()(charT ch);
};

using string_swriter = basic_string_swriter<char>;

template<class charT, class Tr, class Al>
basic_string_swriter<charT,Tr,Al>
    make_string_swriter(std::basic_string<charT,Tr,Al> &s);

An adapter for std::basic_string. Can be created using constructor or make_... function.

4.2.5cstream_swriter

#include<__vic/swriters/cstream.h>

class cstream_swriter
{
public:
    explicit cstream_swriter(std::FILE *fp);
    void operator()(char ch) { __vic::write(fp, ch); }
};

cstream_swriter make_cstream_swriter(std::FILE *fp);

Models swriter<char> for std::FILE. Can be created using constructor or make_... function.

5Config library [C++11]

The library provides tools for parsing and reading configuration files. The tools are:

5.1File format description

Configuration file is a text file with a set of named parameters and their values. Parameters can be:

  1. Ordinary atomic or
  2. Complex (compound).

Also, from the multiplicity point of view, they (both atomic and complex) can be:

  1. Solitary (scalar) or
  2. Multiple (list).

Each parameter has a name and a value. Atomic parameters are defined like this:

name: value

Lists consist of a set of values of the same type. Two equivalent notation can be used to define them. Use any of them you find more convenient.

Notation 1:

list_name: value1
list_name: value2
list_name: value3

Notation 2:

list_name {
value1
value2
value3
}

As you can see, the first notation is the same as that used for the scalar types. The only difference is that a scalar parameter gets only the last value, while a list gets all of them.

Both notations can be combined. For example, if you want the value }, it can be added using the first notation with a colon. The rest can be added using braces:

chars {
$
#
{
}

chars: }

A snippet like this creates a list of 4 elements: "$", "#", "{", "}".

Multiline values can be specified the following syntax:

name <<EOF
string 1
string 2
...
EOF

Where EOF is any sequence of Latin letters. The syntax and processing logic are the same as for the Bourne Shell "here-document" construct.

Complex parameters consist of a set of subparameters. For example:

complex_param (
    scalar_subparam: value
    list_subparam {
        value1
        value2
    }
    complex_subparam (
        ...
    )
)

As mentioned above, complex parameters can also be lists. The second list notation (see above) for complex parameters looks like this:

complex_list_param {
    (
        subparam: value1
        ...
    )
    (
        subparam: value2
        ...
    )
}

The first list notation for complex parameters is allowed as well.

Lines starting with the '#' character are treated as comments and are ignored by the parser.

If different files contain the same subset of parameters and their values, this common part can be moved to a separate file and then simply included in them. The following syntax is used:

...
<common.cfg>

param: value
...

common.cfg here is the name of the included file. The set of parameters from it is included in the current configuration file.

5.2Representation in code

The configuration in the code is represented as a struct with a set of fields corresponding to the configuration parameters. The names do not have to be the same as in the file. On instantiation of such struct, each field must get some default value.

A complex parameter is also a struct and can be treated as a configuration. In fact, the only difference is that they do not occupy the entire file, only a fragment between the parens.

The base class config::parser [C++11] is created to fill in such structs. To create your own parser, you derive a class from the base parser and then describe the set of parameters in the constructor. There are 2 ways to describe an atomic parameter: either using the __VIC_REGISTER_CONFIG_PARAM()/__VIC_REGISTER_CONFIG_PARAM_VP() macros, or using the register_param() member function defined in config::parser. The first method is more convenient if the parameter name is the same in both the struct and the file – you do not have to specify it twice. Complex parameters are described using either the __VIC_REGISTER_COMPLEX_CONFIG_PARAM() macro, or the register_complex_param() member function.

Here is an example. Suppose your code contains a structure with configuration parameters, like this:

struct myconfig
{
    myconfig() = default; // sets the parameters to their default values

    int                      int_param = 0;
    std::string              str_param{"default"};
    std::vector<std::string> list_param;
};

Let's assume that all the parameters except str_param have the same name in the file, and str_param is called "string" in the file. Now let's define a parser for the structure:

struct myconfig_parser : public __vic::config::parser
{
    explicit myconfig_parser(myconfig &cfg)
    {
        __VIC_REGISTER_CONFIG_PARAM(cfg, int_param);
        register_param(cfg.str_param, "string_param");
        __VIC_REGISTER_CONFIG_PARAM(cfg, list_param);
    }
};

The final step is to create an instance of the parser and apply it to the file using the parse() function:

myconfig cfg;
myconfig_parser parser(cfg);
parser.parse("conf/my.cfg");

Now we have the cfg structure filled with values from the file.

For each complex parameter you have to define the corresponding config::parser and register it using register_complex_param().

5.3Implemetation details and additional features

The type of a configuration parameter is determined by its type in the code, and its value is validated during parsing. The library has built-in support for some types:

By including additional headers, you can also add support for:

And also lists with elements of the types mentioned above:

If you are using an unsupported type for your parameter, you can add such support yourself. All you need to do is specialize the config::value<> template for your type in the following form:

namespace __vic { namespace config {
/////////////////////////////////////////////////////////////////////////////
template<> struct value<T>
{
    static bool parse(const std::string &s, T &res)
    {
        // TODO: parse s
    }
};
/////////////////////////////////////////////////////////////////////////////
}}

Where T is your type. The string representation of the value from the file is passed to the parse() function. It must parse it, convert to a value of the type T, and assign the value to the reference specified as the second parameter of the function. If the function fails to convert the value, it must return false.

Example for type bool:

bool __vic::config::value<bool>::parse(const std::string &v, bool &res)
{
    if(v == "1" || __vic::ascii::equal_icase(v, "true")
                || __vic::ascii::equal_icase(v, "yes"))
        res = true;
    else if(v == "0" || __vic::ascii::equal_icase(v, "false")
                     || __vic::ascii::equal_icase(v, "no"))
        res = false;
    else
        return false; // error
    return true; // OK
}

In general, a value parser doesn't have to be a specialization of config::value. There are situations when 2 parameters have the same type, but different representation in the file, so they need to be parsed differently. And the library provides such capabilities.

For example, we want to specify size in the configuration file in megabytes and gigabytes, for which we are going to use the suffixes M and G:

max_log_file_size: 2M

Obviously, if we just specify the type as unsigned and register the parameter in the constructor of the file parser, the config::value<unsigned> parser will be used and it will fail when a letter is encountered. The solution is to create your own value parser, like this:

struct file_size_value
{
    static bool parse(const std::string &st, unsigned &res)
    {
        // parse the string and save the result
    }
};

Now we need to tell the file parser to use this value parser for the parameter. It can be done like this:

register_param<file_size_value>(cfg.max_log_file_size, "max_log_file_size");
// or
__VIC_REGISTER_CONFIG_PARAM_VP(cfg, max_log_file_size, file_size_value);

That's it. Now the parameter will be parsed correctly.

The template argument for the register_param<> function template can be either a class or a class template with one type-parameter. In the latter case, the configuration parameter type will be used as a template argument for the type-parameter.

If the new parameter type is a list of values, you also need to define a specialization for the config::list_traits [C++11] template. Here is an example of adding a new container for lists of values – let's allow std::set to be used.

template<class T>
struct list_traits<std::set<T>>
{
    using value_type = T;
    static void push(std::set<T> &c, T &&v) { c.insert(std::move(v)); }
};

Now all parameters of type std::set<T> will be automatically treated as lists.

5.4__vic/config/parser.h [C++11]

5.4.1config::parser [C++11]

class config::parser
{
public:
    class error : public std::exception {};
    class source_error : public error
    {
    public:
        unsigned line() const;
    };
    class duplicate_param : public std::exception {};

    parser(const parser & ) = delete;
    parser &operator=(const parser & ) = delete;

    void parse(const char *file_path);
    void parse(const std::string &file_path);
protected:
    parser();
    ~parser();

    template<class T>
    void register_param(T &v, const char *name);

    template<template<class > class ValueParser, class T>
    void register_param(T &v, const char *name);

    template<class ValueParser, class T>
    void register_param(T &v, const char *name);

    template<class Parser, class T>
    void register_complex_param(T &v, const char *name);

#define __VIC_REGISTER_CONFIG_PARAM(c,p) this->register_param((c).p, #p)
#define __VIC_REGISTER_CONFIG_PARAM_VP(c,p,vp) \
    this->register_param<vp>((c).p, #p)
#define __VIC_REGISTER_COMPLEX_CONFIG_PARAM(c,p,cp) \
    this->register_complex_param<cp>((c).p, #p)
};

Base class for parsers of config files and complex parameters.

Class members
class error

Base class for exceptions thrown by the parser.

class source_error

Exception thrown on invalid config file format.

class duplicate_param

Exception throw by the register_param() functions when attempting to register a parameter with the same name.

void parse(const char *file_path)
void parse(const std::string &file_path)

Parse the configuration file specified by the path.

template<class ValueParser, class T>
void register_param(T &v, const char *name)

Register a parameter with the specified name and referred by v. ValueParser will be used to parse its values.

template<template<class > class ValueParser, class T>
void register_param(T &v, const char *name)

Calls register_param< ValueParser<T> >(v, name).

template<class T>
void register_param(T &v, const char *name)

Calls register_param< config::value<T> >(v, name).

__VIC_REGISTER_CONFIG_PARAM(cfg, param)

Calls register_param(cfg.param, #param), which prevents duplication of the parameter name (when it is the same as the struct field name).

__VIC_REGISTER_CONFIG_PARAM_VP(cfg, papam, ValueParser)

Same as __VIC_REGISTER_CONFIG_PARAM() but additionally specifies ValueParser.

template<class Parser, class T>
void register_complex_param(T &v, const char *name)

Registers a complex parameter. Parser is derived from config::parser.

__VIC_REGISTER_COMPLEX_CONFIG_PARAM(cfg, param, Parser)

Same as __VIC_REGISTER_CONFIG_PARAM() but for register_complex_param().

5.5__vic/config/value.h [C++11]

5.5.1config::value [C++11]

template<class T>
class config::value
{
public:
    static bool parse(const std::string &s, T &res);
};

template<> class config::value<int>;
template<> class config::value<short>;
template<> class config::value<long>;
template<> class config::value<long long>;
template<> class config::value<signed char>;

template<> class config::value<unsigned>;
template<> class config::value<unsigned short>;
template<> class config::value<unsigned long>;
template<> class config::value<unsigned long long>;
template<> class config::value<unsigned char>;

template<> class config::value<bool>;

template<> class config::value<std::string>;
template<> class config::value<__vic::string_buffer>;

Value parser for values of T type, used by default (unless specified explicitly). Parses the input string s. If successful, stores the result in res and returns true. You can create specializations for your own types.

All user-defined value parsers must have the same interface and behaviour.

5.5.2config::list_traits [C++11]

template<class List>
struct config::list_traits
{
    using value_type = list-element-type;
    static void push(List &list, value_type &&v);
};

Specializing this template for some List type makes the library treat parameters of that type as a list.

Class members
typename value_type

Type of list elements.

static void push(List &list, value_type &&v)

Adds v to the list (usually at the end).

5.6Additional value parsers

5.6.1config::value<std::optional<T>> [C++17]

#include<__vic/config/values/std/optional.h>

template<class T>
class config::value<std::optional<T>>;

5.6.2config::value<__vic::ipv4_addr>

#include<mfisoft/config/values/ip_addr.h>

template<> class config::value<__vic::ipv4_addr>;

5.6.3config::complex_value<std::optional<T>> [C++17]

#include<__vic/config/values/std/optional.h>

template<class T, class Parser>
class config::complex_value<std::optional<T>, Parser, false>;

5.6.4config::list_traits<std::vector<T>>

#include<__vic/config/values/std/vector.h>

template<class T>
struct config::list_traits<std::vector<T>>;

5.6.5config::list_traits<std::list<T>>

#include<__vic/config/values/std/list.h>

template<class T>
struct config::list_traits<std::list<T>>;

5.6.6config::list_traits<std::forward_list<T>> [C++11]

#include<__vic/config/values/std/forward_list.h>

template<class T>
struct config::list_traits<std::forward_list<T>>;

5.6.7config::bytes_value_parser

#include<__vic/config/values/bytes.h>

template<class TUInt>
class config::bytes_value_parser;

Parser of parameters specifying the size in bytes. Allows values like "2K", which means 2 kilobytes. The following suffixes are supported: K – kilo, M – mega, G – giga. All the suffixes are powers of 2 (1K = 1024).

Precondition: TUInt – is an usigned integer type.

6Build and install

To build the library you need one of supported C++ compilers and GNU Make utility version 3.82 or higher available in your command line environment (shell).

Currently supported compilers are:

Go to src subdirectory and write:

$ gmake

The library file will be built for you.

C++17 is used by default but you can choose another language standard version using std option. E.g. to build the library in C++98 mode write:

$ gmake std=98

Available values include: 98, 11, 14, 17, 20 and 23.

Also you can choose the used compiler manually:

$ gmake compiler=gcc

To generate position-independent code (PIC) suitable for use in a shared library write:

$ gmake pic=1

Alternatively bmake utility can be used on FreeBSD 10+ instead of gmake:

$ make -f Makefile.freebsd

Finally, to use the library you just need to copy the library file and contents of include subdirectory to some place where compiler/linker can find it, e.g to /usr/local/include and /usr/local/lib.