__vic's C++ library (Windows) 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/windows/bitmap.h
2.46.1 windows::Bitmap
2.47 __vic/windows/critical_section.h
2.47.1 windows::CriticalSection
2.47.2 windows::CSGuard
2.48 __vic/windows/dc.h
2.48.1 windows::DC
2.48.2 windows::ClientDC
2.48.3 windows::PaintDC
2.49 __vic/windows/error.h
2.49.1 windows::error
2.50 __vic/windows/event.h
2.50.1 windows::Event
2.51 __vic/windows/find_file.h
2.51.1 windows::FindFile
2.52 __vic/windows/handle.h
2.52.1 windows::Handle
2.52.2 windows::WaitAbandoned
2.53 __vic/windows/shadow_dc.h
2.53.1 windows::ShadowDC
2.54 __vic/windows/throw_last_error.h
2.54.1 windows::throw_last_error()
2.54.2 windows::throw_wsa_error()
2.55 __vic/windows/wait_cursor.h
2.55.1 windows::WaitCursor
2.56 __vic/windows/wchar.h
2.56.1 windows::wstring
2.56.2 windows::utf8to16()
2.56.3 windows::utf16to8()
2.56.4 windows::utf16to8_append()
2.57 __vic/windows/window.h
2.57.1 windows::Window
2.57.2 windows::Window::Class
2.57.3 windows::Window::CreateParams
2.57.4 windows::MsgBox()
2.57.5 windows::MessageLoop()
2.57.6 windows::ProcessMessages()
 
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(const wchar_t *fname, in_t);
    bin_file(const wchar_t *fname, out_t);
    bin_file(const wchar_t *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);

    bool open_in(const wchar_t *fname);
    bool open_out(const wchar_t *fname);
    bool open_append(const wchar_t *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)
bin_file(const wchar_t *fname, in_t)
bin_file(const wchar_t *fname, out_t)
bin_file(const wchar_t *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)
bool open_in(const wchar_t *fname)
bool open_out(const wchar_t *fname)
bool open_append(const wchar_t *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 char-encoded paths are expected to be UTF-8!

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

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

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

bool dir_exists(const char *path);
bool dir_exists(const wchar_t *path);
bool dir_exists(const std::string &path);
bool dir_exists(const std::wstring &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);
void mkdir(const wchar_t *path);
void mkdir(const std::string &path);
void mkdir(const std::wstring &path);

bool mkdir_if_absent(const char *path);
bool mkdir_if_absent(const wchar_t *path);
bool mkdir_if_absent(const std::string &path);
bool mkdir_if_absent(const std::wstring &path);

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 wchar_t *path);
void rmdir(const std::string &path);
void rmdir(const std::wstring &path);

bool rmdir_if_exists(const char *path);
bool rmdir_if_exists(const wchar_t *path);
bool rmdir_if_exists(const std::string &path);
bool rmdir_if_exists(const std::wstring &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 wchar_t *path);
void remove_file(const std::string &path);
void remove_file(const std::wstring &path);

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

bool remove_file_nt(const char *path) noexcept;
bool remove_file_nt(const wchar_t *path) noexcept;
bool remove_file_nt(const std::string &path) noexcept;
bool remove_file_nt(const std::wstring &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 wchar_t *src_path, const wchar_t *dest_path, bool replace = false);
void copy_file(
    const std::string &src_path, const std::string &dest_path,
    bool replace = false);
void copy_file(
    const std::wstring &src_path, const std::wstring &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 wchar_t *src_path, const wchar_t *dest_path, bool replace = false);
bool copy_file_if_exists(
    const std::string &src_path, const std::string &dest_path,
    bool replace = false);
bool copy_file_if_exists(
    const std::wstring &src_path, const std::wstring &dest_path,
    bool replace = false);

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

bool copy_file_replace_if_exists(
    const char *src_path, const char *dest_path);
bool copy_file_replace_if_exists(
    const wchar_t *src_path, const wchar_t *dest_path);
bool copy_file_replace_if_exists(
    const std::string &src_path, const std::string &dest_path);
bool copy_file_replace_if_exists(
    const std::wstring &src_path, const std::wstring &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 wchar_t *src_path, const wchar_t *dest_path);
