listings-Chap25-README-onepage.md
Listings of Chap25.docx
This is the list of listings on one page. You can also view a linked summary.
Listing 25.1: Something is done with the input vector—but what?
Book listing lst-0001-book.cpp:
// https://godbolt.org/z/jcWvThn3a
std::vector v{0,1,3,5,7,9,2,4,6,8};
bool flag = true;
for(size_t i=1; (i < v.size()) && flag; ++i) {
flag = false;
for(size_t j=0; (j < v.size()-i); ++j) {
if(v[j+1] < v[j]) {
std::swap(v[j+1], v[j]);
flag = true;
}
}
}
for(int i:v) std::cout << i << ' ';
Godbolt Listing lst-0001-godb.cpp, https://godbolt.org/z/jcWvThn3a:
//#(compile) c++; compiler:g141; options:-O1 -std=c++23 -Wall -Wextra -pedantic; libs:-
// https://godbolt.org/z/jcWvThn3a
std::vector v{0,1,3,5,7,9,2,4,6,8};
bool flag = true;
for(size_t i=1; (i < v.size()) && flag; ++i) {
flag = false;
for(size_t j=0; (j < v.size()-i); ++j) {
if(v[j+1] < v[j]) {
std::swap(v[j+1], v[j]);
flag = true;
}
}
}
for(int i:v) std::cout << i << ' ';
Listing 25.2: This input vector will be sorted!
Book listing lst-0002-book.cpp:
// https://godbolt.org/z/EjT7nPPv7
std::vector v{0,1,3,5,7,9,2,4,6,8};
std::sort(v.begin(), v.end());
for(int i:v) std::cout << i << ' ';
std::cout << '\n';
// or with a range:
std::ranges::sort(v);
for(int i:v) std::cout << i << ' ';
std::cout << '\n';
Godbolt Listing lst-0002-godb.cpp, https://godbolt.org/z/EjT7nPPv7:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/EjT7nPPv7
std::vector v{0,1,3,5,7,9,2,4,6,8};
std::sort(v.begin(), v.end());
for(int i:v) std::cout << i << ' ';
std::cout << '\n';
// or with a range:
std::ranges::sort(v);
for(int i:v) std::cout << i << ' ';
std::cout << '\n';
Listing 25.3: Composing functions
Book listing lst-0003-book.cpp:
// https://godbolt.org/z/9xrP8Ehvd
#include <algorithm>
#include <vector>
#include <iostream>
void sort_uniq(std::vector<int> &data) {
std::ranges::sort(data); // sorting
auto to_delete = std::ranges::unique(data); // move to the back
data.erase(to_delete.begin(), to_delete.end()); // actually delete
}
int main() {
std::vector ns{1,5,2,3,9,2,2,2,2,1,5,2,2,3,1,1,2,2,1};
sort_uniq(ns);
std::ranges::for_each(ns, [](auto x) {
std::cout << x << ' '; });
std::cout << '\n'; // Output: 1 2 3 5 9
}
Godbolt Listing lst-0003-godb.cpp, https://godbolt.org/z/9xrP8Ehvd:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9xrP8Ehvd
#include <algorithm>
#include <vector>
#include <iostream>
void sort_uniq(std::vector<int> &data) {
std::ranges::sort(data); // sorting
auto to_delete = std::ranges::unique(data); // move to the back
data.erase(to_delete.begin(), to_delete.end()); // actually delete
}
int main() {
std::vector ns{1,5,2,3,9,2,2,2,2,1,5,2,2,3,1,1,2,2,1};
sort_uniq(ns);
std::ranges::for_each(ns, [](auto x) {
std::cout << x << ' '; });
std::cout << '\n'; // Output: 1 2 3 5 9
}
Listing 25.4: Algorithms run in parallel.
Book listing lst-0004-book.cpp:
// https://godbolt.org/z/Koxoha5bx
#include <algorithm> // find
#include <numeric> // reduce, accumulate
#include <execution> // std::execution
#include <iostream>
#include <chrono> // time measurement
using namespace std::chrono;
long long millisSince(steady_clock::time_point start) {
return duration_cast<milliseconds>(steady_clock::now()-start).count();
}
template <typename FUNC> void timeit(const char* title, FUNC func) {
auto start = steady_clock::now();
auto ret = func(); // execute
std::cout << title << ": " << millisSince(start) << " ms" << std::endl;
}
int main() {
using namespace std::execution; // seq, par, par_unseq
using std::reduce; using std::accumulate; using std::find;
std::vector<double> v(600'000'000, 0.0); // 600 million elements
for(auto&x:v) x = ::rand(); // fill with random values
timeit("warm-up ", [&v] {
return reduce(seq, v.begin(), v.end(), 0.0);
});
timeit("accumulate ", [&v] {
return accumulate(v.begin(), v.end(), 0.0);
});
timeit("reduce, seq ", [&v] {
return reduce(seq, v.begin(), v.end(), 0.0);
});
timeit("reduce, par ", [&v] {
return reduce(par, v.begin(), v.end(), 0.0);
});
timeit("reduce, par_unseq", [&v] {
return reduce(par_unseq, v.begin(), v.end(), 0.0);
});
timeit("find, seq ", [&v] {
return find(seq, v.begin(), v.end(), 1.1) == v.end() ? 0.0 : 1.0;
});
timeit("find, par ", [&v] {
return find(par, v.begin(), v.end(), 1.1) == v.end() ? 0.0 : 1.0;
});
return 0;
}
Godbolt Listing lst-0004-godb.cpp, https://godbolt.org/z/Koxoha5bx:
//#(compile) c++; compiler:g112; options:-O3 -std=c++23; libs:tbb@20214
// https://godbolt.org/z/Koxoha5bx
#include <algorithm> // find
#include <numeric> // reduce, accumulate
#include <execution> // std::execution
#include <iostream>
#include <chrono> // time measurement
using namespace std::chrono;
long long millisSince(steady_clock::time_point start) {
return duration_cast<milliseconds>(steady_clock::now()-start).count();
}
template <typename FUNC> void timeit(const char* title, FUNC func) {
auto start = steady_clock::now();
auto ret = func(); // execute
std::cout << title << ": " << millisSince(start) << " ms" << std::endl;
}
int main() {
using namespace std::execution; // seq, par, par_unseq
using std::reduce; using std::accumulate; using std::find;
std::vector<double> v(600'000'000, 0.0); // 600 million elements
for(auto&x:v) x = ::rand(); // fill with random values
timeit("warm-up ", [&v] {
return reduce(seq, v.begin(), v.end(), 0.0);
});
timeit("accumulate ", [&v] {
return accumulate(v.begin(), v.end(), 0.0);
});
timeit("reduce, seq ", [&v] {
return reduce(seq, v.begin(), v.end(), 0.0);
});
timeit("reduce, par ", [&v] {
return reduce(par, v.begin(), v.end(), 0.0);
});
timeit("reduce, par_unseq", [&v] {
return reduce(par_unseq, v.begin(), v.end(), 0.0);
});
timeit("find, seq ", [&v] {
return find(seq, v.begin(), v.end(), 1.1) == v.end() ? 0.0 : 1.0;
});
timeit("find, par ", [&v] {
return find(par, v.begin(), v.end(), 1.1) == v.end() ? 0.0 : 1.0;
});
return 0;
}
Listing 25.5: View types and their adapters.
Book listing lst-0005-book.cpp:
// https://godbolt.org/z/rrq1v5qPs
std::list lst{1, 2, 3, 4, 5, 6, 7, 8, 9};
auto take5 = rs::take_view{lst, 5}; // View via type
auto take6 = lst | vs::take(6); // View via adapter
Godbolt Listing lst-0005-godb.cpp, https://godbolt.org/z/rrq1v5qPs:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/rrq1v5qPs
std::list lst{1, 2, 3, 4, 5, 6, 7, 8, 9};
auto take5 = rs::take_view{lst, 5}; // View via type
auto take6 = lst | vs::take(6); // View via adapter
Listing 25.6: Especially the C++23 views can be well combined.
Book listing lst-0006-book.cpp:
// https://godbolt.org/z/hYTv6f9eo
#include <ranges>
#include <array>
#include <string>
#include <iostream>
#include <string_view>
using namespace std::literals; using namespace std;
// Function for outputting all sorts of things
template <typename OBJ>
void print(OBJ&& obj, int level = 0) {
if constexpr(std::ranges::input_range<OBJ>) { // range
cout << '[';
for (const auto& elem : obj) print(elem, level+1);
cout << ']';
} else if constexpr(requires (OBJ tpl){ std::get<0>(tpl);}) { // tuple/pair
cout << "(";
print(get<0>(obj), level+1); print(get<1>(obj), level+1);
cout << ")";
} else cout << obj; // element
if (level == 0) cout << '\n';
}
int main() {
using namespace std::views; // exceptionally for brevity
auto const nums = array{0, 0, 1, 1, 2, 2};
auto const animals = array{"cat"s, "dog"s};
print(iota(0, 5) | chunk(2)); // Output: [[01][23][4]]
print(nums | chunk_by(equal_to{})); // Output: [[00][11][22]]
print(iota(0, 5) | slide(3)); // Output: [[012][123][234]]
print(iota(0, 10) | stride(3)); // Output: [0369]
print(repeat(8) |take(5)); // Output: [88888]
print(zip_transform(plus{}, nums, nums)); // Output: [002244]
print(zip(iota(0, 3), iota(1, 4))); // Output: [(01)(12)(23)]
print(iota(0, 4) | adjacent<2>); // Output: [(01)(12)(23)]
print(iota(0, 4) | pairwise); // Output: [(01)(12)(23)]
print(iota(0, 4) | adjacent_transform<2>(plus{})); // Output: [135]
print(iota(0, 4) | pairwise_transform(plus{})); // Output: [135]
print(animals | join_with( '+' )); // Output: [cat+dog]
print(cartesian_product(iota(0, 2), "AZ"s)); // Output: [(0A)(0Z)(1A)(1Z)]
print(enumerate("APL"s)); // Output: [(0A)(1P)(2L)]
return 0;
}
Godbolt Listing lst-0006-godb.cpp, https://godbolt.org/z/hYTv6f9eo:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/hYTv6f9eo
#include <ranges>
#include <array>
#include <string>
#include <iostream>
#include <string_view>
using namespace std::literals; using namespace std;
// Function for outputting all sorts of things
template <typename OBJ>
void print(OBJ&& obj, int level = 0) {
if constexpr(std::ranges::input_range<OBJ>) { // range
cout << '[';
for (const auto& elem : obj) print(elem, level+1);
cout << ']';
} else if constexpr(requires (OBJ tpl){ std::get<0>(tpl);}) { // tuple/pair
cout << "(";
print(get<0>(obj), level+1); print(get<1>(obj), level+1);
cout << ")";
} else cout << obj; // element
if (level == 0) cout << '\n';
}
int main() {
using namespace std::views; // exceptionally for brevity
auto const nums = array{0, 0, 1, 1, 2, 2};
auto const animals = array{"cat"s, "dog"s};
print(iota(0, 5) | chunk(2)); // Output: [[01][23][4]]
print(nums | chunk_by(equal_to{})); // Output: [[00][11][22]]
print(iota(0, 5) | slide(3)); // Output: [[012][123][234]]
print(iota(0, 10) | stride(3)); // Output: [0369]
print(repeat(8) |take(5)); // Output: [88888]
print(zip_transform(plus{}, nums, nums)); // Output: [002244]
print(zip(iota(0, 3), iota(1, 4))); // Output: [(01)(12)(23)]
print(iota(0, 4) | adjacent<2>); // Output: [(01)(12)(23)]
print(iota(0, 4) | pairwise); // Output: [(01)(12)(23)]
print(iota(0, 4) | adjacent_transform<2>(plus{})); // Output: [135]
print(iota(0, 4) | pairwise_transform(plus{})); // Output: [135]
print(animals | join_with( '+' )); // Output: [cat+dog]
print(cartesian_product(iota(0, 2), "AZ"s)); // Output: [(0A)(0Z)(1A)(1Z)]
print(enumerate("APL"s)); // Output: [(0A)(1P)(2L)]
return 0;
}
Listing 25.7: Functions must receive a range parameter as a universal reference.
Book listing lst-0009-book.cpp:
// https://godbolt.org/z/3EbsPczh1
void print(const auto& range) { // (ERR) critical: constant reference
for (auto const& e : range) { cout << e; } cout << '\n';
}
vector vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
list lst{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
print(vec); // works on direct containers
print(lst); // works on direct containers
print(vec | vs::take(3)); // take with vector works
print(lst | vs::take(3)); // take with list works
print(vec | vs::drop(5)); // drop with vector works
print(lst | vs::drop(5)); // (ERR) drop with list does not work!
Godbolt Listing lst-0009-godb.cpp, https://godbolt.org/z/3EbsPczh1:
//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/3EbsPczh1
void print(const auto& range) { // (ERR) critical: constant reference
for (auto const& e : range) { cout << e; } cout << '\n';
}
vector vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
list lst{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
print(vec); // works on direct containers
print(lst); // works on direct containers
print(vec | vs::take(3)); // take with vector works
print(lst | vs::take(3)); // take with list works
print(vec | vs::drop(5)); // drop with vector works
print(lst | vs::drop(5)); // (ERR) drop with list does not work!
Listing 25.8: A function only for views and not for containers.
Book listing lst-0010-book.cpp:
// https://godbolt.org/z/s1GjfWxv6
void print(ranges::view auto range) { // Value parameter, restricted to Views
for (auto const& e : range) { cout << e; } cout << '\n';
}
vector vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
list lst{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
print(vec); // (ERR) Forbidden for containers, very good!
print(vs::all(vec)); // Convert container to view
print(vs::all(lst)); // Convert container to view
print(vec | vs::take(3)); // take with vector works
print(lst | vs::take(3)); // take with list works
print(vec | vs::drop(5)); // drop with vector works
print(lst | vs::drop(5)); // as a value parameter, drop with list works
Godbolt Listing lst-0010-godb.cpp, https://godbolt.org/z/s1GjfWxv6:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/s1GjfWxv6
void print(ranges::view auto range) { // Value parameter, restricted to Views
for (auto const& e : range) { cout << e; } cout << '\n';
}
vector vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
list lst{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
print(vec); // (ERR) Forbidden for containers, very good!
print(vs::all(vec)); // Convert container to view
print(vs::all(lst)); // Convert container to view
print(vec | vs::take(3)); // take with vector works
print(lst | vs::take(3)); // take with list works
print(vec | vs::drop(5)); // drop with vector works
print(lst | vs::drop(5)); // as a value parameter, drop with list works
Listing 25.9: Searching with a predicate.
Book listing lst-0011-book.cpp:
// https://godbolt.org/z/W9n7sTovz
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>
#include <string_view>
#include <ranges>
using std::vector; using std::string; using std::string_view;
using namespace std::literals; using std::find_if;
vector<string> demo_split(string_view s) {
vector<string> result{};
auto it = s.begin();
while(it != s.end()) {
// until normal character:
it = find_if(it, s.end(), [](char c) { return c!=' '; });
// until whitespace:
auto jt = find_if(it, s.end(), [](char c) { return c==' '; });
if(it!=s.end())
result.push_back(string(it, jt)); // Copy to result
it = jt;
}
return result;
}
int main() {
auto text = "The text is short"sv;
auto res = demo_split(text);
std::ranges::for_each(res, [](const string &e) {
std::cout << "[" << e << "] "; });
std::cout << '\n'; // Output: [The] [text] [is] [short]
// or directly with views::split:
for(auto word : text | std::views::split(" "sv)) {
std::cout << "[";
for(auto c : word) std::cout << c;
std::cout << "] ";
} // Output: [The] [text] [is] [short]
}
Godbolt Listing lst-0011-godb.cpp, https://godbolt.org/z/W9n7sTovz:
//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/W9n7sTovz
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>
#include <string_view>
#include <ranges>
using std::vector; using std::string; using std::string_view;
using namespace std::literals; using std::find_if;
vector<string> demo_split(string_view s) {
vector<string> result{};
auto it = s.begin();
while(it != s.end()) {
// until normal character:
it = find_if(it, s.end(), [](char c) { return c!=' '; });
// until whitespace:
auto jt = find_if(it, s.end(), [](char c) { return c==' '; });
if(it!=s.end())
result.push_back(string(it, jt)); // Copy to result
it = jt;
}
return result;
}
int main() {
auto text = "The text is short"sv;
auto res = demo_split(text);
std::ranges::for_each(res, [](const string &e) {
std::cout << "[" << e << "] "; });
std::cout << '\n'; // Output: [The] [text] [is] [short]
// or directly with views::split:
for(auto word : text | std::views::split(" "sv)) {
std::cout << "[";
for(auto c : word) std::cout << c;
std::cout << "] ";
} // Output: [The] [text] [is] [short]
}
Listing 25.10: Recognizing a palindrome with a single line of code.
Book listing lst-0012-book.cpp:
// https://godbolt.org/z/MKxnGdrbr
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>
#include <string_view>
using std::string_view; using namespace std::literals; using std::cout;
auto isPalindrome(string_view sv) {
return std::ranges::equal(sv.begin(), sv.end(), sv.rbegin(), sv.rend()); };
int main() {
for(auto s : {"madam"sv, "aibohphobia"sv, "abrakadabra"sv }) {
cout << s << " is " << (isPalindrome(s)?"a":"not a") << " palindrome\n";
}
}
Godbolt Listing lst-0012-godb.cpp, https://godbolt.org/z/MKxnGdrbr:
//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/MKxnGdrbr
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>
#include <string_view>
using std::string_view; using namespace std::literals; using std::cout;
auto isPalindrome(string_view sv) {
return std::ranges::equal(sv.begin(), sv.end(), sv.rbegin(), sv.rend()); };
int main() {
for(auto s : {"madam"sv, "aibohphobia"sv, "abrakadabra"sv }) {
cout << s << " is " << (isPalindrome(s)?"a":"not a") << " palindrome\n";
}
}
Listing 25.11: Even “read-only” algorithms like “for_each” can modify elements.
Book listing lst-0013-book.cpp:
// https://godbolt.org/z/jz1Gqo7d9
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> c{ 1,2,3,4 };
std::ranges::for_each(c, [](auto &n) { n*=n; }); // (ERR) modifying
std::cout << c[3] << '\n'; // Output: 16
}
Godbolt Listing lst-0013-godb.cpp, https://godbolt.org/z/jz1Gqo7d9:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jz1Gqo7d9
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> c{ 1,2,3,4 };
std::ranges::for_each(c, [](auto &n) { n*=n; }); // (ERR) modifying
std::cout << c[3] << '\n'; // Output: 16
}
Listing 25.12: “transform” can juggle with different types.
Book listing lst-0015-book.cpp:
// https://godbolt.org/z/7r4b8jdGr
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>
using std::to_string; using std::string; using std::vector;
struct Squares {
mutable int n = 1;
int operator()() const { return n*n++; }
};
int main() {
vector<int> sq(10);
std::ranges::generate(sq, Squares{});
std::ranges::for_each(sq, [](auto n) {
std::cout << n << " "; });
std::cout << '\n'; // Output: 1 4 9 16 25 36 49 64 81 100
string a = "NCC-";
vector<int> b {1,7,0,1};
vector<string> c(4);
auto f = [](char c, int i) -> string { return c+to_string(i); };
std::ranges::transform(
a, // Input 1
b, // Input 2
c.begin(), // Output
f); // string f(char,int)
std::ranges::for_each(c, [](auto s) {
std::cout << s << " "; });
std::cout << '\n'; // Output: N1 C7 C0 -1
}
Godbolt Listing lst-0015-godb.cpp, https://godbolt.org/z/7r4b8jdGr:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/7r4b8jdGr
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>
using std::to_string; using std::string; using std::vector;
struct Squares {
mutable int n = 1;
int operator()() const { return n*n++; }
};
int main() {
vector<int> sq(10);
std::ranges::generate(sq, Squares{});
std::ranges::for_each(sq, [](auto n) {
std::cout << n << " "; });
std::cout << '\n'; // Output: 1 4 9 16 25 36 49 64 81 100
string a = "NCC-";
vector<int> b {1,7,0,1};
vector<string> c(4);
auto f = [](char c, int i) -> string { return c+to_string(i); };
std::ranges::transform(
a, // Input 1
b, // Input 2
c.begin(), // Output
f); // string f(char,int)
std::ranges::for_each(c, [](auto s) {
std::cout << s << " "; });
std::cout << '\n'; // Output: N1 C7 C0 -1
}
Listing 25.13: Transforming with range adapters.
Book listing lst-0016-book.cpp:
// https://godbolt.org/z/j9ozax8qE
#include <ranges> // zip_transform
// …
auto res = std::views::zip_transform(f, a, b); // Range adapter
for(auto s: res) { std::cout << s << " "; };
std::cout << '\n'; // Output: N1 C7 C0 -1
Godbolt Listing lst-0016-godb.cpp, https://godbolt.org/z/j9ozax8qE:
//#(compile) c++; compiler:g132; options:"-std=c++23"; libs:-
// https://godbolt.org/z/j9ozax8qE
#include <ranges> // zip_transform
// …
auto res = std::views::zip_transform(f, a, b); // Range adapter
for(auto s: res) { std::cout << s << " "; };
std::cout << '\n'; // Output: N1 C7 C0 -1
GodboltId:s53qx664K
Book listing lst-0017-book.cpp:
// https://godbolt.org/z/s53qx664K
#include <iostream>
#include <random> // default_random_engine
#include <string>
#include <iterator> // back_inserter
#include <algorithm> // sample
int main() {
std::default_random_engine random{};
const std::string in = "abcdefgh";
for(auto idx : {0,1,2,3}) {
std::string out;
std::ranges::sample(in, std::back_inserter(out), 5, random);
std::cout << out << '\n';
}
}
Godbolt Listing lst-0017-godb.cpp, https://godbolt.org/z/s53qx664K:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/s53qx664K
#include <iostream>
#include <random> // default_random_engine
#include <string>
#include <iterator> // back_inserter
#include <algorithm> // sample
int main() {
std::default_random_engine random{};
const std::string in = "abcdefgh";
for(auto idx : {0,1,2,3}) {
std::string out;
std::ranges::sample(in, std::back_inserter(out), 5, random);
std::cout << out << '\n';
}
}
Listing 25.14: Functionality of the set algorithms.
Book listing lst-0018-book.cpp:
// https://godbolt.org/z/1esod6hrT
#include <algorithm>
#include <iostream>
#include <list>
#include <string>
#include <iterator> // ostream_iterator
#include <cctype> // toupper
using std::toupper;
int main() {
std::list a{ 1,2,4,4,4,7,7,9 };
std::list b{ 2,2,3,4,4,8 };
using Os = std::ostream_iterator<int>; // Type of output iterator
Os os{std::cout, " "}; // Stream output iterator for int
auto run = [&a,&b,&os](auto algo) { // use a, b, and os
algo(a.begin(), a.end(), b.begin(), b.end(), os); // Call algorithm
std::cout << '\n';
};
// Results of the algorithms
using It = decltype(a.begin()); // Type of input iterators
run(std::merge<It,It,Os>); // Output: 1 2 2 2 3 4 4 4 4 4 7 7 8 9
run(std::set_union<It,It,Os>); // Output: 1 2 2 3 4 4 4 7 7 8 9
run(std::set_intersection<It,It,Os>); // Output: 2 4 4
run(std::set_difference<It,It,Os>); // Output: 1 4 7 7 9
run(std::set_symmetric_difference<It,It,Os>); // Output: 1 2 3 4 7 7 8 9
// With letters it becomes even clearer
std::string x = "abdddggi";
std::string y = "BBCDDH";
using Us = std::ostream_iterator<char>; // Type of output iterator
Us us{std::cout, ""}; // Stream output iterator for char
auto compare = [](auto c, auto d) { return toupper(c) < toupper(d); };
auto run2 = [&x,&y,&us,&compare](auto algo) { // use x, y, and us
algo(x.begin(), x.end(), y.begin(), y.end(), us, compare);
std::cout << '\n';
};
// Results of the algorithms
using Jt = decltype(x.begin()); // Type of input iterators
using Cm = decltype(compare); // Type of comparison function
run2(std::merge<Jt,Jt,Us,Cm>); // Output: abBBCdddDDggHi
run2(std::set_union<Jt,Jt,Us,Cm>); // Output: abBCdddggHi
run2(std::set_intersection<Jt,Jt,Us,Cm>); // Output: bdd
run2(std::set_difference<Jt,Jt,Us,Cm>); // Output: adggi
run2(std::set_symmetric_difference<Jt,Jt,Us,Cm>); // Output: aBCdggHi
}
Godbolt Listing lst-0018-godb.cpp, https://godbolt.org/z/1esod6hrT:
//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/1esod6hrT
#include <algorithm>
#include <iostream>
#include <list>
#include <string>
#include <iterator> // ostream_iterator
#include <cctype> // toupper
using std::toupper;
int main() {
std::list a{ 1,2,4,4,4,7,7,9 };
std::list b{ 2,2,3,4,4,8 };
using Os = std::ostream_iterator<int>; // Type of output iterator
Os os{std::cout, " "}; // Stream output iterator for int
auto run = [&a,&b,&os](auto algo) { // use a, b, and os
algo(a.begin(), a.end(), b.begin(), b.end(), os); // Call algorithm
std::cout << '\n';
};
// Results of the algorithms
using It = decltype(a.begin()); // Type of input iterators
run(std::merge<It,It,Os>); // Output: 1 2 2 2 3 4 4 4 4 4 7 7 8 9
run(std::set_union<It,It,Os>); // Output: 1 2 2 3 4 4 4 7 7 8 9
run(std::set_intersection<It,It,Os>); // Output: 2 4 4
run(std::set_difference<It,It,Os>); // Output: 1 4 7 7 9
run(std::set_symmetric_difference<It,It,Os>); // Output: 1 2 3 4 7 7 8 9
// With letters it becomes even clearer
std::string x = "abdddggi";
std::string y = "BBCDDH";
using Us = std::ostream_iterator<char>; // Type of output iterator
Us us{std::cout, ""}; // Stream output iterator for char
auto compare = [](auto c, auto d) { return toupper(c) < toupper(d); };
auto run2 = [&x,&y,&us,&compare](auto algo) { // use x, y, and us
algo(x.begin(), x.end(), y.begin(), y.end(), us, compare);
std::cout << '\n';
};
// Results of the algorithms
using Jt = decltype(x.begin()); // Type of input iterators
using Cm = decltype(compare); // Type of comparison function
run2(std::merge<Jt,Jt,Us,Cm>); // Output: abBBCdddDDggHi
run2(std::set_union<Jt,Jt,Us,Cm>); // Output: abBCdddggHi
run2(std::set_intersection<Jt,Jt,Us,Cm>); // Output: bdd
run2(std::set_difference<Jt,Jt,Us,Cm>); // Output: adggi
run2(std::set_symmetric_difference<Jt,Jt,Us,Cm>); // Output: aBCdggHi
}
GodboltId:j6GPKc36P
Book listing lst-0019-book.cpp:
// https://godbolt.org/z/j6GPKc36P
#include <iostream>
#include <algorithm>
#include <string>
void one(std::string &seq) {
std::ranges::next_permutation(seq);
std::cout << seq << '\n';
}
int main() {
std::string seq = "JQK";
std::cout << seq << '\n'; // Output: JQK
auto limit = 3*2*1; // n!
for(int i=0; i<limit; ++i)
one(seq);
// Here the sequence is back to its original state.
}
Godbolt Listing lst-0019-godb.cpp, https://godbolt.org/z/j6GPKc36P:
//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/j6GPKc36P
#include <iostream>
#include <algorithm>
#include <string>
void one(std::string &seq) {
std::ranges::next_permutation(seq);
std::cout << seq << '\n';
}
int main() {
std::string seq = "JQK";
std::cout << seq << '\n'; // Output: JQK
auto limit = 3*2*1; // n!
for(int i=0; i<limit; ++i)
one(seq);
// Here the sequence is back to its original state.
}
Listing 25.15: “accumulate” example.
Book listing lst-0020-book.cpp:
// https://godbolt.org/z/Y7GPcqWM8
#include <numeric> // accumulate
#include <functional> // multiplies
#include <algorithm> // transform, fold_left
#include <iostream>
#include <vector>
using std::accumulate; using std::cout; using std::vector; using std::multiplies;
namespace rs = std::ranges;
int main() {
vector data{ 2, 3, 5, 10, 20 };
cout << accumulate(data.begin(),data.end(),0)<<'\n'; // +, Output: 40
cout << rs::fold_left(data, 1, multiplies<int>{})<<'\n'; // *, 6000
vector<bool> even( data.size() );
std::transform( data.begin(), data.end(), even.begin(),
[](auto n) { return n%2==0; });
for(auto b : even) {
cout << ( b ? "even " : "odd ");
}
cout << "\n"; // Output: even odd odd even even
auto areAllEven = accumulate(even.begin(), even.end(), true,
[](auto b, auto c) { return b&&c; });
if(areAllEven) {
cout << "all even numbers\n";
} else {
cout << "odd numbers included\n"; // this is the output
}
}
Godbolt Listing lst-0020-godb.cpp, https://godbolt.org/z/Y7GPcqWM8:
//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/Y7GPcqWM8
#include <numeric> // accumulate
#include <functional> // multiplies
#include <algorithm> // transform, fold_left
#include <iostream>
#include <vector>
using std::accumulate; using std::cout; using std::vector; using std::multiplies;
namespace rs = std::ranges;
int main() {
vector data{ 2, 3, 5, 10, 20 };
cout << accumulate(data.begin(),data.end(),0)<<'\n'; // +, Output: 40
cout << rs::fold_left(data, 1, multiplies<int>{})<<'\n'; // *, 6000
vector<bool> even( data.size() );
std::transform( data.begin(), data.end(), even.begin(),
[](auto n) { return n%2==0; });
for(auto b : even) {
cout << ( b ? "even " : "odd ");
}
cout << "\n"; // Output: even odd odd even even
auto areAllEven = accumulate(even.begin(), even.end(), true,
[](auto b, auto c) { return b&&c; });
if(areAllEven) {
cout << "all even numbers\n";
} else {
cout << "odd numbers included\n"; // this is the output
}
}
Listing 25.16: “adjacent_difference” and “pairwise_transform”.
Book listing lst-0021-book.cpp:
// https://godbolt.org/z/5Whz59374
#include <numeric> // adjacent_difference
#include <functional> // plus
#include <algorithm> // copy
#include <iostream>
#include <iterator> // ostream_iterator
#include <vector>
#include <ranges> // pairwise_transform
using std::cout; using std::vector; namespace vs = std::views;
int main() {
// Stream output iterator for int;
std::ostream_iterator<int> os{std::cout, " "};
vector data{ 1, -1, 2, -2, -4, 4, -6, 6 };
std::copy(data.begin(), data.end (), os);
cout << '\n'; // Output: 1 -1 2 -2 -4 4 -6 6
vector<int> res( data.size()-1 ); // Space for result
// Write results to res:
adjacent_difference(data.begin(), data.end(), res.begin());
std::copy (res.begin(), res.end (), os);
cout << '\n'; // Output: 1 -2 3 -4 -2 8 -10
// Write directly to os:
adjacent_difference(data.begin(), data.end(), os, std::plus<int>{});
cout << '\n'; // Output: 1 0 1 0 -6 0 -2 0
// or via range adapter:
for(auto e: vs::pairwise_transform(data, std::plus<int>{}))
cout << e << ' ';
cout << '\n'; // Output: 0 1 0 –6 0 –2 0
}
Godbolt Listing lst-0021-godb.cpp, https://godbolt.org/z/5Whz59374:
//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/5Whz59374
#include <numeric> // adjacent_difference
#include <functional> // plus
#include <algorithm> // copy
#include <iostream>
#include <iterator> // ostream_iterator
#include <vector>
#include <ranges> // pairwise_transform
using std::cout; using std::vector; namespace vs = std::views;
int main() {
// Stream output iterator for int;
std::ostream_iterator<int> os{std::cout, " "};
vector data{ 1, -1, 2, -2, -4, 4, -6, 6 };
std::copy(data.begin(), data.end (), os);
cout << '\n'; // Output: 1 -1 2 -2 -4 4 -6 6
vector<int> res( data.size()-1 ); // Space for result
// Write results to res:
adjacent_difference(data.begin(), data.end(), res.begin());
std::copy (res.begin(), res.end (), os);
cout << '\n'; // Output: 1 -2 3 -4 -2 8 -10
// Write directly to os:
adjacent_difference(data.begin(), data.end(), os, std::plus<int>{});
cout << '\n'; // Output: 1 0 1 0 -6 0 -2 0
// or via range adapter:
for(auto e: vs::pairwise_transform(data, std::plus<int>{}))
cout << e << ' ';
cout << '\n'; // Output: 0 1 0 –6 0 –2 0
}
Listing 25.17: “iota”, “stride”, and “take”
Book listing lst-0022-book.cpp:
// https://godbolt.org/z/WPrP79sv6
#include <numeric> // accumulate, iota
#include <algorithm> // copy
#include <iostream>
#include <iterator> // ostream_iterator
#include <vector>
#include <ranges> // iota, take, stride
using std::accumulate; using std::cout; using std::vector;
namespace vs = std::views;
struct Generator {
int state_;
void operator++() { state_ += state_; }
operator int() { return state_; }
};
int main() {
std::ostream_iterator<int> os{std::cout, " "}; // Stream output iterator for int
vector<int> data(7);
std::iota(data.begin(), data.end(), 10);
std::copy(data.begin(), data.end (), os);
cout << '\n'; // Output: 10 11 12 13 14 15 16
vector<int> seq(7);
std::iota(seq.begin(), seq.end(), Generator{2});
std::copy(seq.begin(), seq.end(), os);
cout << '\n'; // Output: 2 4 8 16 32 64 128
for(auto i: vs::iota(0) | vs::stride(3) | vs::take(6))
cout << i << ' ';
cout << '\n'; // Output: 0 3 6 9 12 15
}
Godbolt Listing lst-0022-godb.cpp, https://godbolt.org/z/WPrP79sv6:
//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/WPrP79sv6
#include <numeric> // accumulate, iota
#include <algorithm> // copy
#include <iostream>
#include <iterator> // ostream_iterator
#include <vector>
#include <ranges> // iota, take, stride
using std::accumulate; using std::cout; using std::vector;
namespace vs = std::views;
struct Generator {
int state_;
void operator++() { state_ += state_; }
operator int() { return state_; }
};
int main() {
std::ostream_iterator<int> os{std::cout, " "}; // Stream output iterator for int
vector<int> data(7);
std::iota(data.begin(), data.end(), 10);
std::copy(data.begin(), data.end (), os);
cout << '\n'; // Output: 10 11 12 13 14 15 16
vector<int> seq(7);
std::iota(seq.begin(), seq.end(), Generator{2});
std::copy(seq.begin(), seq.end(), os);
cout << '\n'; // Output: 2 4 8 16 32 64 128
for(auto i: vs::iota(0) | vs::stride(3) | vs::take(6))
cout << i << ' ';
cout << '\n'; // Output: 0 3 6 9 12 15
}
Listing 25.18: “inclusive_scan” and “exclusive_scan”.
Book listing lst-0023-book.cpp:
// https://godbolt.org/z/enj3znvTs
#include <numeric> // *_scan
#include <iostream>
#include <vector>
using std::inclusive_scan; using std::exclusive_scan;
std::ostream& operator<<=(std::ostream&os, const std::vector<int>&data) {
for(auto &e : data) os << e << ' '; return os << '\n';
}
int main() {
std::vector data{ 1, 3, 10, 18, 30, 50 };
std::vector<int> result(6); // 6 elements
auto plus = [](auto a, auto b) { return a+b; };
inclusive_scan(data.begin(),data.end(), result.begin(), plus, 100);
std::cout <<= result;
// Output: 101 104 114 132 162 212
exclusive_scan(data.begin(),data.end(), result.begin(), 100);
std::cout <<= result;
// Output: 100 101 104 114 132 162
}
Godbolt Listing lst-0023-godb.cpp, https://godbolt.org/z/enj3znvTs:
//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/enj3znvTs
#include <numeric> // *_scan
#include <iostream>
#include <vector>
using std::inclusive_scan; using std::exclusive_scan;
std::ostream& operator<<=(std::ostream&os, const std::vector<int>&data) {
for(auto &e : data) os << e << ' '; return os << '\n';
}
int main() {
std::vector data{ 1, 3, 10, 18, 30, 50 };
std::vector<int> result(6); // 6 elements
auto plus = [](auto a, auto b) { return a+b; };
inclusive_scan(data.begin(),data.end(), result.begin(), plus, 100);
std::cout <<= result;
// Output: 101 104 114 132 162 212
exclusive_scan(data.begin(),data.end(), result.begin(), 100);
std::cout <<= result;
// Output: 100 101 104 114 132 162
}
GodboltId:dKPbjj1f8
Book listing lst-0024-book.cpp:
// https://godbolt.org/z/dKPbjj1f8
#include <iostream>
#include <memory> // uninitialized_copy
#include <alloca.h> // alloca (Linux)
#include <list>
int main () {
const std::list input{1,9,2,6,6,6,8};
const auto SZ = input.size();
// uninitialized memory area:
int* target = (int*)alloca(sizeof(int) * SZ); // space for 7 ints
std::uninitialized_copy(input.begin(), input.end(), target);
// test output
for(int idx=0; idx<SZ; ++idx) {
std::cout << target[idx] << ' ';
}
std::cout << '\n'; // output: 1 9 2 6 6 6 8
}
Godbolt Listing lst-0024-godb.cpp, https://godbolt.org/z/dKPbjj1f8:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/dKPbjj1f8
#include <iostream>
#include <memory> // uninitialized_copy
#include <alloca.h> // alloca (Linux)
#include <list>
int main () {
const std::list input{1,9,2,6,6,6,8};
const auto SZ = input.size();
// uninitialized memory area:
int* target = (int*)alloca(sizeof(int) * SZ); // space for 7 ints
std::uninitialized_copy(input.begin(), input.end(), target);
// test output
for(int idx=0; idx<SZ; ++idx) {
std::cout << target[idx] << ' ';
}
std::cout << '\n'; // output: 1 9 2 6 6 6 8
}
Listing 26.19: A custom algorithm.
Book listing lst-0026-book.cpp:
// https://godbolt.org/z/n8ErWj7j6
template<typename It, typename Func>
void adjacent_pair(It begin, It end, Func func) {
if(begin != end) {
It prev = begin; // first argument
++begin; // second argument
for(; begin != end; ++begin, ++prev) {
func(*prev, *begin);
}
}
}
Godbolt Listing lst-0026-godb.cpp, https://godbolt.org/z/n8ErWj7j6:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/n8ErWj7j6
template<typename It, typename Func>
void adjacent_pair(It begin, It end, Func func) {
if(begin != end) {
It prev = begin; // first argument
++begin; // second argument
for(; begin != end; ++begin, ++prev) {
func(*prev, *begin);
}
}
}
Listing 25.19: The use of adjacent_pair.
Book listing lst-0027-book.cpp:
// https://godbolt.org/z/91jj8Toqs
#include <vector>
#include <iostream>
// … adjacent_pair from above here …
int main() {
std::vector v{1,2,3,4};
auto f = [](auto a, auto b) { std::cout << (a+b) << ' '; };
adjacent_pair(v.begin(), v.end(), f); // 3 5 7
std::cout << '\n';
std::vector x{4,8};
adjacent_pair(x.begin(), x.end(), f); // 12
std::cout << '\n';
std::vector w{4};
adjacent_pair(w.begin(), w.end(), f); // nothing
std::cout << '\n';
std::vector<int> y{};
adjacent_pair(y.begin(), y.end(), f); // nothing
std::cout << '\n';
}
Godbolt Listing lst-0027-godb.cpp, https://godbolt.org/z/91jj8Toqs:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/91jj8Toqs
#include <vector>
#include <iostream>
// … adjacent_pair from above here …
int main() {
std::vector v{1,2,3,4};
auto f = [](auto a, auto b) { std::cout << (a+b) << ' '; };
adjacent_pair(v.begin(), v.end(), f); // 3 5 7
std::cout << '\n';
std::vector x{4,8};
adjacent_pair(x.begin(), x.end(), f); // 12
std::cout << '\n';
std::vector w{4};
adjacent_pair(w.begin(), w.end(), f); // nothing
std::cout << '\n';
std::vector<int> y{};
adjacent_pair(y.begin(), y.end(), f); // nothing
std::cout << '\n';
}
Listing 25.20: Custom range adapters for views.
Book listing lst-0028-book.cpp:
// https://godbolt.org/z/e54xzT9dW
#include <ranges>
#include <iostream>
#include <string_view>
#include <vector>
using namespace std::literals;
using namespace std; namespace vs = std::views; namespace rs = std::ranges;
// Example 1
class Add_1: public rs::range_adaptor_closure<Add_1> {
// derive from helper class
public:
template<rs::input_range R>
constexpr auto operator()(R&& r) const { // universal reference
return forward<R>(r) // preserve universal reference
| vs::transform([](auto i) {return i+1;}); // Your implementation
}
};
Add_1 add_1{}; // Create range adapter
// Example 2
class Dna_to_rna: public rs::range_adaptor_closure<Dna_to_rna> { // derive
public:
template<rs::input_range R>
constexpr auto operator()(R&& r) const { // universal reference
return forward<R>(r) // preserve universal reference
| vs::transform([](char c) // Your implementation
{
switch(c) {
case 'T': return 'U';
case 't': return 'u';
default: return c;
}
});
}
};
Dna_to_rna dna_to_rna{}; // Create Range-Adapter
// Use examples
int main() {
vector vec{1, 2, 3, 4, 5};
for(auto i: vec | add_1) // use
cout << i << ' ';
cout << '\n'; // Output: 2 3 4 5 6
auto telo_rep = "TTAGGGTTAGGGTTAGGGTTAGGGT"sv;
for(auto c: telo_rep | dna_to_rna) // use
cout << c;
cout << '\n'; // Output: UUAGGGUUAGGGUUAGGGUUAGGGU
}
Godbolt Listing lst-0028-godb.cpp, https://godbolt.org/z/e54xzT9dW:
//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/e54xzT9dW
#include <ranges>
#include <iostream>
#include <string_view>
#include <vector>
using namespace std::literals;
using namespace std; namespace vs = std::views; namespace rs = std::ranges;
// Example 1
class Add_1: public rs::range_adaptor_closure<Add_1> {
// derive from helper class
public:
template<rs::input_range R>
constexpr auto operator()(R&& r) const { // universal reference
return forward<R>(r) // preserve universal reference
| vs::transform([](auto i) {return i+1;}); // Your implementation
}
};
Add_1 add_1{}; // Create range adapter
// Example 2
class Dna_to_rna: public rs::range_adaptor_closure<Dna_to_rna> { // derive
public:
template<rs::input_range R>
constexpr auto operator()(R&& r) const { // universal reference
return forward<R>(r) // preserve universal reference
| vs::transform([](char c) // Your implementation
{
switch(c) {
case 'T': return 'U';
case 't': return 'u';
default: return c;
}
});
}
};
Dna_to_rna dna_to_rna{}; // Create Range-Adapter
// Use examples
int main() {
vector vec{1, 2, 3, 4, 5};
for(auto i: vec | add_1) // use
cout << i << ' ';
cout << '\n'; // Output: 2 3 4 5 6
auto telo_rep = "TTAGGGTTAGGGTTAGGGTTAGGGT"sv;
for(auto c: telo_rep | dna_to_rna) // use
cout << c;
cout << '\n'; // Output: UUAGGGUUAGGGUUAGGGUUAGGGU
}