18 Utilities
18 Utilities
Programming
17. Utilities
Federico Busato
2024-11-05
Table of Contents
1 I/O Stream
Manipulator
ofstream/ifstream
1/87
Table of Contents
3 View
std::span
4 Math Libraries
2/87
Table of Contents
5 Random Number
Basic Concepts
C++ <random>
Seed
PRNG Period and Quality
Distribution
Recent Algorithms and Performance
Quasi-random
3/87
Table of Contents
6 Time Measuring
Wall-Clock Time
User Time
System Time
4/87
Table of Contents
7 Std Classes
std::pair
std::tuple
std::variant
std::optional
std::any
std::stacktrace
8 Filesystem Library
Query Methods
Modify Methods
5/87
I/O Stream
I/O Stream
buffered: the content of the buffer is not write to disk until some events occur
6/87
I/O Stream (manipulator) 1/3
• flush and endl force the program to synchronize with the terminal → very
slow operation!
7/87
I/O Stream (manipulator) 2/3
8/87
I/O Stream (manipulator) 3/3
<iomanip>
9/87
I/O Stream - std::cin
std::cin is an example of input stream. Data coming from a source is read by the program.
In this example cin is the standard input
#include <iostream>
int main() {
int a;
std::cout << "Please enter an integer value:" << endl;
std::cin >> a;
int b;
float c;
std::cout << "Please enter an integer value "
<< "followed by a float value:" << endl;
std::cin >> b >> c; // read an integer and store into "b",
} // then read a float value, and store
10/87
// into "c"
I/O Stream - ofstream/ifstream 1/3
• Get a pointer to the stream buffer object currently associated with the stream
my file.rdbuf()
can be used to redirect file stream
13/87
I/O Stream - Example 1
Open a file and print line by line: An alternative version with redirection:
14/87
Reading files line by line in C++ using ifstream
I/O Stream - Example 2
Another example:
#include <iostream>
#include <fstream>
example.txt:
int main() {
23 70 44\n std::ifstream fin("example.txt");
char c = fin.peek(); // c = '2'
\t57\t89
while (fin.good()) {
int var;
The input stream is independent from the fin >> var;
std::cout << var;
type of space (multiple space, tab, new-
} // print 2370445789
line \n, \r\n, etc.) fin.seekg(4);
c = fin.peek(); // c = '0'
fin.close();
} 15/87
I/O Stream -Check the End of a File
16/87
I/O Stream (checkRegularType)
18/87
Strings and std::print
std::string 1/4
More flexible and safer than raw char array but can be slower
#include <string>
int main() {
std::string a; // empty string
std::string b("first");
19/87
std::string - Capacity and Search 2/4
• find(string) returns the position of the first substring equal to the given character
sequence or npos if no substring is found
• rfind(string) returns the position of the last substring equal to the given character
sequence or npos if no substring is found
• find first of(char seq) returns the position of the first character equal to one of the
characters in the given character sequence or npos if no characters is found
• find last of(char seq) returns the position of the last character equal to one of the
characters in the given character sequence or npos if no characters is found
npos special value returned by string methods
20/87
std::string - Operations 3/4
• c str()
returns a pointer to the raw char sequence 21/87
std::string - Overloaded Operators 4/4
22/87
Conversion from/to Numeric Values
25/87
std::string view 1/3
#include <string>
#include <string_view>
26/87
std::string view 2/3
28/87
std::format 1/2
• Type-safe
• Support positional arguments
• Extensible (support user-defined types)
• Return a std::string
29/87
std::format - Example 2/2
Integer formatting
std::format("{}", 3); // "3"
std::format("{:b}", 3); // "101"
Alignment
std::format("{:>6}", 3.27); // " 3.27"
std::format("{:<6}", 3.27); // "3.27 "
Argument reordering
std::format("{1} - {0}", 1, 3); // "3 - 1"
30/87
std::print
31/87
std::print in C++23
View
std::span 1/3
template<
class T,
std::size_t Extent = std::dynamic_extent
> class span;
32/87
std::span 2/3
# include <span>
# include <array>
# include <vector>
33/87
std::span s5{v}; // dynamic extent
std::span 3/3
34/87
Math Libraries
<cmath> Math Library 1/2
<cmath>
• fabs(x) computes absolute value, |x |, C++11
• exp(x) returns e raised to the given power, e x
Math functions in C++11 can be applied directly to integral types without implicit/explicit
casting (return type: floating point).
en.cppreference.com/w/cpp/numeric/math
36/87
<limits> Numerical Limits
<limits> C++11
37/87
<numeric> Mathematical Constants
<numeric> C++20
The header provides numeric constants
• e Euler number e
• pi π
√
• phi Golden ratio 1+ 5
2
√
• sqrt2 2
38/87
Integer Division
value 1
• Rounded Division: +
div 2
unsigned round_div(unsigned value, unsigned div) {
return (value + div / 2) / div;
} // note: may overflow
41/87
see Lavarand
Basic Concepts
• The state of a PRNG describes the status of the generator (the values of its variables),
namely where the system is after a certain amount of transitions
• The seed is a value that initializes the starting state of a PRNG. The same seed always
produces the same sequence of results
• PRNGs produce uniformly distributed values. PRNGs can also generate values according
to a probability function (binomial, normal, etc.) 42/87
C++ <random> 1/2
Simplest example:
#include <iostream>
#include <random>
int main() {
std::random_device rd;
std::default_random_engine generator{rd{}};
std::uniform_int_distribution<int> distribution{0, 9};
It generates two random integer numbers in the range [0, 9] by using the default
random engine
44/87
Seed 1/4
46/87
How do I generate a random integer in C#?
Seed 3/4
#include <random>
std::random_device rnd_device;
std::default_random_engine generator{rnd_device()};
47/87
Seed 4/4
48/87
PRNG Period and Quality
PRNG Period
The period (or cycle length) of a PRNG is the length of the sequence of numbers that the
PRNG generates before repeating
PRNG Quality
(informal) If it is hard to distinguish a generator output from truly random sequences, we call it
a high quality generator. Otherwise, we call it low quality generator
49/87
Randomness Quality
The table shows after how many iterations the generator fails the statistical tests
52/87
Space and Performance
53/87
Distribution
54/87
Examples
55/87
Recent Algorithms and Performance
Recent algorithms:
• PCG, A Family of Better Random Number Generators
• Xoshiro / Xoroshiro generators and the PRNG shootout
• The Xorshift128+ random number generator fails BigCrush
Parallel algorithms:
• Squares: A Fast Counter-Based RNG
• Parallel Random Numbers: As Easy as 1, 2, 3 (Philox)
• OpenRNG: New Random Number Generator Library for best performance
when porting to Arm
If strong random number quality properties are not needed, it is possible to generate a
random permutation of integer values (with period of 232 ) in a very efficient way by
using hashing functions Hash Function Prospector 56/87
Performance Comparison
57/87
Random number generators for C++ performance tested
Quasi-random 1/2
• The concept of low-discrepancy is associated with the property that the successive
numbers are added in a position as away as possible from the other numbers that
is, avoiding clustering (grouping of numbers close to each other)
58/87
Quasi-random 2/2
59/87
Time Measuring
Time Measuring 1/2
Wall-Clock/Real time
It is the human perception of the passage of time from the start to the completion of
a task
User/CPU time
The amount of time spent by the CPU to compute in user code
System time
The amount of time spent by the CPU to compute system calls (including I/O calls)
executed into kernel code
60/87
Time Measuring 2/2
The Wall-clock time measured on a concurrent process platform may include the time
elapsed for other tasks
The User/CPU time of a multi-thread program is the sum of the execution time of all
threads
If the system workload (except the current program) is very low and the program uses
only one thread then
Wall-clock time = User time + System time
61/87
Time Measuring - Wall-Clock Time 1/3
Problems: Linux only (not portable), the time is not monotonic increasing (timezone), time
resolution is big
62/87
Time Measuring - Wall-Clock Time 2/3
std::chrono C++11
# include <chrono>
auto start_time = std::chrono::system_clock::now();
... // code
auto end_time = std::chrono::system_clock::now();
63/87
Time Measuring - Wall-Clock Time 3/3
64/87
Measuring clock precision
Time Measuring - User Time
std::clock , implemented over clock gettime on POSIX system and has 1ns
time resolution
# include <chrono>
65/87
Time Measuring - User/System Time
# include <sys/times.h>
66/87
Std Classes
std::pair 1/2
<utility>
std::pair class couples together a pair of values, which may be of different types
Construct a std::pair
• std::pair<T1, T2> pair(value1, value2)
• std::pair<T1, T2> pair = {value1, value2}
• auto pair = std::make pair(value1, value2)
Data members:
• first access first field
• second access second field
Methods:
• comparison ==, <, >, ≥, ≤
• swap std::swap 67/87
std::pair 2/2
# include <utility>
swap(pair1, pair2);
cout << pair2.first; // print "zzz"
cout << pair2.second; // print 4
68/87
std::tuple 1/3
<tuple>
std::tuple is a fixed-size collection of heterogeneous values. It is a generalization of
std::pair . It allows any number of values
Construct a std::tuple (of size 3)
• std::tuple<T1, T2, T3> tuple(value1, value2, value3)
• std::tuple<T1, T2, T3> tuple = {value1, value2, value3}
• auto tuple = std::make tuple(value1, value2, value3)
Data members:
std:get<I>(tuple) returns the i-th value of the tuple
Methods:
• comparison ==, <, >, ≥, ≤
• swap std::swap 69/87
std::tuple 2/3
• std::ignore
an object of unspecified type such that any value can be assigned to it with no
effect 70/87
std::tuple 3/3
# include <tuple>
std::tuple<int, float, char> f() { return {7, 0.1f, 'a'}; }
<variant> C++17
std::variant represents a type-safe union as the corresponding objects know
which type is currently being held
# include <variant>
Another useful method is index() which returns the position of the type currently
held by the variant
# include <variant>
std::get<bool>(v) = true
cout << v.index(); // return 2
73/87
std::variant + Visitor 3/3
It is also possible to query the index at run-time depending on the type currently being
held by providing a visitor
# include <variant>
struct Visitor {
void operator()(int& value) { value *= 2; }
std::visit(v, Visitor{});
<optional> C++17
std::optional provides facilities to represent potential “no value” states
As an example, it can be used for representing the state when an element is not found
in a set
# include <optional>
75/87
std::optional 2/2
# include <optional>
76/87
std::any
<any> C++17
std::any holds arbitrary values and provides type-safety
# include <any>
var.reset();
cout << var.has_value(); // print 'false'
77/87
std::stacktrace 1/2
C++23 introduces std::stacktrace library to get the current function call stack,
namely the sequence of calls from the main() entry point
# include <print>
# include <stacktrace> // the program must be linked with the library
// -lstdc++_libbacktrace
// (-lstdc++exp with gcc-14 trunk)
void g() {
auto call_stack = std::stacktrace::current();
for (const auto& entry : call_stack)
std::print("{}\n", entry);
}
The library also provides additional functions for entry to allow fine-grained control
of the output description() , source file() , source line()
C++17 introduces abstractions and facilities for performing operations on file systems
and their components, such as paths, files, and directories
80/87
Basic concepts
• file name: a string of characters that names a file. Names . (dot) and ..
(dot-dot) have special meaning at library level
82/87
path Methods
namespace fs = std::filesystem;
85/87
Filesystem Methods - Modify
• Copy files
copy file(src path, src path, [fs::copy options::recursive])
namespace fs = std::filesystem;
fs::path p1 = "/usr/tmp/my_file.txt";
fs::create_directory("/my_dir/");
fs::copy(p1.parent_path(), "/my_dir/", fs::copy_options::recursive);
fs::copy_file(p1, "/my_dir/my_file2.txt");
fs::remove(p1);
87/87
fs::remove_all(p1.parent_path());