void move_file(const std::string &src_path, const std::string &dest_path);
void move_file(const std::wstring &src_path, const std::wstring &dest_path);

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

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

bool move_file_replace_if_exists(
    const char *src_path, const char *dest_path);
bool move_file_replace_if_exists(
    const wchar_t *src_path, const wchar_t *dest_path);
bool move_file_replace_if_exists(
    const std::string &src_path, const std::string &dest_path);
bool move_file_replace_if_exists(
    const std::wstring &src_path, const std::wstring &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 wchar_t *src_name, const wchar_t *dest_name);
void rename_file(const std::string &src_name, const std::string &dest_name);
void rename_file(const std::wstring &src_name, const std::wstring &dest_name);

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

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

bool rename_file_replace_if_exists(
    const char *src_name, const char *dest_name);
bool rename_file_replace_if_exists(
    const wchar_t *src_name, const wchar_t *dest_name);
bool rename_file_replace_if_exists(
    const std::string &src_name, const std::string &dest_name);
bool rename_file_replace_if_exists(
    const std::wstring &src_name, const std::wstring &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 wchar_t *path);
uintmax_t file_size(const std::string &path);
uintmax_t file_size(const std::wstring &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;

    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.

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/windows/bitmap.h

2.46.1windows::Bitmap

class windows::Bitmap
{
public:
    Bitmap() = default;
    explicit Bitmap(HBITMAP h);

    static Bitmap CreateCompatible(HDC hdc, int w, int h);

    bool DeleteNT() noexcept;
    void Delete();

    void ClearHandle();
    HBITMAP Handle() const;
    void Handle(HBITMAP h);
    operator HBITMAP() const;
};

C++ wrapper for Win32 API HBITMAP.

Class members
Bitmap() = default

Creates an uninitialized value.

explicit Bitmap(HBITMAP h)
Postcondition: Handle() == h
static Bitmap CreateCompatible(HDC hdc, int w, int h)

Calls ::CreateCompatibleBitmap().

bool DeleteNT() noexcept

Calls ::DeleteObject() and returns false on error.

void Delete()

Calls ::DeleteObject() and throws on error.

void ClearHandle()
Postcondition: !Handle()
HBITMAP Handle() const
operator HBITMAP() const

Returns the wrapped HBITMAP value.

void Handle(HBITMAP h)
Postcondition: Handle() == h

2.47__vic/windows/critical_section.h

2.47.1windows::CriticalSection

class windows::CriticalSection : private non_copyable
{
public:
    CriticalSection();
    explicit CriticalSection(DWORD dwSpinCount); // _WIN32_WINNT >= 0x0403
    ~CriticalSection();

    void Enter();
    bool TryEnter();
    void Leave() noexcept;

    ::CRITICAL_SECTION *handle();
    const ::CRITICAL_SECTION *handle() const;
};

A C++ wrapper for Win32 API CRITICAL_SECTION.

Class members
CriticalSection()

Calls ::InitializeCriticalSection().

explicit CriticalSection(DWORD dwSpinCount) [_WIN32_WINNT >= 0x0403]

Calls ::InitializeCriticalSectionAndSpinCount().

~CriticalSection()

Calls ::LeaveCriticalSection().

void Enter()

Calls ::EnterCriticalSection().

bool TryEnter()

Calls ::TryEnterCriticalSection() and returs the result.

void Leave() noexcept

Calls ::LeaveCriticalSection().

Note: Direct calls of Enter()/Leave() should be avoided, use windows::CSGuard objects instead.

2.47.2windows::CSGuard

class windows::CSGuard : private non_copyable
{
public:
    enum adopt_t { adopt };

    explicit CSGuard(::CRITICAL_SECTION &cs);
    CSGuard(::CRITICAL_SECTION &cs, adopt_t);

    explicit CSGuard(CriticalSection &cs);
    CSGuard(CriticalSection &cs, adopt_t);

    ~CSGuard();
};

A scoped lock guard. Works with ::CRITICAL_SECTION as well as with windows::CriticalSection objects.

Class members
explicit CSGuard(::CRITICAL_SECTION &cs)
explicit CSGuard(CriticalSection &cs)

Calls ::EnterCriticalSection(&cs).

CSGuard(::CRITICAL_SECTION &cs, adopt_t)
CSGuard(CriticalSection &cs, adopt_t)

Only saves the reference to cs without ::EnterCriticalSection() call.

~CSGuard()

Calls ::LeaveCriticalSection(&cs).

Example
// Typical usage
void reentrant_function()
{
    static __vic::windows::CriticalSection cs;
    __vic::windows::CSGuard guard(cs);
    // Critical section code until the end of the block
    ...
}

// Usage of the adopt-constructor
__vic::windows::CriticalSection cs;
if(cs.TryEnter()) // Try to enter the critical section
{
    // Success
    using __vic::windows::CSGuard;
    CSGuard guard(cs, CSGuard::adopt);
    // Critical section code until the end of the block
    ...
}
else
{
    // The critical section is busy
    ...
}

2.48__vic/windows/dc.h

C++ wrappers for Win32 GDI device context (DC).

2.48.1windows::DC

class windows::DC
{
public:
    DC() = default;
    explicit DC(HDC hdc);

    static DC CreateCompatible(HDC hdc);

    bool ReleaseNT(HWND hwnd) noexcept;
    void Release(HWND hwnd);
    bool DeleteNT() noexcept;
    void Delete();

    int GetHorzRes() const;
    int GetVertRes() const;
    HWND GetWindow() const;
    HGDIOBJ GetCurrentObject(UINT uObjType) const;
    HBRUSH GetCurrentBrush() const;
    HPEN GetCurrentPen() const;
    HFONT GetCurrentFont() const;
    HBITMAP GetCurrentBitmap() const;

    void Select(HGDIOBJ hObj); // not a region object
    void Select(HRGN hReg);

    COLORREF SetPixel(int x, int y, COLORREF c);
    bool MoveTo(int x, int y, POINT *p = 0);
    bool LineTo(int x, int y);
    bool PolyBezier(const POINT *lppt, DWORD cPoints);
    bool FillRect(const RECT &rect, HBRUSH hbr);

    bool BlitTo(HDC dcDest, int x, int y,
                            int w, int h, DWORD dwRop = SRCCOPY) const;
    bool BlitTo(HDC dcDest, const RECT &r, DWORD dwRop = SRCCOPY) const;

    void ClearHandle();
    HDC Handle() const;
    void Handle(HDC hdc);
    operator HDC() const;
};

General purpose HDC wrapper. Use windows::ClientDC instead of ::ReleaseDC(). Use windows::PaintDC instead of ::BeginPaint()/::EndPaint().

Note: For the most functions returning false on error no any addition information can be obtained using ::GetLastError().
Class members
DC() = default

Creates an uninitialized value.

explicit DC(HDC hdc)
Postcondition: Handle() == hdc
static DC CreateCompatible(HDC hdc)

Calls ::CreateCompatibleDC().

bool ReleaseNT(HWND hwnd) noexcept

Calls ::ReleaseDC() and returns false on error.

void Release(HWND hwnd)

Calls ::ReleaseDC() and throws on error.

bool DeleteNT() noexcept

Calls ::DeleteDC() and returns false on error.

void Delete()

Calls ::DeleteDC() and throws on error.

int GetHorzRes() const

Returns a horizontal resolution of the DC.

int GetVertRes() const

Returns a vertical resolution of the DC.

HWND GetWindow() const

Calls ::WindowFromDC() and returns its result.

HGDIOBJ GetCurrentObject(UINT uObjType) const

Calls ::GetCurrentObject() with the specified uObjType and returns its result.

HBRUSH GetCurrentBrush() const
HPEN GetCurrentPen() const
HFONT GetCurrentFont() const
HBITMAP GetCurrentBitmap() const

Calls ::GetCurrentObject() for the corresponding object type and returns its result.

void Select(HGDIOBJ hObj)

Calls ::SelectObject() for object that is not a region and throws on error.

void Select(HRGN hReg)

Calls ::SelectObject() for region object and throws on error.

COLORREF SetPixel(int x, int y, COLORREF c)

Calls ::SetPixel() and returns its result.

bool MoveTo(int x, int y, POINT *p = 0)

Calls ::MoveToEx() and returns false on error.

bool LineTo(int x, int y)

Calls ::LineTo() and returns false on error.

bool PolyBezier(const POINT *lppt, DWORD cPoints)

Calls ::PolyBezier() and returns false on error.

bool FillRect(const RECT &rect, HBRUSH hbr)

Calls ::PolyBezier() and returns false on error.

bool BlitTo(HDC dcDest, int x, int y, int w, int h, DWORD dwRop = SRCCOPY) const
bool BlitTo(HDC dcDest, const RECT &r, DWORD dwRop = SRCCOPY) const

Calls ::BitBlt() and returns false on error.

Note: ::GetLastError() can be used to get extended error information.
void ClearHandle()
Postcondition: !Handle()
HDC Handle() const
operator HDC() const

Returns the wrapped HDC value.

void Handle(HDC hdc)
Postcondition: Handle() == hdc

2.48.2windows::ClientDC

class windows::ClientDC : public windows::DC, private non_copyable
{
public:
    explicit ClientDC(HWND hwnd);
    ClientDC(HDC hdc, HWND hwnd);
    ~ClientDC();
};

RAII-wrapper. Calls ::ReleaseDC() in destructor.

Class members
explicit ClientDC(HWND hwnd)

Calls ::GetDC(hwnd). Throws on error.

ClientDC(HDC hdc, HWND hwnd)

Adopts hdc for the subsequent release in the destructor.

Precondition: hdc is a valid handler returned by ::GetDC(hwnd) call.
Postcondition: Handle() == hdc
~ClientDC()

Calls ::ReleaseDC().

2.48.3windows::PaintDC

class windows::PaintDC :
    public windows::DC, public PAINTSTRUCT, private non_copyable
{
public:
    explicit PaintDC(HWND hwnd);
    ~PaintDC();
};

Wrapper for PAINTSTRUCT and ::BeginPaint()/::EndPaint() calls.

Class members
explicit PaintDC(HWND hwnd)

Calls ::BeginPaint(hwnd, this). Throws on error.

~PaintDC()

Calls ::EndPaint().

2.49__vic/windows/error.h

Windows-specific error handling tools.

2.49.1windows::error

class windows::error : public std::exception
{
public:
    explicit error(DWORD err_code = ::GetLastError());
    explicit error(const char *prompt, DWORD err_code = ::GetLastError());

    const char *what() const noexcept;
    DWORD code() const;
};

Wrapper for Windows system error codes returned by Win32 API function GetLastError(). See libc_error for reference.

2.50__vic/windows/event.h

2.50.1windows::Event

class windows::Event : private non_copyable
{
public:
    explicit Event(bool bManualReset,
         bool bInitialSignaled = false, LPCWSTR lpName = nullptr);
    ~Event();

    void Set();
    void Reset();
    bool Wait(DWORD timeout = INFINITE) const;
    bool wait_for(std::chrono::milliseconds ms) const; // C++11

    HANDLE handle() const;
};

Wrapper for Win32 API event synchronization object.

Class members
explicit Event(bool bManualReset, bool bInitialSignaled = false, LPCWSTR lpName = nullptr)

Creates the object using ::CreateEvent(). Throws on error.

~Event()

Destroys the object.

void Set()

Calls ::SetEvent(). Throws on error.

void Reset()

Calls ::ResetEvent(). Throws on error.

bool Wait(DWORD timeout = INFINITE) const

Calls ::WaitForSingleObject(). Throws on error.

bool wait_for(std::chrono::milliseconds ms) const [C++11]

chrono-friendly wrapper for Wait().

HANDLE handle() const

Returns Win32 API handle.

2.51__vic/windows/find_file.h

2.51.1windows::FindFile

class windows::FindFile : public WIN32_FIND_DATA, private non_copyable
{
public:
    FindFile();
    ~FindFile();

    bool FindFirst(LPCTSTR filename);
    bool FindNext();

    bool IsOpen() const;
    void Close();
    bool CloseNT() noexcept;
};

Wrapper for Win32 API FindFirstFile()/FindNextFile() functions. Special entries . and .. are newer included in the resulting set.

Class members
FindFile()
Postcondition: IsOpen() == false
~FindFile()

Calls CloseNT() if IsOpen() == true.

bool FindFirst(LPCTSTR filename)

Calls FindFirstFile(). Returns false if no files found. Throws windows::error on other errors.

Precondition: IsOpen() == false
bool FindNext()

Calls FindNextFile(). Returns false if no more files available. Throws windows::error on other errors.

Precondition: IsOpen() == true
bool Close()

Closes the find handle. Throws windows::error on errors.

Precondition: IsOpen() == true
Postcondition: IsOpen() == false
bool CloseNT() noexcept

Same as Close() but returns false instead of throwing exceptions.

Precondition: IsOpen() == true
Postcondition: IsOpen() == false

2.52__vic/windows/handle.h

2.52.1windows::Handle

class windows::Handle
{
public:
    Handle() = default; // uninitialized
    constexpr Handle(HANDLE h);

    void Close();
    bool CloseNT() noexcept;
    static void Close(HANDLE h);

    bool Wait(DWORD timeout = INFINITE) const;

    bool IsInvalid() const;
    void SetInvalid();
    operator HANDLE() const;

    void swap(Handle &o) noexcept;
};

A C++ wrapper for Win32 API HANDLE.

Class members
Handle() = default

Creates an uninitialized value.

constexpr Handle(HANDLE h)

Implicit converter from HANDLE.

Postcondition: *this == h
operator HANDLE() const

Implicit converter to HANDLE.

bool IsInvalid() const

Returns true if the handle has value INVALID_HANDLE_VALUE.

void SetInvalid()

Assigns value INVALID_HANDLE_VALUE to the handle.

Postcondition: IsInvalid() == true
void Close()
static void Close(HANDLE h)

Calls ::CloseHandle(). Throws on error.

Precondition: The same as for ::CloseHandle().
bool CloseNT() noexcept

Calls ::CloseHandle() and returns true on success. On failure ::GetLastError() can be used to get the error description.

Precondition: The same as for ::CloseHandle().
bool Wait(DWORD timeout = INFINITE) const

Calls ::WaitForSingleObject() with the specified timeout. Returns false in case of WAIT_TIMEOUT. Throws on error. windows::WaitAbandoned is thrown in case of WAIT_ABANDONED.

void swap(Handle &o) noexcept

Swaps the value with o.

2.52.2windows::WaitAbandoned

struct windows::WaitAbandoned : public std::exception
{
    const char *what() const noexcept;
};

An exception class thrown by __vic::windows::Handle::Wait().

2.53__vic/windows/shadow_dc.h

2.53.1windows::ShadowDC

class windows::ShadowDC : public windows::DC, private non_copyable
{
public:
    ShadowDC();
    ~ShadowDC();

    void Create(HWND hwnd);
    void Create(HWND hwnd, int w, int h);
    void Destroy();
    bool IsCreated() const;
};

Virtual in-memory DC.

Class members
ShadowDC()
Postcondition: !IsCreated()
~ShadowDC()

Calls Destroy() is IsCreated() == true.

void Create(HWND hwnd, int w, int h)

Creates a shadow DC compatible with the specified window and having the specified dimensions. Throws on errors.

Precondition: !IsCreated()
Postcondition: IsCreated() == true
void Create(HWND hwnd)

Creates a shadow DC compatible with the specified window and having the same dimensions. Throws on errors.

Precondition: !IsCreated()
Postcondition: IsCreated() == true
void Destroy()

Destroys the DC.

Precondition: IsCreated() == true
Postcondition: !IsCreated()
bool IsCreated() const

Returns true if the object has an associated shadow DC.

2.54__vic/windows/throw_last_error.h

2.54.1windows::throw_last_error()

[[noreturn]] void throw_last_error(const char *prompt);
[[noreturn]] void throw_last_error(const char *prompt, DWORD code);

Throw an exception with the global GetLastError() value or the given code correspondingly.

Example
if(!CloseHandle(h)) __vic::windows::throw_last_error("CloseHandle");

2.54.2windows::throw_wsa_error()

[[noreturn]] void throw_wsa_error(const char *prompt);
[[noreturn]] void throw_wsa_error(const char *prompt, int code);

Same as windows::throw_last_error(), but for the error codes returned by WSAGetLastError().

2.55__vic/windows/wait_cursor.h

2.55.1windows::WaitCursor

class windows::WaitCursor : private non_copyable
{
public:
    explicit WaitCursor(HCURSOR h);
    ~WaitCursor();

    static HCURSOR GetDefault();
};

A RAII-wrapper. Temporarily replaces the mouse cursor with the one given in the constructor. The destructor restores the previous cursor.

Class members
explicit WaitCursor(HCURSOR h)

Replaces current cursor with h.

~WaitCursor()

Restores the cursor.

static HCURSOR GetDefault()

Returns the default wait-cursor handle (IDC_WAIT).

Example
using __vic::windows::WaitCursor;
static HCURSOR hWaitCursor = WaitCursor::GetDefault();
{
    WaitCursor _(hWaitCursor); // the cursor is replaced here by hWaitCursor
    some_long_processing();
    // here the destructor restores the cursor
}

2.56__vic/windows/wchar.h

UTF-8 <-> UTF-16 interconversion tools.

2.56.1windows::wstring

class windows::wstring : public std::wstring
{
public:
    wstring() = default;
    explicit wstring(size_type n) { reserve(n); }
    wstring(const wchar_t *st);
    wstring(std::wstring st);

    operator const wchar_t *() const { return c_str(); }
};

std::wstring with automatic conversion to const wchar_t *.

2.56.2windows::utf8to16()

windows::wstring windows::utf8to16(const char *s, size_t len);
#if __cpp_lib_string_view // C++17
windows::wstring windows::utf8to16(std::string_view s);
#else
windows::wstring windows::utf8to16(const char *s);
windows::wstring windows::utf8to16(const std::string &s);
#endif

UTF-8 to UTF-16 converter.

2.56.3windows::utf16to8()

std::string windows::utf16to8(const wchar_t *s, size_t len);
#if __cpp_lib_string_view // C++17
std::string windows::utf16to8(std::wstring_view s);
#else
std::string windows::utf16to8(const wchar_t *s);
std::string windows::utf16to8(const std::wstring &s);
#endif

UTF-16 to UTF-8 converter.

2.56.4windows::utf16to8_append()

std::string &windows::utf16to8_append(
                            const wchar_t *s, size_t len, std::string &res);
#if __cpp_lib_string_view // C++17
std::string &windows::utf16to8_append(std::wstring_view s, std::string &res);
#else
std::string &windows::utf16to8_append(const wchar_t *s, std::string &res);
std::string &windows::utf16to8_append(const std::wstring &s, std::string &res);
#endif

Same as windows::utf16to8() but appends the result to res. Returns a reference to res.

2.57__vic/windows/window.h

2.57.1windows::Window

class windows::Window
{
public:
    struct Class;
    struct CreateParams;

    Window() = default;
    explicit Window(HWND hwnd);

    static void Register(WNDCLASSEXW wcl);
    void Create(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWndName,
        DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent,
        HMENU hMenu, HINSTANCE hInstance, void *lpParam = nullptr);
    void Create(const CREATESTRUCTW &cs);
    bool Destroy() noexcept;

    LRESULT SendMessage(UINT msg, WPARAM w = 0, LPARAM l = 0);

    void Update();
    bool Show(int nWinMode);
    void Redraw(const RECT *rect = 0, HRGN hrgn = 0,
                        UINT flags = RDW_INVALIDATE | RDW_UPDATENOW);

    void GetRect(RECT &r) const;
    RECT GetRect() const;
    void GetClientRect(RECT &r) const
    RECT GetClientRect() const;

    void SetText(LPCWSTR st);
    void SetText(const char *st);
    int GetText(LPWSTR st, int nMax) const;

    void SetPos(HWND hWndAfter, int x, int y, int w, int h, UINT uFlags);
    void SetPos(int x, int y, int w, int h);
    void SetSize(int w, int h);
    void SetClientAreaSize(int w, int h);
    void MoveTo(int x, int y);
    void MoveToCenter();

    HWND Handle() const;
    void Handle(HWND hwnd);
    operator HWND() const;
};

Thin wrapper for Win32 API HWND.

Class members
Window() = default

Creates an uninitialized value.

explicit Window(HWND hwnd)
Postcondition: Handle() == hwnd
static void Register(WNDCLASSEXW wcl)

Calls ::RegisterClassExW(). Throws on error.

void Create(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWndName,
    DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent,
    HMENU hMenu, HINSTANCE hInstance, void *lpParam = nullptr)

Calls ::CreateWindowExW() and updates the wrapped HWND value. Throws on error.

void Create(const CREATESTRUCTW &cs)

Calls Create() with the values specified in cs. Throws on error.

bool Destroy() noexcept

Calls ::DestroyWindow(). Return true> on success.

LRESULT SendMessage(UINT msg, WPARAM w = 0, LPARAM l = 0)

Calls ::SendMessage() and returns the returned value.

void Update()

Calls ::UpdateWindow(). Throws on error.

bool Show(int nWinMode)

Calls ::ShowWindow() and returns the returned value.

void Redraw(const RECT *rect = 0, HRGN hrgn = 0,
        UINT flags = RDW_INVALIDATE | RDW_UPDATENOW)

Calls ::RedrawWindow(). Throws on error.

void GetRect(RECT &r) const
RECT GetRect() const

Calls ::GetWindowRect(). Throws on error.

void GetClientRect(RECT &r) const
RECT GetClientRect() const

Calls ::GetClientRect(). Throws on error.

void SetText(LPCWSTR st)

Calls ::SetWindowTextW(). Throws on error.

void SetText(const char *st)

Converts the specified string from UTF-8 to UTF-16 then calls SetText(). Throws on error.

int GetText(LPWSTR st, int nMax) const

Calls ::GetWindowTextW() and returns the returned value.

void SetPos(HWND hWndAfter, int x, int y, int w, int h, UINT uFlags)

Calls ::SetWindowPos(). Throws on error.

void SetPos(int x, int y, int w, int h)

Sets position and size of the window. Throws on error.

void SetSize(int w, int h)

Sets size of the window. Throws on error.

void SetClientAreaSize(int w, int h)

Sets client area size of the window. Throws on error.

void MoveTo(int x, int y)

Moves the window to the specified position. Throws on error.

void MoveToCenter()

Moves the window to the center of the screen. Throws on error.

HWND Handle() const
operator HWND() const

Returns the wrapped value.

void Handle(HWND hwnd)
Postcondition: Handle() == hwnd
Example
// Skeleton Win32 API application
#include<__vic/windows/window.h>
#include<windows.h>
#include<exception>

extern "C" LRESULT CALLBACK WindowFunc(
    HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
        case WM_DESTROY:
            PostQuitMessage(0); break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}
WPARAM skeleton_win32_app(int nWinMode)
{
    using __vic::windows::Window;
    static wchar_t szWinClassName[] = L"TestAppClass";

     Window wnd;
     HINSTANCE hInstance = ::GetModuleHandle(0);
     HICON hIcon = LoadIcon(NULL, IDI_APPLICATION);
     Window::Register(Window::Class(hInstance, szWinClassName, WindowFunc)
        .Icon(hIcon)
        .SmallIcon(hIcon)
        .Cursor(LoadCursor(0, IDC_ARROW))
        .Background((HBRUSH) GetStockObject(GRAY_BRUSH))
    );
    wnd.Create(Window::CreateParams(hInstance,
        szWinClassName, L"Skeleton Win32 application"));
    wnd.Show(nWinMode);
    wnd.Update();
    return __vic::windows::MessageLoop();
}
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR lpszArgs, int nWinMode)
{
    try
    {
        return skeleton_win32_app(nWinMode);
    }
    catch(const std::exception &ex)
    {
        __vic::windows::MsgBox(ex.what(),
            "Application error", MB_OK | MB_ICONERROR);
    }
    return 1;
}

2.57.2windows::Window::Class

struct windows::Window::Class : WNDCLASSEXW
{
    Class(HMODULE hInst, LPCWSTR name, WNDPROC wndProc)
    {
        cbSize = sizeof(WNDCLASSEXW);
        style = 0;
        lpfnWndProc = wndProc;
        cbClsExtra = cbWndExtra = 0;
        hInstance = hInst;
        hIcon = 0;
        hCursor = ::LoadCursorW(0, IDC_ARROW);
        hbrBackground = 0;
        lpszMenuName = 0;
        lpszClassName = name;
        hIconSm = 0;
    }
    Class &Style(UINT v) { style = v; return *this; }
    Class &ClsExtra(int v) { cbClsExtra = v; return *this; }
    Class &WndExtra(int v) { cbWndExtra = v; return *this; }
    Class &Instance(HINSTANCE v) { hInstance = v; return *this; }
    Class &Icon(HICON v) { hIcon = v; return *this; }
    Class &Cursor(HCURSOR v) { hCursor = v; return *this; }
    Class &Background(HBRUSH v) { hbrBackground = v; return *this; }
    Class &MenuName(LPCWSTR v) { lpszMenuName = v; return *this; }
    Class &SmallIcon(HICON v) { hIconSm = v; return *this; }
};

Wrapper for WNDCLASSEXW.

Example
using __vic::windows::Windows;

Window::Register(Window::Class(hInstance, WndClassName, wndProc)
    .Icon(hIcon)
    .SmallIcon(hIcon)
    .Cursor(::LoadCursor(nullptr, IDC_ARROW))
    .Background((HBRUSH) ::GetStockObject(LTGRAY_BRUSH))
);

2.57.3windows::Window::CreateParams

struct windows::Window::CreateParams : CREATESTRUCTW
{
    CreateParams(HMODULE hInst, LPCWSTR lpClsName, LPCWSTR lpWndName = nullptr)
    {
        lpCreateParams = 0;
        hInstance = hInst;
        hMenu = 0;
        hwndParent = HWND_DESKTOP;
        cy = cx = y = x = CW_USEDEFAULT;
        style = WS_OVERLAPPEDWINDOW;
        lpszName = lpWndName;
        lpszClass = lpClsName;
        dwExStyle = 0;
    }
    CreateParams &ExtraParam(void *v) { lpCreateParams = v; return *this; }
    CreateParams &Instance(HINSTANCE v) { hInstance = v; return *this; }
    CreateParams &Menu(HMENU v) { hMenu = v; return *this; }
    CreateParams &Parent(HWND v) { hwndParent = v; return *this; }
    CreateParams &Position(int X, int Y) { x = X; y = Y; return *this; }
    CreateParams &Dimension(int w, int h) { cx = w; cy = h; return *this; }
    CreateParams &Style(DWORD v) { style = v; return *this; }
    CreateParams &ExStyle(DWORD v) { dwExStyle = v; return *this; }
};

Wrapper for CREATESTRUCTW.

Example
using __vic::windows::Windows;

Windows wnd;
wnd.Create(Window::CreateParams(hInstance, className, title).Position(x, y));

2.57.4windows::MsgBox()

int windows::MsgBox(HWND hwnd,
    const wchar_t *msg, const wchar_t *title = L"", int t = MB_OK);
int windows::MsgBox(
    const wchar_t *msg, const wchar_t *title = L"", int t = MB_OK);
int windows::MsgBox(HWND hwnd,
    const char *msg, const char *title = "", int t = MB_OK);
int windows::MsgBox(
    const char *msg, const char *title = "", int t = MB_OK)

Calls ::MessageBoxW() and returns the returned value. hwnd parameter is NULL (HWND_DESKTOP) when not specified. char-functions convert strings from UTF-8 to UTF-16.

2.57.5windows::MessageLoop()

WPARAM windows::MessageLoop(HWND hwnd = nullptr);

Calls ::GetMessage() while it returs nonzero (until WM_QUIT is read). Then calls ::TranslateMessage() and ::DispatchMessage() with the message. Returns MSG::wParam.

2.57.6windows::ProcessMessages()

bool windows::ProcessMessages(HWND hwnd = nullptr);

Like windows::MessageLoop() but returns when message queue is empty. Returns true if can be called again and false if WM_QUIT message was read.

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

Currently supported compilers are:

Go to src subdirectory and write:

C:\> 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:

C:\> gmake std=98

Available values include: 98, 11, 14, 17, 20 and 23.

Also you can choose the used compiler manually:

C:\> gmake compiler=gcc

Alternatively NMAKE utility can be used with Visual C++ and clang-cl instead of gmake:

C:\> nmake -f Makefile.nmake compiler=msvc

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.