├── .devcontainer ├── Dockerfile └── devcontainer.json ├── .gitignore ├── .vscode ├── extensions.json └── settings.json ├── LICENSE.md ├── README.md ├── book.tex ├── build └── .keep ├── chapters ├── 00_title_page.tex ├── 01_preface.tex ├── 02_introduction.tex ├── 03_algorithms_00_main.tex ├── 03_algorithms_01_foreach.tex ├── 03_algorithms_02_swaps.tex ├── 03_algorithms_03_sorting.tex ├── 03_algorithms_04_partitioning.tex ├── 03_algorithms_05_divide.tex ├── 03_algorithms_06_linear_sorted.tex ├── 03_algorithms_07_sets.tex ├── 03_algorithms_08_transformations.tex ├── 03_algorithms_09_left_folds.tex ├── 03_algorithms_10_general_reductions.tex ├── 03_algorithms_11_boolean.tex ├── 03_algorithms_12_generators.tex ├── 03_algorithms_13_copies_moves.tex ├── 03_algorithms_14_uninitialized.tex ├── 03_algorithms_15_heap.tex ├── 03_algorithms_16_searching.tex ├── 03_algorithms_17_minmax.tex ├── 04_views_00_main.tex ├── 04_views_01_intro_ranges.tex ├── 04_views_02_the_views.tex ├── 90_theory.tex └── Y8_extra_topics.tex ├── code_examples ├── CMakeLists.txt ├── algorithms │ ├── CMakeLists.txt │ ├── accumulate.cpp │ ├── accumulate_code.h │ ├── accumulate_right.cpp │ ├── accumulate_right_code.h │ ├── adjacent_difference.cpp │ ├── adjacent_difference_code.h │ ├── adjacent_difference_extra.cpp │ ├── adjacent_difference_extra_code.h │ ├── adjacent_difference_par_code.h │ ├── adjacent_find.cpp │ ├── adjacent_find_code.h │ ├── all_of.cpp │ ├── all_of_code.h │ ├── binary_search.cpp │ ├── binary_search_code.h │ ├── bsearch.cpp │ ├── bsearch_alternatives.cpp │ ├── bsearch_alternatives_code.h │ ├── bsearch_code.h │ ├── clamp.cpp │ ├── clamp_code.h │ ├── copy.cpp │ ├── copy_backward.cpp │ ├── copy_backward_code.h │ ├── copy_code.h │ ├── copy_if.cpp │ ├── copy_if_code.h │ ├── copy_n.cpp │ ├── copy_n_code.h │ ├── count.cpp │ ├── count_code.h │ ├── create_at.cpp │ ├── create_at_code.h │ ├── equal.cpp │ ├── equal_code.h │ ├── equal_range.cpp │ ├── equal_range_code.h │ ├── equal_with_range.cpp │ ├── equal_with_range_code.h │ ├── exclusive_scan.cpp │ ├── exclusive_scan_code.h │ ├── fill_n.cpp │ ├── fill_n_code.h │ ├── find.cpp │ ├── find_code.h │ ├── find_first_of.cpp │ ├── find_first_of_code.h │ ├── find_if.cpp │ ├── find_if_code.h │ ├── for_each.cpp │ ├── for_each_code_cpp20.h │ ├── for_each_code_parallel.h │ ├── for_each_code_range.h │ ├── for_each_code_simple.h │ ├── for_each_n.cpp │ ├── for_each_n_code.h │ ├── generate.cpp │ ├── generate_code.h │ ├── includes.cpp │ ├── includes_code.h │ ├── inclusive_scan.cpp │ ├── inclusive_scan_code.h │ ├── inner_product.cpp │ ├── inner_product_code.h │ ├── inner_product_one.cpp │ ├── inner_product_one_code.h │ ├── inplace_merge.cpp │ ├── inplace_merge_code.h │ ├── iota.cpp │ ├── iota_code.h │ ├── iota_view.cpp │ ├── iota_view_code.h │ ├── is_heap.cpp │ ├── is_heap_code.h │ ├── is_partitioned.cpp │ ├── is_partitioned_code.h │ ├── is_permutation.cpp │ ├── is_permutation_code.h │ ├── is_sorted.cpp │ ├── is_sorted_code.h │ ├── is_sorted_until.cpp │ ├── is_sorted_until_code.h │ ├── iter_swap_partition.cpp │ ├── iter_swap_partition_code.h │ ├── iter_swap_unique_ptr.cpp │ ├── iter_swap_unique_ptr_code.h │ ├── lexicographical_compare.cpp │ ├── lexicographical_compare_code.h │ ├── lexicographical_compare_three_way.cpp │ ├── lexicographical_compare_three_way_code.h │ ├── lexicographical_compare_useful.cpp │ ├── lexicographical_compare_useful_code.h │ ├── lower_bound.cpp │ ├── lower_bound_code.h │ ├── lower_bound_set.cpp │ ├── lower_bound_set_code.h │ ├── make_heap.cpp │ ├── make_heap_code.h │ ├── merge.cpp │ ├── merge_code.h │ ├── merge_par.cpp │ ├── merge_par_code.h │ ├── min_element.cpp │ ├── min_element_code.h │ ├── min_element_dangling.cpp │ ├── min_element_dangling_code.h │ ├── min_max.cpp │ ├── min_max_code.h │ ├── minmax.cpp │ ├── minmax_code.h │ ├── minmax_extra.cpp │ ├── minmax_extra_code.h │ ├── mismatch.cpp │ ├── mismatch_code.h │ ├── move.cpp │ ├── move_code.h │ ├── move_nomove.cpp │ ├── move_nomove_code.h │ ├── next_permutation.cpp │ ├── next_permutation_code.h │ ├── nth_element.cpp │ ├── nth_element_code.h │ ├── partial_sort.cpp │ ├── partial_sort_code.h │ ├── partial_sort_copy.cpp │ ├── partial_sort_copy_code.h │ ├── partial_sum.cpp │ ├── partial_sum_code.h │ ├── partition.cpp │ ├── partition_code.h │ ├── partition_copy.cpp │ ├── partition_copy_code.h │ ├── partition_point.cpp │ ├── partition_point_code.h │ ├── push_heap.cpp │ ├── push_heap_code.h │ ├── qsort.cpp │ ├── qsort_code.h │ ├── qsort_not.cpp │ ├── qsort_not_code.h │ ├── reduce.cpp │ ├── reduce_code.h │ ├── reduce_noinit.cpp │ ├── reduce_noinit_code.h │ ├── remove.cpp │ ├── remove_code.h │ ├── replace.cpp │ ├── replace_code.h │ ├── replace_copy.cpp │ ├── replace_copy_code.h │ ├── reverse.cpp │ ├── reverse_code.h │ ├── reverse_copy.cpp │ ├── reverse_copy_code.h │ ├── rotate.cpp │ ├── rotate_code.h │ ├── rotate_copy.cpp │ ├── rotate_copy_code.h │ ├── sample.cpp │ ├── sample_code.h │ ├── search.cpp │ ├── search_code.h │ ├── search_n.cpp │ ├── search_n_code.h │ ├── searchers.cpp │ ├── searchers_code.h │ ├── set_difference.cpp │ ├── set_difference_code.h │ ├── set_difference_equal.cpp │ ├── set_difference_equal_code.h │ ├── set_intersection.cpp │ ├── set_intersection_code.h │ ├── set_intersection_equal.cpp │ ├── set_intersection_equal_code.h │ ├── set_symmetric_difference.cpp │ ├── set_symmetric_difference_code.h │ ├── set_symmetric_difference_equal.cpp │ ├── set_symmetric_difference_equal_code.h │ ├── set_union.cpp │ ├── set_union_code.h │ ├── set_union_equal.cpp │ ├── set_union_equal_code.h │ ├── shift_code.h │ ├── shift_move_code.h │ ├── shuffle.cpp │ ├── shuffle_code.h │ ├── sort.cpp │ ├── sort_code.h │ ├── sort_heap.cpp │ ├── sort_heap_code.h │ ├── sort_projection.cpp │ ├── sort_projection_code.h │ ├── stable_partition.cpp │ ├── stable_partition_code.h │ ├── stable_sort.cpp │ ├── stable_sort_code.h │ ├── swap_calling.cpp │ ├── swap_calling_code.h │ ├── swap_range.cpp │ ├── swap_range_code.h │ ├── swap_ranges.cpp │ ├── swap_ranges_code.h │ ├── transactional.cpp │ ├── transactional_code.h │ ├── transform.cpp │ ├── transform_code.h │ ├── transform_inclusive.cpp │ ├── transform_inclusive_code.h │ ├── transform_reduce.cpp │ ├── transform_reduce_code.h │ ├── uninitialized_constr.cpp │ ├── uninitialized_constr_code.h │ ├── uninitialized_copy.cpp │ ├── uninitialized_copy_code.h │ ├── unique.cpp │ ├── unique_code.h │ ├── unique_copy.cpp │ └── unique_copy_code.h ├── extras │ ├── CMakeLists.txt │ ├── priority_queue.cpp │ ├── priority_queue_heap_code.h │ ├── priority_queue_queue_code.h │ ├── span_stringview.cpp │ └── span_stringview_code.h ├── introduction │ ├── CMakeLists.txt │ ├── categories.cpp │ ├── categories_code.h │ ├── history_cc11.cpp │ ├── history_cc11_code.h │ ├── history_cc17.cpp │ ├── history_cc17_code.h │ ├── history_cc20.cpp │ ├── history_cc20_code.h │ ├── history_cc98.cpp │ ├── history_cc98_code.h │ ├── iterators.cpp │ ├── iterators_code.h │ ├── mental_find.cpp │ ├── mental_find_code.h │ ├── mental_range.cpp │ ├── mental_range_code.h │ ├── mental_sorted.cpp │ ├── mental_sorted_code.h │ ├── mental_two.cpp │ ├── mental_two_code.h │ ├── sentinels.cpp │ └── sentinels_code.h ├── ranges │ ├── CMakeLists.txt │ ├── borrowed_optin_code.h │ ├── concepts.cpp │ ├── concepts_code.h │ ├── dangling.cpp │ ├── dangling_code.h │ ├── infinite.cpp │ ├── infinite_code.h │ ├── projected_type.cpp │ ├── projected_type_code.h │ ├── projection_code.h │ ├── rangified.cpp │ ├── rangified_code.h │ ├── stateful_code.h │ ├── view_demo.cpp │ └── view_demo_code.h ├── theory │ ├── CMakeLists.txt │ ├── adl.cpp │ ├── adl_code.h │ ├── adl_default.cpp │ ├── adl_default_code.h │ ├── adl_friend.cpp │ ├── adl_friend_code.h │ ├── adl_niebloid.cpp │ ├── adl_niebloid_code.h │ ├── adl_nonfunc.cpp │ ├── adl_nonfunc_code.h │ ├── adl_shutdown.cpp │ ├── adl_shutdown_code.h │ ├── adl_simple.cpp │ ├── adl_simple_code.h │ ├── adl_unqalified.cpp │ ├── adl_unqalified_code.h │ ├── comparable_code.h │ ├── const_cast.cpp │ ├── const_cast_code.h │ ├── deduction_algorithm.h │ ├── deduction_concepts.h │ ├── floating_point.h │ ├── floating_point_ordering.h │ ├── initializer_list.cpp │ ├── initializer_list_code.h │ ├── integral_conversions_different_a.h │ ├── integral_conversions_different_b.h │ ├── integral_conversions_different_c.h │ ├── integral_conversions_problems.h │ ├── integral_conversions_same.h │ ├── integral_promotions.h │ ├── references.h │ ├── safe_compare.h │ ├── safe_in_range.h │ └── safe_ssize.h ├── verify.sh └── views │ ├── CMakeLists.txt │ ├── all.cpp │ ├── all_code.h │ ├── common.cpp │ ├── common_code.h │ ├── counted.cpp │ ├── counted_code.h │ ├── drop.cpp │ ├── drop_code.h │ ├── elements.cpp │ ├── elements_code.h │ ├── filter.cpp │ ├── filter_code.h │ ├── iota.cpp │ ├── iota_code.h │ ├── istream.cpp │ ├── istream_code.h │ ├── join.cpp │ ├── join_code.h │ ├── keys_values.cpp │ ├── keys_values_code.h │ ├── reverse.cpp │ ├── reverse_code.h │ ├── single.cpp │ ├── single_code.h │ ├── split.cpp │ ├── split_code.h │ ├── take.cpp │ ├── take_code.h │ ├── transform.cpp │ └── transform_code.h ├── packages ├── custom_commands │ ├── CC.tex │ ├── ExternalLink.tex │ ├── circled.tex │ ├── codebox.tex │ ├── constraints.tex │ ├── cpp.tex │ ├── cppversions.tex │ └── version.tex ├── fonts.tex ├── hyperref.tex └── packages.tex └── static ├── book_cover.pdf ├── book_cover.png └── fonts ├── asap ├── Asap-Bold.ttf ├── Asap-BoldItalic.ttf ├── Asap-Italic.ttf ├── Asap-Medium.ttf ├── Asap-MediumItalic.ttf ├── Asap-Regular.ttf ├── Asap-SemiBold.ttf └── Asap-SemiBoldItalic.ttf ├── brygada ├── Brygada1918-Bold.ttf ├── Brygada1918-BoldItalic.ttf ├── Brygada1918-Italic.ttf ├── Brygada1918-Medium.ttf ├── Brygada1918-MediumItalic.ttf ├── Brygada1918-Regular.ttf ├── Brygada1918-SemiBold.ttf └── Brygada1918-SemiBoldItalic.ttf └── jetbrains ├── JetBrainsMono-Bold.ttf ├── JetBrainsMono-BoldItalic.ttf ├── JetBrainsMono-ExtraBold.ttf ├── JetBrainsMono-ExtraBoldItalic.ttf ├── JetBrainsMono-ExtraLight.ttf ├── JetBrainsMono-ExtraLightItalic.ttf ├── JetBrainsMono-Italic.ttf ├── JetBrainsMono-Light.ttf ├── JetBrainsMono-LightItalic.ttf ├── JetBrainsMono-Medium.ttf ├── JetBrainsMono-MediumItalic.ttf ├── JetBrainsMono-Regular.ttf ├── JetBrainsMono-SemiBold.ttf ├── JetBrainsMono-SemiBoldItalic.ttf ├── JetBrainsMono-Thin.ttf └── JetBrainsMono-ThinItalic.ttf /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | #FROM ubuntu:22.04 2 | FROM texlive/texlive:latest 3 | 4 | ARG DEBIAN_FRONTEND=noninteractive 5 | 6 | RUN set -ex && \ 7 | apt-get update && \ 8 | apt-get install -y cmake gcc g++ -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "build": { 3 | "dockerfile": "Dockerfile" 4 | }, 5 | "extensions": [ 6 | "James-Yu.latex-workshop" 7 | ] 8 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Core latex/pdflatex auxiliary files: 2 | *.aux 3 | *.lof 4 | *.log 5 | *.lot 6 | *.fls 7 | *.out 8 | *.toc 9 | *.fmt 10 | *.fot 11 | *.cb 12 | *.cb2 13 | .*.lb 14 | 15 | ## Intermediate documents: 16 | *.dvi 17 | *.xdv 18 | *-converted-to.* 19 | # these rules might exclude image files for figures etc. 20 | # *.ps 21 | # *.eps 22 | # *.pdf 23 | 24 | ## Generated if empty string is given at "Please type another file name for output:" 25 | .pdf 26 | 27 | ## Bibliography auxiliary files (bibtex/biblatex/biber): 28 | *.bbl 29 | *.bcf 30 | *.blg 31 | *-blx.aux 32 | *-blx.bib 33 | *.run.xml 34 | 35 | ## Build tool auxiliary files: 36 | *.fdb_latexmk 37 | *.synctex 38 | *.synctex(busy) 39 | *.synctex.gz 40 | *.synctex.gz(busy) 41 | *.pdfsync 42 | 43 | ## Build tool directories for auxiliary files 44 | # latexrun 45 | latex.out/ 46 | 47 | ## Auxiliary and intermediate files from other packages: 48 | # algorithms 49 | *.alg 50 | *.loa 51 | 52 | # achemso 53 | acs-*.bib 54 | 55 | # amsthm 56 | *.thm 57 | 58 | # beamer 59 | *.nav 60 | *.pre 61 | *.snm 62 | *.vrb 63 | 64 | # changes 65 | *.soc 66 | 67 | # comment 68 | *.cut 69 | 70 | # cprotect 71 | *.cpt 72 | 73 | # elsarticle (documentclass of Elsevier journals) 74 | *.spl 75 | 76 | # endnotes 77 | *.ent 78 | 79 | # fixme 80 | *.lox 81 | 82 | # feynmf/feynmp 83 | *.mf 84 | *.mp 85 | *.t[1-9] 86 | *.t[1-9][0-9] 87 | *.tfm 88 | 89 | #(r)(e)ledmac/(r)(e)ledpar 90 | *.end 91 | *.?end 92 | *.[1-9] 93 | *.[1-9][0-9] 94 | *.[1-9][0-9][0-9] 95 | *.[1-9]R 96 | *.[1-9][0-9]R 97 | *.[1-9][0-9][0-9]R 98 | *.eledsec[1-9] 99 | *.eledsec[1-9]R 100 | *.eledsec[1-9][0-9] 101 | *.eledsec[1-9][0-9]R 102 | *.eledsec[1-9][0-9][0-9] 103 | *.eledsec[1-9][0-9][0-9]R 104 | 105 | # glossaries 106 | *.acn 107 | *.acr 108 | *.glg 109 | *.glo 110 | *.gls 111 | *.glsdefs 112 | *.lzo 113 | *.lzs 114 | 115 | # uncomment this for glossaries-extra (will ignore makeindex's style files!) 116 | # *.ist 117 | 118 | # gnuplottex 119 | *-gnuplottex-* 120 | 121 | # gregoriotex 122 | *.gaux 123 | *.gtex 124 | 125 | # htlatex 126 | *.4ct 127 | *.4tc 128 | *.idv 129 | *.lg 130 | *.trc 131 | *.xref 132 | 133 | # hyperref 134 | *.brf 135 | 136 | # knitr 137 | *-concordance.tex 138 | # TODO Comment the next line if you want to keep your tikz graphics files 139 | *.tikz 140 | *-tikzDictionary 141 | 142 | # listings 143 | *.lol 144 | 145 | # luatexja-ruby 146 | *.ltjruby 147 | 148 | # makeidx 149 | *.idx 150 | *.ilg 151 | *.ind 152 | 153 | # minitoc 154 | *.maf 155 | *.mlf 156 | *.mlt 157 | *.mtc[0-9]* 158 | *.slf[0-9]* 159 | *.slt[0-9]* 160 | *.stc[0-9]* 161 | 162 | # minted 163 | _minted* 164 | *.pyg 165 | 166 | # morewrites 167 | *.mw 168 | 169 | # nomencl 170 | *.nlg 171 | *.nlo 172 | *.nls 173 | 174 | # pax 175 | *.pax 176 | 177 | # pdfpcnotes 178 | *.pdfpc 179 | 180 | # sagetex 181 | *.sagetex.sage 182 | *.sagetex.py 183 | *.sagetex.scmd 184 | 185 | # scrwfile 186 | *.wrt 187 | 188 | # sympy 189 | *.sout 190 | *.sympy 191 | sympy-plots-for-*.tex/ 192 | 193 | # pdfcomment 194 | *.upa 195 | *.upb 196 | 197 | # pythontex 198 | *.pytxcode 199 | pythontex-files-*/ 200 | 201 | # tcolorbox 202 | *.listing 203 | 204 | # thmtools 205 | *.loe 206 | 207 | # TikZ & PGF 208 | *.dpth 209 | *.md5 210 | *.auxlock 211 | 212 | # todonotes 213 | *.tdo 214 | 215 | # vhistory 216 | *.hst 217 | *.ver 218 | 219 | # easy-todo 220 | *.lod 221 | 222 | # xcolor 223 | *.xcp 224 | 225 | # xmpincl 226 | *.xmpi 227 | 228 | # xindy 229 | *.xdy 230 | 231 | # xypic precompiled matrices and outlines 232 | *.xyc 233 | *.xyd 234 | 235 | # endfloat 236 | *.ttt 237 | *.fff 238 | 239 | # Latexian 240 | TSWLatexianTemp* 241 | 242 | ## Editors: 243 | # WinEdt 244 | *.bak 245 | *.sav 246 | 247 | # Texpad 248 | .texpadtmp 249 | 250 | # LyX 251 | *.lyx~ 252 | 253 | # Kile 254 | *.backup 255 | 256 | # gummi 257 | .*.swp 258 | 259 | # KBibTeX 260 | *~[0-9]* 261 | 262 | # TeXnicCenter 263 | *.tps 264 | 265 | # auto folder when using emacs and auctex 266 | ./auto/* 267 | *.el 268 | 269 | # expex forward references with \gathertags 270 | *-tags.tex 271 | 272 | # standalone packages 273 | *.sta 274 | 275 | # Makeindex log files 276 | *.lpz 277 | 278 | code_examples/bin 279 | code_examples/build 280 | build -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-vscode-remote.remote-containers" 4 | ], 5 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "latex-workshop.latex.tools": [ 3 | { 4 | "name": "LuaLaTex", 5 | "command": "lualatex", 6 | "args": [ 7 | "-shell-escape", 8 | "-output-directory=%OUTDIR%", 9 | "%DOC%" 10 | ] 11 | } 12 | ], 13 | "latex-workshop.latex.recipes": [ 14 | { 15 | "name": "Build the book", 16 | "tools": [ 17 | "LuaLaTex" 18 | ] 19 | }, 20 | ], 21 | "latex-workshop.latex.recipe.default": "first", 22 | "latex-workshop.latex.outDir": "build" 23 | 24 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Book: A Complete Guide to Standard C++ Algorithms 2 | 3 | This repository contains the LaTeX source and C++ code samples for the book "A Complete Guide to Standard C++ Algorithms". 4 | 5 | [Latest PDF release (v1.0.1)](https://github.com/HappyCerberus/book-cpp-algorithms/releases/download/v1.0.1/a_complete_guide_to_standard_cpp_algorithms_v1_0_1.pdf) 6 | 7 | [![Book Cover](static/book_cover.png)](https://github.com/HappyCerberus/book-cpp-algorithms/releases/download/v1.0.1/a_complete_guide_to_standard_cpp_algorithms_v1_0_1.pdf) 8 | 9 | ## Changelog 10 | 11 | - `1.0.1` Small (mostly) formatting fixes. 12 | - `1.0.0` Content complete release with Compiler Explorer links. 13 | - `0.3.0` New chapter with ADL information and formatting cleanup. 14 | - `0.2.1` Fixed page numbering issue, small text changes. 15 | - `0.2.0` Added chapter covering C++20 ranges and views. 16 | - `0.1.1` Added index and a cover page, small text changes. 17 | - `0.1.0` First pre-release 18 | 19 | ## Building from sources 20 | 21 | The repository is configured with VSCode devcontainer support. 22 | 23 | Make sure that you have VSCode and Docker installed, then simply open the repository in VSCode. You will be prompted to reopen the project in a docker image. 24 | 25 | VSCode is configured to use the LaTeX Workshop extension. To build the PDF simply press `CTRL+ALT+B` or select `LaTeX Workshop: Build LaTeX Project` from the command palette. 26 | Note that due to the high number of code examples, the build does take a while. 27 | The resulting PDF will be in the build folder. 28 | 29 | ### Code samples 30 | 31 | Most code files have wrapping main files that exercise both the build and also contain `assert` expressions that verify correctness of the code. 32 | 33 | The `verify.sh` shell script will build all (except for a few that don't compile with GCC 11) examples, and then run each of them to validate all asserts. 34 | 35 | ## Alternative approach of building from sources 36 | 37 | This section was provided by [@wxinix](https://github.com/wxinix). Please direct any questions to him. 38 | 39 | [TeXstudio](https://www.texstudio.org/) offers an alternative solution for those who are building from sources in a virtual machine environment and are unable to use the VSCode and Docker approach. Follow the steps below (assuming the Guest OS of the virtual machine is Windows): 40 | 41 | - Install [Anaconda](https://www.anaconda.com/) and add `C:\Users\YourUserName\anaconda3\Scripts` to system path. Replace `YourUserName` with your actual user name. 42 | - Install [TeXstudio](https://www.texstudio.org/). 43 | - Go to TeXstudio menu "Options -> Configure TeXstudio -> Commands -> XeLaTex", and enter the following command: `xelatex.exe -synctex=1 -interaction=nonstopmode -shell-escape -aux-directory=build -output-directory=build %.tex`. This command sets both the aux and output directories to ".\build". 44 | - Go to TeXstudio menu "Options -> Configure TeXstudio -> Build -> Meta Commands -> Default Compiler", and enter `txs:///xelatex`. This switches the default compiler from `pdflatex` to `xelatex`. Then, enable the checkbox "Show Advanced Options". 45 | - For TeXstudio menu "Options -> Configure TeXstudio -> Build -> Build Options -> PDF File", enter `build`. This tells the pdf previewer to look for the generated pdf file in the ".\build" directory. 46 | - Finally, go to "TeXstudio menu Options -> Configure TeXstudio -> Commands -> Makeindex", and enter the following command: `makeindex.exe build%.idx` 47 | 48 | These steps will enable you to build from sources inside a virtual machine using TeXstudio. Keep in mind that the VSCode and Docker approach might not work in a virtual machine environment, because it requires extra set-up for [nested virtulization](https://stackoverflow.com/questions/39720254/can-i-run-docker-in-a-virtual-machine). Ask @wxinix if you have any questions. 49 | -------------------------------------------------------------------------------- /book.tex: -------------------------------------------------------------------------------- 1 | \documentclass[11pt,svgnames,table,a4paper]{book} 2 | \input{packages/packages} 3 | 4 | \begin{document} 5 | \frontmatter 6 | \input{chapters/00_title_page} 7 | \input{chapters/01_preface} 8 | 9 | \mainmatter 10 | \tableofcontents 11 | 12 | \input{chapters/02_introduction} 13 | \input{chapters/03_algorithms_00_main} 14 | \input{chapters/04_views_00_main} 15 | \input{chapters/90_theory} 16 | 17 | \appendix 18 | \printindex 19 | 20 | \backmatter 21 | 22 | \end{document} -------------------------------------------------------------------------------- /build/.keep: -------------------------------------------------------------------------------- 1 | # Dummy file to keep the folder in git. -------------------------------------------------------------------------------- /chapters/00_title_page.tex: -------------------------------------------------------------------------------- 1 | \begin{titlepage} 2 | \centering 3 | \vspace{2cm} 4 | {\scshape\huge A complete guide to\par} 5 | \vspace{1.5cm} 6 | {\huge\bfseries Standard C++ Algorithms\par} 7 | \vspace{2cm} 8 | {\Large\itshape RNDr. Šimon Tóth\par} 9 | \vfill 10 | version \version\par 11 | \href{https://github.com/HappyCerberus/book-cpp-algorithms}{https://github.com/HappyCerberus/book-cpp-algorithms} 12 | 13 | \vfill 14 | 15 | % Bottom of the page 16 | {\large \today\par} 17 | \end{titlepage} 18 | 19 | \pagestyle{empty} 20 | %% copyrightpage 21 | \begingroup 22 | \footnotesize 23 | \parindent 0pt 24 | \parskip \baselineskip 25 | \vfill 26 | \textcopyright{} 2022-2023 Šimon Tóth \\ 27 | All rights reserved. 28 | 29 | This work may be distributed and/or modified under the conditions of the CC-BY-NC-SA license. 30 | 31 | Original copy of this book can be obtained at \href{https://github.com/HappyCerberus/book-cpp-algorithms}{https://github.com/HappyCerberus/book-cpp-algorithms}. 32 | 33 | The book is also available through LeanPub where the proceeds go to Electronic Frontier Foundation (after LeanPub takes their cut) \href{https://leanpub.com/cpp-algorithms-guide}{https://leanpub.com/cpp-algorithms-guide}. 34 | 35 | This copy of the book is version \version. 36 | 37 | \vfill 38 | 39 | \vspace*{2\baselineskip} 40 | 41 | 42 | \endgroup 43 | \clearpage 44 | \pagestyle{plain} -------------------------------------------------------------------------------- /chapters/01_preface.tex: -------------------------------------------------------------------------------- 1 | \chapter{Preface} 2 | 3 | This book will not start with a personal story or some other flowery recollections. Instead, to protect your time, I will lay out precisely what this book is about and who am I to be qualified to write this book. Hopefully, this will help you decide whether reading this book is a good use of your time. 4 | 5 | \section*{About this book} 6 | 7 | This book is a complete guide to the \CC\,standard algorithms. However, that might not mean much to you, so let me unpack this statement. 8 | 9 | This book is a guide, as opposed to a reference, meaning that instead of describing every detail, the book concentrates on examples and pointing out notable, surprising, dangerous or interesting aspects of the different algorithms. Furthermore, unlike a reference, it is supposed to be read, for the most part, like a book in sequential order. 10 | 11 | \CC\,already has one canonical reference, the \CC\,standard, and for quick lookup, the \href{https://cppreference.com}{cppreference.com} wiki is a great source. 12 | 13 | The "complete" part of the statement refers to the width of coverage. The book covers all algorithms and relevant theory up to the \CC20 standard (the \CC23 standard is not finalized at the time of writing). All information is present only in sufficient depth required by the context. This depth limitation keeps the book's overall size reasonable and within the "guide" style. 14 | 15 | \section*{About the author} 16 | 17 | I am Šimon Tóth, the sole author of this book. My primary qualification is 20 years of \CC\,experience, with approximately 15 of those years \CC\,being my primary language in professional settings. 18 | 19 | My background is HPC, spanning academia, big tech and startup environments. I have architected, built and operated systems of all scales, from single machine hardware supported high-availability to planet-scale services.\footnote{You can check my \href{https://cz.linkedin.com/in/simontoth}{LinkedIn profile} for a detailed view of my past career.} 20 | 21 | Throughout my career, my passion has always been teaching and mentoring junior engineers, which is why you are now reading this book. 22 | 23 | \section*{Feedback} 24 | 25 | Creating free educational content is very much akin to shouting into the void. There are no sales statistics to follow or milestones to hit. Therefore, please let me know if you read this book and find it helpful or hate it. It will inform my future efforts. 26 | 27 | \section*{Why cc-by-sa-nc} 28 | 29 | This book is licensed CC-BY-SA-NC, which is both an open but, at the same time, minimal license. I aim to allow derivative works (such as translations) but not to permit commercial use, such as using the book as the basis for commercial training or selling printed copies. 30 | 31 | Explicitly, any personal use is permitted. For example, you can read, print, or share the book with your friends. 32 | 33 | If you want to use this content where you are unsure whether you fit within the Creative Commons commercial definition\footnote{primarily intended for or directed toward commercial advantage or monetary compensation}, feel free to contact me on \href{https://hachyderm.io/@simontoth}{Mastodon}, \href{https://cz.linkedin.com/in/simontoth}{LinkedIn} or by \href{mailto:business@simontoth.eu}{email} (my DMs are always open). 34 | 35 | \section*{Book status} 36 | 37 | This book is currently content-complete (upto and including \CC20). 38 | 39 | To keep up with the changes, visit the hosting repository: \url{https://github.com/HappyCerberus/book-cpp-algorithms}. 40 | 41 | \subsection*{Changelog} 42 | 43 | \begin{enumerate} 44 | \item[1.0.1] Small (mostly) formatting changes. 45 | \item[1.0.0] First complete release. 46 | \end{enumerate} -------------------------------------------------------------------------------- /chapters/03_algorithms_00_main.tex: -------------------------------------------------------------------------------- 1 | \chapter{The algorithms} 2 | 3 | \input{chapters/03_algorithms_01_foreach} 4 | \input{chapters/03_algorithms_02_swaps} 5 | \input{chapters/03_algorithms_03_sorting} 6 | \input{chapters/03_algorithms_04_partitioning} 7 | \input{chapters/03_algorithms_05_divide} 8 | \input{chapters/03_algorithms_06_linear_sorted} 9 | \input{chapters/03_algorithms_07_sets} 10 | \input{chapters/03_algorithms_08_transformations} 11 | \input{chapters/03_algorithms_09_left_folds} 12 | \input{chapters/03_algorithms_10_general_reductions} 13 | \input{chapters/03_algorithms_11_boolean} 14 | \input{chapters/03_algorithms_12_generators} 15 | \input{chapters/03_algorithms_13_copies_moves} 16 | \input{chapters/03_algorithms_14_uninitialized} 17 | \input{chapters/03_algorithms_15_heap} 18 | \input{chapters/03_algorithms_16_searching} 19 | \input{chapters/03_algorithms_17_minmax} 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /chapters/03_algorithms_02_swaps.tex: -------------------------------------------------------------------------------- 1 | \section{Swaps} 2 | 3 | Before C++11 and the introduction of move operations, swaps were the only way objects with value semantics could exchange content without involving a deep copy. 4 | 5 | \subsection{\texorpdfstring{\cpp{std::swap}}{\texttt{std::swap}}} 6 | \index{\cpp{std::swap}} 7 | 8 | The non-range version of \cpp{std::swap} will swap the values of the two parameters using a three-step move-swap. Users can provide a more optimized implementation as friend functions on their type. 9 | 10 | \cppversions{\texttt{swap}}{\CC98}{\CC20}{N/A}{\CC20} 11 | 12 | Correctly calling swap requires pulling the default std::swap version to the local scope. To read more on why this is needed check out the theory chapter of this book, specifically the section on ADL (\ref{theory:adl}). 13 | 14 | \begin{codebox}[breakable]{\href{https://compiler-explorer.com/z/Yzvzrb4rY}{\ExternalLink}} 15 | \footnotesize Example of correctly calling \cpp{std::swap}. 16 | \tcblower 17 | \cppfile{code_examples/algorithms/swap_calling_code.h} 18 | \end{codebox} 19 | 20 | The C++20 rangified version of swap removes this complexity, and it will: 21 | 22 | \begin{itemize} 23 | \item call the user-provided (found by ADL) overload of swap 24 | \item if that doesn't exist and the parameters are arrays of the same span, \cpp{std::ranges::swap} will behave as \cpp{std::ranges::swap_ranges} 25 | \item if the parameters are also not arrays, it will default to a move-swap 26 | \end{itemize} 27 | 28 | \begin{codebox}[]{\href{https://compiler-explorer.com/z/8GxdMxsan}{\ExternalLink}} 29 | \footnotesize Example of specializing and calling \cpp{std::ranges::swap}. 30 | \tcblower 31 | \cppfile{code_examples/algorithms/swap_range_code.h} 32 | \end{codebox} 33 | 34 | \subsection{\texorpdfstring{\cpp{std::iter_swap}}{\texttt{std::iter\_swap}}} 35 | \index{\cpp{std::iter_swap}} 36 | 37 | The \cpp{std::iter_swap} is an indirect swap, swapping values behind two forward iterators. 38 | 39 | \cppversions{\texttt{iter\_swap}}{\CC98}{\CC20}{N/A}{\CC20} 40 | 41 | \constraints{(\cpp{forward_iterator}, \cpp{forward_iterator}) (non-range)}{}{}{} 42 | 43 | \begin{codebox}[]{\href{https://compiler-explorer.com/z/77enEEh4c}{\ExternalLink}} 44 | \footnotesize Example demonstrating the use \cpp{std::iter_swap} in a generic two-way partition algorithm. The algorithm uses concepts to constrain the acceptable types of its arguments. 45 | \tcblower 46 | \cppfile{code_examples/algorithms/iter_swap_partition_code.h} 47 | \end{codebox} 48 | 49 | The range version extends the functionality to other dereferenceable objects. 50 | 51 | \begin{codebox}[]{\href{https://compiler-explorer.com/z/bxeP3PPaE}{\ExternalLink}} 52 | \footnotesize Example demonstrating the use of range version of \cpp{std::ranges::iter_swap} to swap the values pointed to by two instances of \cpp{std::unique_ptr}. 53 | \tcblower 54 | \cppfile{code_examples/algorithms/iter_swap_unique_ptr_code.h} 55 | \end{codebox} 56 | 57 | \subsection{\texorpdfstring{\cpp{std::swap_ranges}}{\texttt{std::swap\_ranges}}} 58 | \index{\cpp{std::swap_ranges}} 59 | 60 | The \cpp{std::swap_ranges} algorithm exchanges elements between two non-overlapping ranges (potentially from the same container). 61 | 62 | \cppversions{\texttt{swap\_ranges}}{\CC98}{\CC20}{\CC17}{\CC20} 63 | 64 | \begin{codebox}[]{\href{https://compiler-explorer.com/z/aEPe66f1E}{\ExternalLink}} 65 | \footnotesize Example of swapping the first three elements of an array with the last three elements using \cpp{std::swap_ranges}. Note the reversed order of elements due to the use of \cpp{rbegin}. 66 | \tcblower 67 | \cppfile{code_examples/algorithms/swap_ranges_code.h} 68 | \end{codebox} -------------------------------------------------------------------------------- /chapters/03_algorithms_11_boolean.tex: -------------------------------------------------------------------------------- 1 | \section{Boolean reductions} 2 | 3 | When reducing boolean expressions, we can take advantage of the early termination offered by boolean logic. The standard offers a set of three boolean reduction algorithms. 4 | 5 | \subsection{\texorpdfstring{\cpp{std::all_of}, \cpp{std::any_of}, \cpp{std::none_of}}{\texttt{std::all\_of}, \texttt{std::any\_of}, \texttt{std::none\_of}}} 6 | \index{\cpp{std::all_of}} 7 | \index{\cpp{std::any_of}} 8 | \index{\cpp{std::none_of}} 9 | 10 | The algorithms either require the elements to be convertible to bool or a predicate to be specified. 11 | 12 | \cppversions{\texttt{all\_of}}{\CC11}{\CC20}{\CC17}{\CC20} 13 | \cppversions{\texttt{any\_of}}{\CC11}{\CC20}{\CC17}{\CC20} 14 | \cppversions{\texttt{none\_of}}{\CC11}{\CC20}{\CC17}{\CC20} 15 | 16 | \constraints{\texttt{input\_range}}{\texttt{forward\_range}}{N/A}{\texttt{unary\_predicate}} 17 | 18 | The algorithms follow their naming in their behaviour. 19 | The \cpp{std::all_of} algorithm only returns true if no elements that evaluate to false are present. 20 | The \cpp{std::any_of} algorithm returns true if at least one element evaluates to true. 21 | Finally, \cpp{std::none_of} only returns true if no elements that evaluate true are present. 22 | 23 | \begin{center} 24 | \footnotesize 25 | \begin{tabular}{|m{\dimexpr14em}|m{\dimexpr.15\textwidth-2\tabcolsep}|m{\dimexpr.15\textwidth-2\tabcolsep}|m{\dimexpr.15\textwidth-2\tabcolsep}|m{\dimexpr.15\textwidth-2\tabcolsep}|} 26 | \hline 27 | \rowcolor{black!80} \diagbox[linecolor=white,innerrightsep=2.1em]{\textcolor{white}{algorithm}}{\textcolor{white}{elements}} & \textcolor{white}{all \texttt{true}} & \textcolor{white}{all \texttt{false}} & \textcolor{white}{mixed} & \textcolor{white}{empty} \\ 28 | \hline 29 | \texttt{all\_of} & \cpp{true} & \cpp{false} & \cpp{false} & \cpp{true} \\ 30 | \hline 31 | \texttt{any\_of} & \cpp{true} & \cpp{false} & \cpp{true} & \cpp{false} \\ 32 | \hline 33 | \texttt{none\_of} & \cpp{false} & \cpp{true} & \cpp{false} & \cpp{true} \\ 34 | \hline 35 | \end{tabular} 36 | \end{center} 37 | 38 | \begin{codebox}[]{\href{https://compiler-explorer.com/z/Kf1319e3j}{\ExternalLink}} 39 | \footnotesize Example demonstrating all three boolean reduction algorithms. 40 | \tcblower 41 | \cppfile{code_examples/algorithms/all_of_code.h} 42 | \end{codebox} -------------------------------------------------------------------------------- /chapters/03_algorithms_12_generators.tex: -------------------------------------------------------------------------------- 1 | \section{Generators} 2 | 3 | The C++ standard offers three types of generators: fill with copies of a value, fill with results of invoking a generator functor and fill with sequentially increasing values. 4 | 5 | \subsection{\texorpdfstring{\cpp{std::fill}, \cpp{std::generate}}{\texttt{std::fill}, \texttt{std::generate}}} 6 | \index{\cpp{std::fill}} 7 | \index{\cpp{std::generate}} 8 | 9 | The \cpp{std::fill} algorithm fills a range by consecutively assigning the given value to each element. 10 | The \cpp{std::generate} algorithm fills a range by consecutively assigning the result of the provided generator. 11 | 12 | \cppversions{\texttt{fill}, \texttt{generate}}{\CC98}{\CC20}{\CC17}{\CC20} 13 | 14 | \constraints{\texttt{forward\_range}}{\texttt{forward\_range}}{N/A}{\texttt{generator}} 15 | 16 | The generator provided to \cpp{std::generate} can be a non-regular function since \cpp{std::generate} guarantees strict left-to-right evaluation. 17 | 18 | \begin{codebox}[]{\href{https://compiler-explorer.com/z/6dnTG7Mqo}{\ExternalLink}} 19 | \footnotesize Example of using \cpp{std::fill} and \cpp{std::generate}. 20 | \tcblower 21 | \cppfile{code_examples/algorithms/generate_code.h} 22 | \end{codebox} 23 | 24 | \subsection{\texorpdfstring{\cpp{std::fill_n}, \cpp{std::generate_n}}{\texttt{std::fill\_n}, \texttt{std::generate\_n}}} 25 | \index{\cpp{std::fill_n}} 26 | \index{\cpp{std::generate_n}} 27 | 28 | The \cpp{std::fill_n} and \cpp{std::generate_n} are variants of \cpp{std::fill} and \newline\cpp{std::generate} that operate on ranges specified using the start iterator and number of elements. This behaviour allows the algorithms to be used with iterator adapters, such as \cpp{std::back_inserter}. 29 | 30 | \cppversions{\texttt{fill\_n, generate\_n}}{\CC98}{\CC20}{\CC17}{\CC20} 31 | \constraints{\texttt{output\_iterator}}{\texttt{forward\_iterator}}{N/A}{\texttt{generator}} 32 | 33 | \begin{codebox}[]{\href{https://compiler-explorer.com/z/qGcdezEaG}{\ExternalLink}} 34 | \footnotesize Example of using \cpp{std::fill_n} and \cpp{std::generate_n}. 35 | \tcblower 36 | \cppfile{code_examples/algorithms/fill_n_code.h} 37 | \end{codebox} 38 | 39 | \subsection{\texorpdfstring{\cpp{std::iota}}{\texttt{std::iota}}} 40 | \index{\cpp{std::iota}} 41 | 42 | The \cpp{std::iota} generates elements by consecutively assigning the result of applying the prefix \cpp{operator++}, starting with the initial value. 43 | 44 | \cppversions{\texttt{iota}}{\CC11}{\CC20}{N/A}{\CC23} 45 | \constraints{\texttt{forward\_range}}{}{}{} 46 | 47 | \begin{codebox}[]{\href{https://compiler-explorer.com/z/19WaoodvM}{\ExternalLink}} 48 | \footnotesize Example of using \cpp{std::iota}. 49 | \tcblower 50 | \cppfile{code_examples/algorithms/iota_code.h} 51 | \end{codebox} 52 | 53 | Notably, the \cpp{std::iota} algorithm is also an outlier in the support added with the C++20 standard. The \cpp{std::iota} algorithm did not receive a range version. However, we do have access to an iota view. 54 | 55 | \begin{codebox}[]{\href{https://compiler-explorer.com/z/qnz9hWxh8}{\ExternalLink}} 56 | \footnotesize Example of using both finite and infinite \cpp{std::views::iota}. 57 | \tcblower 58 | \cppfile{code_examples/algorithms/iota_view_code.h} 59 | \end{codebox} 60 | 61 | Here we take advantage of the finite view constructor \cpp{std::views::iota(1,10)} to establish the output size (line 3), which allows us to use the infinite view \texttt{std::views\-::iota(5)} for the second parameter. Functionally, we could swap even the second view for a finite one. However, this would impose an additional (and unnecessary) boundary check. 62 | -------------------------------------------------------------------------------- /chapters/04_views_00_main.tex: -------------------------------------------------------------------------------- 1 | \input{chapters/04_views_01_intro_ranges} 2 | \input{chapters/04_views_02_the_views} -------------------------------------------------------------------------------- /chapters/Y8_extra_topics.tex: -------------------------------------------------------------------------------- 1 | \chapter{Extras} 2 | 3 | \section{Unitialized memory} 4 | 5 | The heap and uninitialized memory algorithms represent a niche category in the overall algorithm arsenal, primarily because the standard library offers more convenient alternatives that, on the other hand, offer less control. Therefore, if you desire or need the control, you can use these algorithms as a foundation for your custom implementation. 6 | 7 | \subsection{Working with uninitialized memory} 8 | 9 | The second category of algorithms we will talk about today are algorithms that operate on uninitialized memory. Like the heap algorithms, you should prefer higher-level abstractions (e.g. polymorphic memory resource). However, when working with uninitialized memory, using these algorithms is preferable to implementing all the functionality from scratch. 10 | 11 | We first need to start with obtaining a block of uninitialized memory, and there are two valid approaches to that in C++. First, we can allocate an array of char with the appropriate alignment and size. Because char* is permitted to alias any other pointer type, we can reinterpret\_cast the resulting buffer to our desired type. 12 | 13 | Alternatively, we can use the global operator new, that since C++17 accepts an alignment parameter and returns a pointer to void. We can then cast this pointer to the desired type using static\_cast. 14 | 15 | Here is an example of allocating (and deallocating) space for ten std::string objects using the global operator new: 16 | 17 | \begin{codebox} 18 | \begin{cppcode} 19 | auto* begin = static_cast( 20 | ::operator new[](sizeof(std::string)*10, 21 | static_cast(alignof(std::string)))); 22 | 23 | ::operator delete[](begin, static_cast(alignof(std::string))); 24 | \end{cppcode} 25 | \end{codebox} 26 | 27 | This example contains a lot of spelling, so let’s step through: 28 | 29 | \begin{itemize} 30 | \item First, we need sizeof(std::string)*10 bytes, which is the first parameter of the new operator (line 2). 31 | \item Whenever allocating raw memory, we must ensure that the alignment requirement of the objects we intend to store in this memory is satisfied. 32 | \item To prevent overload resolution collisions, the new operator takes alignment as align\_val\_t instead of the size\_t returned by alignof, so we need to use an additional static\_cast (line3). 33 | \item Finally, we must cast the void pointer to the desired element type (line 1). 34 | \item When deleting, we need to make sure that we use the matching version (here, the array version) of operator delete and supply alignment following the same logic as previously mentioned. 35 | \end{itemize} 36 | 37 | Here is an example of using a char buffer on the stack: 38 | 39 | \begin{codebox} 40 | \begin{cppcode} 41 | alignas(alignof(std::string)) char buff[sizeof(std::string)*10]; 42 | auto *begin = reinterpret_cast(buff); 43 | \end{cppcode} 44 | \end{codebox} 45 | 46 | Because the memory lives on the stack, we do not need a deallocation step. 47 | 48 | Importantly, all we have in both snippets of code is raw memory. There are no objects of type std::string created or destroyed. Also, note the difference in static\_cast vs reinterpret\_cast. The static\_cast is for converting between related types (void* is related to all pointer types). The reinterpret\_cast is for converting between unrelated types (char* can alias any other pointer but is not a related type to std::string*). -------------------------------------------------------------------------------- /code_examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | set(CMAKE_C_COMPILER "/usr/bin/gcc") 4 | set(CMAKE_CXX_COMPILER "/usr/bin/g++") 5 | 6 | project(code_examples LANGUAGES CXX) 7 | 8 | set(CMAKE_CXX_FLAGS "-std=c++20 -Wall -Wextra -Werror -Wno-unused-variable -Wno-unused-but-set-variable -pedantic -fsanitize=address,undefined") 9 | 10 | set(CMAKE_VERBOSE_MAKEFILE OFF) 11 | 12 | add_subdirectory(introduction) 13 | add_subdirectory(algorithms) 14 | add_subdirectory(theory) 15 | add_subdirectory(extras) 16 | add_subdirectory(ranges) 17 | add_subdirectory(views) 18 | -------------------------------------------------------------------------------- /code_examples/algorithms/accumulate.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main() { 12 | #include "accumulate_code.h" 13 | assert(sum == 15); 14 | assert(product == 120); 15 | 16 | std::cerr << "."; 17 | } 18 | -------------------------------------------------------------------------------- /code_examples/algorithms/accumulate_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 2, 3, 4, 5}; 2 | auto sum = std::accumulate(data.begin(), data.end(), 0); 3 | // sum == 15 4 | 5 | auto product = std::accumulate(data.begin(), data.end(), 1, 6 | std::multiplies<>{}); 7 | // product == 120 -------------------------------------------------------------------------------- /code_examples/algorithms/accumulate_right.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main() { 12 | #include "accumulate_right_code.h" 13 | assert(left_fold == 8); 14 | assert(right_fold == 3); 15 | 16 | std::cerr << "."; 17 | } 18 | -------------------------------------------------------------------------------- /code_examples/algorithms/accumulate_right_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 2, 3, 4, 5}; 2 | 3 | auto left_fold = std::accumulate(data.begin(), data.end(), 0, 4 | [](int acc, int el) { 5 | return acc / 2 + el; 6 | }); 7 | // left_fold == 8 8 | 9 | auto right_fold = std::accumulate(data.rbegin(), data.rend(), 0, 10 | [](int acc, int el) { 11 | return acc / 2 + el; 12 | }); 13 | // right_fold == 3 -------------------------------------------------------------------------------- /code_examples/algorithms/adjacent_difference.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main() { 11 | #include "adjacent_difference_code.h" 12 | auto cmp = {2, 1, 2, 2, 4, 2}; 13 | assert(std::ranges::equal(data, cmp)); 14 | 15 | std::cerr << "."; 16 | } 17 | -------------------------------------------------------------------------------- /code_examples/algorithms/adjacent_difference_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{2, 3, 5, 7, 11, 13}; 2 | std::adjacent_difference(data.begin(), data.end(), data.begin()); 3 | // data == {2, 1, 2, 2, 4, 2} -------------------------------------------------------------------------------- /code_examples/algorithms/adjacent_difference_extra.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main() { 11 | #include "adjacent_difference_extra_code.h" 12 | auto cmp = {1, 1, 2, 3, 5, 8, 13, 21, 34, 55}; 13 | assert(std::ranges::equal(data, cmp)); 14 | 15 | std::cerr << "."; 16 | } 17 | -------------------------------------------------------------------------------- /code_examples/algorithms/adjacent_difference_extra_code.h: -------------------------------------------------------------------------------- 1 | std::vector data(10, 1); 2 | // data == {1, 1, 1, 1, 1, 1, 1, 1, 1, 1} 3 | 4 | std::adjacent_difference(data.begin(), std::prev(data.end()), 5 | std::next(data.begin()), std::plus()); 6 | // Fibonacci sequence: 7 | // data == {1, 1, 2, 3, 5, 8, 13, 21, 34, 55} -------------------------------------------------------------------------------- /code_examples/algorithms/adjacent_difference_par_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{2, 3, 5, 7, 11, 13}; 2 | std::vector out(data.size()); 3 | 4 | std::adjacent_difference(std::execution::par_unseq, 5 | data.begin(), data.end(), out.begin()); 6 | // out == {2, 1, 2, 2, 4, 2} -------------------------------------------------------------------------------- /code_examples/algorithms/adjacent_find.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main() { 11 | #include "adjacent_find_code.h" 12 | assert(it1 == data.begin()+3); 13 | assert(it2 == data.begin()+5); 14 | 15 | std::cerr << "."; 16 | } 17 | -------------------------------------------------------------------------------- /code_examples/algorithms/adjacent_find_code.h: -------------------------------------------------------------------------------- 1 | std::vector data = { 1, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9 }; 2 | auto it1 = std::adjacent_find(data.begin(), data.end()); 3 | // *it1 == 4, i.e. {4, 4} 4 | 5 | auto it2 = std::adjacent_find(data.begin(), data.end(), 6 | [](int l, int r) { return l + r > 10; }); 7 | // *it2 == 5, i.e. {5, 6} -------------------------------------------------------------------------------- /code_examples/algorithms/all_of.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | int main() { 13 | #include "all_of_code.h" 14 | assert(all_even); 15 | assert(one_negative); 16 | assert(none_odd); 17 | 18 | std::cerr << "."; 19 | } 20 | -------------------------------------------------------------------------------- /code_examples/algorithms/all_of_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{-2, 0, 2, 4, 6, 8}; 2 | 3 | bool all_even = std::ranges::all_of(data, 4 | [](int v) { return v % 2 == 0; }); 5 | // all_even == true 6 | 7 | bool one_negative = std::ranges::any_of(data, 8 | [](int v) { return std::signbit(v); }); 9 | // one_negative == true 10 | 11 | bool none_odd = std::ranges::none_of(data, 12 | [](int v) { return v % 2 != 0; }); 13 | // none_odd == true 14 | -------------------------------------------------------------------------------- /code_examples/algorithms/binary_search.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main() { 10 | #include "binary_search_code.h" 11 | assert(exists); 12 | assert(lb != ub); 13 | 14 | std::cerr << "."; 15 | } 16 | -------------------------------------------------------------------------------- /code_examples/algorithms/binary_search_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 2, 3, 4, 5, 6, 7, 8, 9}; 2 | 3 | bool exists = std::ranges::binary_search(data, 5); 4 | // exists == true 5 | auto [lb, ub] = std::ranges::equal_range(data, 5); 6 | // lb != ub, i.e. the value is in the range 7 | -------------------------------------------------------------------------------- /code_examples/algorithms/bsearch.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main() { 10 | #include "bsearch_code.h" 11 | assert(*static_cast(el1) == 1); 12 | assert(el2 == nullptr); 13 | 14 | std::cerr << "."; 15 | } 16 | -------------------------------------------------------------------------------- /code_examples/algorithms/bsearch_alternatives.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main() { 10 | #include "bsearch_alternatives_code.h" 11 | assert(exist); 12 | assert(candidate == &data[3]); 13 | assert(lb == &data[3]); 14 | assert(ub == &data[4]); 15 | 16 | std::cerr << "."; 17 | } 18 | -------------------------------------------------------------------------------- /code_examples/algorithms/bsearch_alternatives_code.h: -------------------------------------------------------------------------------- 1 | int data[] = {-2, -1, 0, 1, 2}; 2 | int size = sizeof data / sizeof(int); 3 | 4 | int value = 1; 5 | bool exist = std::binary_search(&data[0], &data[size], value); 6 | // exist == true 7 | 8 | auto candidate = std::lower_bound(&data[0], &data[size], value); 9 | if (candidate != &data[size] && *candidate == value) { 10 | // process element 11 | } 12 | 13 | auto [lb, ub] = std::equal_range(&data[0], &data[size], value); 14 | if (lb != ub) { 15 | // process equal elements 16 | } 17 | -------------------------------------------------------------------------------- /code_examples/algorithms/bsearch_code.h: -------------------------------------------------------------------------------- 1 | int data[] = {-2, -1, 0, 1, 2}; 2 | int size = sizeof data / sizeof(int); 3 | 4 | auto cmp = [](const void* left, const void* right){ 5 | int vl = *(const int*)left; 6 | int vr = *(const int*)right; 7 | 8 | if (vl < vr) return -1; 9 | if (vl > vr) return 1; 10 | return 0; 11 | }; 12 | 13 | int value = 1; 14 | void* el1 = bsearch(&value, data, size, sizeof(int), cmp); 15 | // *static_cast(el1) == 1 16 | 17 | value = 3; 18 | void *el2 = bsearch(&value, data, size, sizeof(int), cmp); 19 | // el2 == nullptr 20 | -------------------------------------------------------------------------------- /code_examples/algorithms/clamp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main() { 10 | #include "clamp_code.h" 11 | assert(a == 10); 12 | assert(b == 0); 13 | assert(c == 20); 14 | assert(x == 10); 15 | assert(y == 99); 16 | assert(z == 30); 17 | 18 | std::cerr << "."; 19 | } 20 | -------------------------------------------------------------------------------- /code_examples/algorithms/clamp_code.h: -------------------------------------------------------------------------------- 1 | int a = std::ranges::clamp(10, 0, 20); 2 | // a == 10 (0 < 10 && 10 < 20) 3 | 4 | int b = std::clamp(-20, 0, 20); 5 | // b == 0 (-20 < 0) 6 | 7 | int c = std::clamp(30, 0, 20); 8 | // c == 20 ( 30 > 20 ) 9 | 10 | int x = 10, y = 20, z = 30; 11 | int &w = const_cast(std::clamp(z, x, y)); 12 | w = 99; 13 | // x == 10, y == 99, z == 30 -------------------------------------------------------------------------------- /code_examples/algorithms/copy.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | int main() { 13 | #include "copy_code.h" 14 | std::vector cmp{ "b", "c", "a", "b", "c", "c" }; 15 | assert(std::ranges::equal(data, cmp)); 16 | 17 | std::cerr << "."; 18 | } 19 | -------------------------------------------------------------------------------- /code_examples/algorithms/copy_backward.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | int main() { 13 | #include "copy_backward_code.h" 14 | std::vector cmp1{ "a", "a", "b", "c", "d", "e" }; 15 | std::vector cmp2{"", "", "", "a", "b", "c", "d", "e", "f"}; 16 | 17 | assert(std::ranges::equal(cmp1, data)); 18 | assert(std::ranges::equal(cmp2, out)); 19 | 20 | std::cerr << "."; 21 | } 22 | -------------------------------------------------------------------------------- /code_examples/algorithms/copy_backward_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{ "a", "b", "c", "d", "e", "f"}; 2 | std::vector out(9, ""); 3 | // out == {"", "", "", "", "", "", "", "", ""} 4 | 5 | std::copy_backward(data.begin(), data.end(), out.end()); 6 | // out == {"", "", "", "a", "b", "c", "d", "e", "f"} 7 | 8 | std::copy_backward(data.begin(), std::prev(data.end()), data.end()); 9 | // data == { "a", "a", "b", "c", "d", "e" } -------------------------------------------------------------------------------- /code_examples/algorithms/copy_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{ "a", "b", "c", "d", "e", "f"}; 2 | 3 | std::copy(data.begin(), data.begin()+3, data.begin()+3); 4 | // data = { "a", "b", "c", "a", "b", "c" } 5 | 6 | // Overlapping case: 7 | std::copy(std::next(data.begin()), data.end(), data.begin()); 8 | // data = { "b", "c", "a", "b", "c", "c" } -------------------------------------------------------------------------------- /code_examples/algorithms/copy_if.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int main() { 14 | #include "copy_if_code.h" 15 | auto cmp1 = {2, 4, 6, 8}; 16 | assert(std::ranges::equal(even, cmp1)); 17 | auto cmp2 = {1, 3, 5, 7, 9}; 18 | assert(std::ranges::equal(odd, cmp2)); 19 | auto cmp3 = { 1, 2, 3, 4, 6, 7, 8, 9 }; 20 | assert(std::ranges::equal(no_five, cmp3)); 21 | 22 | std::cerr << "."; 23 | } 24 | -------------------------------------------------------------------------------- /code_examples/algorithms/copy_if_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{ 1, 2, 3, 4, 5, 6, 7, 8, 9}; 2 | std::vector even, odd, no_five; 3 | 4 | auto is_even = [](int v) { return v % 2 == 0; }; 5 | 6 | std::ranges::copy_if(data, std::back_inserter(even), is_even); 7 | // even == { 2, 4, 6, 8 } 8 | 9 | std::ranges::remove_copy_if(data, std::back_inserter(odd), is_even); 10 | // odd == { 1, 3, 5, 7, 9 } 11 | 12 | std::ranges::remove_copy(data, std::back_inserter(no_five), 5); 13 | // no_five == { 1, 2, 3, 4, 6, 7, 8, 9 } -------------------------------------------------------------------------------- /code_examples/algorithms/copy_n.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int main() { 14 | #include "copy_n_code.h" 15 | auto cmp = {1, 2, 3, 4, 5}; 16 | assert(std::ranges::equal(out, cmp)); 17 | 18 | std::cerr << "."; 19 | } 20 | -------------------------------------------------------------------------------- /code_examples/algorithms/copy_n_code.h: -------------------------------------------------------------------------------- 1 | std::list data{1, 2, 3, 4, 5, 6, 7, 8, 9}; 2 | std::vector out; 3 | 4 | std::copy_n(data.begin(), 5, std::back_inserter(out)); 5 | // out == { 1, 2, 3, 4, 5 } -------------------------------------------------------------------------------- /code_examples/algorithms/count.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | #include "count_code.h" 9 | assert(one_cnt == 3); 10 | assert(even_cnt == 4); 11 | 12 | std::cerr << "."; 13 | } 14 | -------------------------------------------------------------------------------- /code_examples/algorithms/count_code.h: -------------------------------------------------------------------------------- 1 | std::vector data = { 1, 2, 3, 2, 1, 2, 3, 2, 1 }; 2 | 3 | auto one_cnt = std::count(data.begin(), data.end(), 1); 4 | // one_cnt == 3 5 | 6 | auto even_cnt = std::count_if(data.begin(), data.end(), 7 | [](int v) { return v % 2 == 0; }); 8 | // even_cnt == 4 9 | -------------------------------------------------------------------------------- /code_examples/algorithms/create_at.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main() { 10 | #include "create_at_code.h" 11 | std::cerr << "."; 12 | } 13 | -------------------------------------------------------------------------------- /code_examples/algorithms/create_at_code.h: -------------------------------------------------------------------------------- 1 | alignas(alignof(std::string)) char mem[sizeof(std::string)]; 2 | auto *ptr = reinterpret_cast(mem); 3 | 4 | std::construct_at(ptr, 8, 'X'); 5 | // *ptr == "XXXXXXXX", ptr->length() == 8 6 | std::destroy_at(ptr); 7 | -------------------------------------------------------------------------------- /code_examples/algorithms/equal.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | #include "equal_code.h" 9 | assert(!test1); 10 | assert(test2); 11 | 12 | std::cerr << "."; 13 | } 14 | -------------------------------------------------------------------------------- /code_examples/algorithms/equal_code.h: -------------------------------------------------------------------------------- 1 | std::vector first = { 1, 2, 3, 4, 5 }; 2 | std::vector second = { -1, -2, -3, -4, -5 }; 3 | 4 | bool test1 = std::equal(first.begin(), first.end(), second.begin()); 5 | // test1 == false 6 | 7 | bool test2 = std::equal(first.begin(), first.end(), second.begin(), 8 | [](int l, int r) { return std::abs(l) == std::abs(r); }); 9 | // test2 == true 10 | -------------------------------------------------------------------------------- /code_examples/algorithms/equal_range.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main() { 10 | #include "equal_range_code.h" 11 | assert(*lb == 6); 12 | assert(*ub == 7); 13 | assert(std::distance(data.begin(), lb) == 5); 14 | assert(std::distance(data.begin(), ub) == 8); 15 | 16 | std::cerr << "."; 17 | } 18 | -------------------------------------------------------------------------------- /code_examples/algorithms/equal_range_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 2, 3, 4, 5, 6, 6, 6, 7, 8, 9}; 2 | 3 | auto [lb, ub] = std::equal_range(data.begin(), data.end(), 6); 4 | // std::distance(data.begin(), lb) == 5, *lb == 6 5 | // std::distance(data.begin(), ub) == 8, *ub == 7 6 | -------------------------------------------------------------------------------- /code_examples/algorithms/equal_with_range.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | #include "equal_with_range_code.h" 9 | assert(test1); 10 | assert(!test2); 11 | assert(pair_it.first == first.end()); 12 | assert(pair_it.second == second.begin()+5); 13 | 14 | std::cerr << "."; 15 | } 16 | -------------------------------------------------------------------------------- /code_examples/algorithms/equal_with_range_code.h: -------------------------------------------------------------------------------- 1 | std::vector first = { 1, 2, 3, 4, 5 }; 2 | std::vector second = { 1, 2, 3, 4, 5, 6 }; 3 | 4 | bool test1 = std::equal(first.begin(), first.end(), second.begin()); 5 | // test1 == true, cannot detect mismatch in number of elements 6 | 7 | bool test2 = std::equal(first.begin(), first.end(), 8 | second.begin(), second.end()); 9 | // test2 == false, different number of elements -> not equal. 10 | 11 | auto pair_it = std::mismatch(first.begin(), first.end(), 12 | second.begin(), second.end()); 13 | // pair_it.first == first.end() 14 | // *pair_it.second == 6 -------------------------------------------------------------------------------- /code_examples/algorithms/exclusive_scan.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main() { 12 | #include "exclusive_scan_code.h" 13 | auto cmp = {1, 1, 2, 6, 24, 120}; 14 | assert(std::ranges::equal(out, cmp)); 15 | 16 | std::cerr << "."; 17 | } 18 | -------------------------------------------------------------------------------- /code_examples/algorithms/exclusive_scan_code.h: -------------------------------------------------------------------------------- 1 | std::vector src{1, 2, 3, 4, 5, 6}; 2 | std::vector out; 3 | 4 | std::exclusive_scan(src.begin(), src.end(), 5 | std::back_inserter(out), 0); 6 | // out == {0, 1, 3, 6, 10, 15} 7 | 8 | std::exclusive_scan(src.begin(), src.end(), 9 | out.begin(), 1, std::multiplies<>{}); 10 | // out == {1, 1, 2, 6, 24, 120} -------------------------------------------------------------------------------- /code_examples/algorithms/fill_n.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | int main() { 13 | #include "fill_n_code.h" 14 | auto cmp = {11, 11, 11, 11, 11, 7, 7, 7, 7, 7}; 15 | assert(std::ranges::equal(data, cmp)); 16 | 17 | std::cerr << "."; 18 | } 19 | -------------------------------------------------------------------------------- /code_examples/algorithms/fill_n_code.h: -------------------------------------------------------------------------------- 1 | std::vector data; 2 | // data == {} 3 | 4 | std::fill_n(std::back_inserter(data), 5, 11); 5 | // data == {11, 11, 11, 11, 11} 6 | 7 | std::ranges::generate_n(std::back_inserter(data), 5, 8 | []() { return 7; }); 9 | // data == {11, 11, 11, 11, 11, 7, 7, 7, 7, 7} -------------------------------------------------------------------------------- /code_examples/algorithms/find.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main() { 11 | #include "find_code.h" 12 | std::vector cmp{"John", "Doe", "April", "1", "1900"}; 13 | assert(std::ranges::equal(out, cmp)); 14 | 15 | std::cerr << "."; 16 | } 17 | -------------------------------------------------------------------------------- /code_examples/algorithms/find_code.h: -------------------------------------------------------------------------------- 1 | std::string data = "John;Doe;April;1;1900;"; 2 | auto it = data.begin(), token = data.begin(); 3 | std::vector out; 4 | 5 | while ((token = find(it, data.end(), ';')) != data.end()) { 6 | out.push_back(""); 7 | std::copy(it, token, std::back_inserter(out.back())); 8 | it = std::next(token); 9 | } 10 | // out == { "John", "Doe", "April", "1", "1900" } -------------------------------------------------------------------------------- /code_examples/algorithms/find_first_of.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main() { 11 | #include "find_first_of_code.h" 12 | assert(it == haystack.begin()+2); 13 | 14 | std::cerr << "."; 15 | } 16 | -------------------------------------------------------------------------------- /code_examples/algorithms/find_first_of_code.h: -------------------------------------------------------------------------------- 1 | std::vector haystack = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 2 | std::vector needles = { 7, 5, 3 }; 3 | 4 | auto it = std::find_first_of(haystack.begin(), haystack.end(), 5 | needles.begin(), needles.end()); 6 | // *it == 3, i.e. haystack[2] -------------------------------------------------------------------------------- /code_examples/algorithms/find_if.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main() { 11 | #include "find_if_code.h" 12 | assert(out == "hello world!"); 13 | 14 | std::cerr << "."; 15 | } 16 | -------------------------------------------------------------------------------- /code_examples/algorithms/find_if_code.h: -------------------------------------------------------------------------------- 1 | std::string data = " hello world! "; 2 | 3 | auto begin = std::find_if_not(data.begin(), data.end(), 4 | [](char c) { return isspace(c); }); 5 | if (begin == data.end()) // only spaces 6 | return 0; 7 | 8 | std::string out; 9 | std::copy(begin, 10 | std::find_if_not(data.rbegin(), data.rend(), 11 | [](char c) { return isspace(c); } 12 | ).base(), 13 | std::back_inserter(out)); 14 | // out == "hello world!" -------------------------------------------------------------------------------- /code_examples/algorithms/for_each.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | { 9 | #include "for_each_code_range.h" 10 | assert(sum == 45); 11 | } 12 | { 13 | #include "for_each_code_simple.h" 14 | assert(sum == 45); 15 | } 16 | { 17 | #include "for_each_code_parallel.h" 18 | } 19 | { 20 | #include "for_each_code_cpp20.h" 21 | assert(sum == 10); 22 | } 23 | std::cerr << "."; 24 | } 25 | -------------------------------------------------------------------------------- /code_examples/algorithms/for_each_code_cpp20.h: -------------------------------------------------------------------------------- 1 | struct Custom { 2 | explicit Custom(double value) : value_(value) {} 3 | double getValue() { return value_; } 4 | private: 5 | double value_; 6 | }; 7 | 8 | std::vector data(10, Custom{1.0}); 9 | 10 | double sum = 0; 11 | std::ranges::for_each(data, 12 | [&sum](auto v) { sum += v; }, 13 | &Custom::getValue); 14 | // sum == 10.0 15 | -------------------------------------------------------------------------------- /code_examples/algorithms/for_each_code_parallel.h: -------------------------------------------------------------------------------- 1 | struct Custom { 2 | void expensive_operation() { 3 | // ... 4 | } 5 | }; 6 | 7 | std::vector data(10); 8 | 9 | std::for_each(std::execution::par_unseq, 10 | data.begin(), data.end(), 11 | [](Custom& el) { 12 | el.expensive_operation(); 13 | }); -------------------------------------------------------------------------------- /code_examples/algorithms/for_each_code_range.h: -------------------------------------------------------------------------------- 1 | std::vector data = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 2 | int sum = 0; 3 | for(auto el : data) { 4 | sum += el; 5 | } 6 | // sum == 45 -------------------------------------------------------------------------------- /code_examples/algorithms/for_each_code_simple.h: -------------------------------------------------------------------------------- 1 | std::vector data = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 2 | int sum = 0; 3 | std::for_each(data.begin(), data.end(), [&sum](int el) { 4 | sum += el; 5 | }); 6 | // sum == 45 -------------------------------------------------------------------------------- /code_examples/algorithms/for_each_n.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | inline constexpr const size_t MAIN_SEATS = 2; 8 | inline constexpr const size_t PAGE_SIZE = 2; 9 | 10 | struct Player { 11 | std::string display_name; 12 | std::string contact_email; 13 | uint32_t score; 14 | }; 15 | 16 | std::vector get_rankings() { 17 | return { 18 | {"user1", "user1_email", 10}, 19 | {"user2", "user2_email", 1}, 20 | {"user3", "user3_email", 15}, 21 | {"user4", "user4_email", 2}, 22 | }; 23 | } 24 | 25 | std::vector invitations; 26 | 27 | void send_invitation_to_main_tournament(const Player& player) { 28 | invitations.push_back(player); 29 | }; 30 | 31 | struct FinalScore { 32 | uint32_t page; 33 | std::string name; 34 | uint32_t score; 35 | }; 36 | 37 | std::vector final_score; 38 | 39 | void store_final_score(uint32_t page, const std::string& name, uint32_t score) { 40 | final_score.push_back(FinalScore{page, name, score}); 41 | }; 42 | 43 | 44 | int main() { 45 | #include "for_each_n_code.h" 46 | assert(invitations[0].display_name == "user3"); 47 | assert(invitations[1].display_name == "user1"); 48 | 49 | assert(final_score[0].page == 0 && final_score[0].name == "user3"); 50 | assert(final_score[1].page == 0 && final_score[1].name == "user1"); 51 | assert(final_score[2].page == 1 && final_score[2].name == "user4"); 52 | assert(final_score[3].page == 1 && final_score[3].name == "user2"); 53 | 54 | std::cerr << "."; 55 | } 56 | -------------------------------------------------------------------------------- /code_examples/algorithms/for_each_n_code.h: -------------------------------------------------------------------------------- 1 | std::vector final_ranking = get_rankings(); 2 | std::ranges::sort(final_ranking, std::greater<>(), &Player::score); 3 | 4 | std::for_each_n(std::execution::par_unseq, 5 | final_ranking.begin(), 6 | std::min(MAIN_SEATS, final_ranking.size()), 7 | send_invitation_to_main_tournament); 8 | 9 | auto it = final_ranking.begin(); 10 | uint32_t page = 0; 11 | while (it != final_ranking.end()) { 12 | size_t cnt = std::min(PAGE_SIZE, size_t(final_ranking.end() - it)); 13 | std::for_each_n(it, cnt, [page](const Player& p) { 14 | store_final_score(page, p.display_name, p.score); 15 | }); 16 | page++; 17 | it += cnt; 18 | } -------------------------------------------------------------------------------- /code_examples/algorithms/generate.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | int main() { 13 | #include "generate_code.h" 14 | 15 | auto cmp = {0, 1, 2, 3, 4}; 16 | assert(std::ranges::equal(data, cmp)); 17 | 18 | std::cerr << "."; 19 | } 20 | -------------------------------------------------------------------------------- /code_examples/algorithms/generate_code.h: -------------------------------------------------------------------------------- 1 | std::vector data(5, 0); 2 | // data == {0, 0, 0, 0, 0} 3 | 4 | std::fill(data.begin(), data.end(), 11); 5 | // data == {11, 11, 11, 11, 11} 6 | 7 | std::ranges::generate(data, []() { return 5; }); 8 | // data == {5, 5, 5, 5, 5} 9 | 10 | // iota-like 11 | std::ranges::generate(data, [i = 0]() mutable { return i++; }); 12 | // data == {0, 1, 2, 3, 4} -------------------------------------------------------------------------------- /code_examples/algorithms/includes.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main() { 10 | #include "includes_code.h" 11 | assert(test); 12 | 13 | std::cerr << "."; 14 | } 15 | -------------------------------------------------------------------------------- /code_examples/algorithms/includes_code.h: -------------------------------------------------------------------------------- 1 | std::vector letters('z'-'a'+1,'\0'); 2 | std::iota(letters.begin(), letters.end(), 'a'); 3 | std::string input = "the quick brown fox jumps over the lazy dog"; 4 | std::ranges::sort(input); 5 | 6 | bool test = std::ranges::includes(input, letters); 7 | // test == true -------------------------------------------------------------------------------- /code_examples/algorithms/inclusive_scan.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main() { 12 | #include "inclusive_scan_code.h" 13 | auto cmp = {1, 2, 6, 24, 120, 720}; 14 | assert(std::ranges::equal(out, cmp)); 15 | 16 | std::cerr << "."; 17 | } 18 | -------------------------------------------------------------------------------- /code_examples/algorithms/inclusive_scan_code.h: -------------------------------------------------------------------------------- 1 | std::vector src{1, 2, 3, 4, 5, 6}; 2 | std::vector out; 3 | 4 | std::inclusive_scan(src.begin(), src.end(), 5 | std::back_inserter(out)); 6 | // out == {1, 3, 6, 10, 15, 21} 7 | 8 | std::inclusive_scan(src.begin(), src.end(), 9 | out.begin(), std::multiplies<>{}, 1); 10 | // out == {1, 2, 6, 24, 120, 720} -------------------------------------------------------------------------------- /code_examples/algorithms/inner_product.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main() { 12 | #include "inner_product_code.h" 13 | assert(total_area == 70); 14 | 15 | std::cerr << "."; 16 | } 17 | -------------------------------------------------------------------------------- /code_examples/algorithms/inner_product_code.h: -------------------------------------------------------------------------------- 1 | std::vector heights{1, 2, 3, 4, 5}; 2 | std::vector widths{2, 3, 4, 5, 6}; 3 | 4 | auto total_area = std::inner_product(heights.begin(), heights.end(), 5 | widths.begin(), 0); 6 | // total_area == 70 -------------------------------------------------------------------------------- /code_examples/algorithms/inner_product_one.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main() { 12 | #include "inner_product_one_code.h" 13 | assert(sum_of_diffs == 13); 14 | 15 | std::cerr << "."; 16 | } 17 | -------------------------------------------------------------------------------- /code_examples/algorithms/inner_product_one_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{6, 4, 3, 7, 2, 1}; 2 | auto sum_of_diffs = std::inner_product( 3 | data.begin(), std::prev(data.end()), 4 | std::next(data.begin()), 0, 5 | std::plus<>{}, 6 | [](int left, int right) { return std::abs(left-right); } 7 | ); 8 | // sum_of_diffs == 13 -------------------------------------------------------------------------------- /code_examples/algorithms/inplace_merge.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main() { 11 | #include "inplace_merge_code.h" 12 | auto cmp = {1, 2, 3, 4, 5, 6}; 13 | assert(std::ranges::equal(range, cmp)); 14 | 15 | std::cerr << "."; 16 | } 17 | -------------------------------------------------------------------------------- /code_examples/algorithms/inplace_merge_code.h: -------------------------------------------------------------------------------- 1 | std::vector range{1, 3, 5, 2, 4, 6}; 2 | std::inplace_merge(range.begin(), range.begin()+3, range.end()); 3 | // range == { 1, 2, 3, 4, 5, 6 } 4 | -------------------------------------------------------------------------------- /code_examples/algorithms/iota.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | int main() { 13 | #include "iota_code.h" 14 | auto cmp = {-4, -3, -2, -1, 0, 1, 2, 3, 4}; 15 | assert(std::ranges::equal(data, cmp)); 16 | 17 | std::cerr << "."; 18 | } 19 | -------------------------------------------------------------------------------- /code_examples/algorithms/iota_code.h: -------------------------------------------------------------------------------- 1 | std::vector data(9, 0); 2 | // data == {0, 0, 0, 0, 0, 0, 0, 0, 0} 3 | 4 | std::iota(data.begin(), data.end(), -4); 5 | // data == {-4, -3, -2, -1, 0, 1, 2, 3, 4} -------------------------------------------------------------------------------- /code_examples/algorithms/iota_view.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | int main() { 13 | #include "iota_view_code.h" 14 | auto cmp = { 6, 8, 10, 12, 14, 16, 18, 20, 22 }; 15 | assert(std::ranges::equal(data, cmp)); 16 | 17 | std::cerr << "."; 18 | } 19 | -------------------------------------------------------------------------------- /code_examples/algorithms/iota_view_code.h: -------------------------------------------------------------------------------- 1 | std::vector data; 2 | 3 | std::ranges::transform(std::views::iota(1, 10), std::views::iota(5), 4 | std::back_inserter(data), std::plus<>{}); 5 | // data == { 6, 8, 10, 12, 14, 16, 18, 20, 22 } 6 | -------------------------------------------------------------------------------- /code_examples/algorithms/is_heap.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | #include "is_heap_code.h" 9 | 10 | assert(test1 == false); 11 | assert(test2 == true); 12 | assert(it1 == std::next(data.begin())); 13 | assert(it2 == data.end()); 14 | 15 | std::cerr << "."; 16 | } 17 | -------------------------------------------------------------------------------- /code_examples/algorithms/is_heap_code.h: -------------------------------------------------------------------------------- 1 | std::vector data = {1, 2, 3, 4, 5, 6, 7, 8, 9}; 2 | 3 | bool test1 = std::is_heap(data.begin(), data.end()); 4 | // test1 == false 5 | auto it1 = std::is_heap_until(data.begin(), data.end()); 6 | // *it1 == 2 7 | 8 | std::make_heap(data.begin(), data.end()); 9 | 10 | bool test2 = std::is_heap(data.begin(), data.end()); 11 | // test2 == true 12 | auto it2 = std::is_heap_until(data.begin(), data.end()); 13 | // it2 == data.end() 14 | -------------------------------------------------------------------------------- /code_examples/algorithms/is_partitioned.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | #include "is_partitioned_code.h" 9 | assert(test1); 10 | assert(test2); 11 | 12 | std::cerr << "."; 13 | } 14 | -------------------------------------------------------------------------------- /code_examples/algorithms/is_partitioned_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{2, 4, 6, 7, 9, 11}; 2 | 3 | auto is_even = [](int v) { return v % 2 == 0; }; 4 | bool test1 = std::ranges::is_partitioned(data, is_even); 5 | // test1 == true 6 | 7 | bool test2 = true; 8 | for (int i = 0; i < 16; ++i) { 9 | test2 = test2 && std::is_partitioned(data.begin(), data.end(), 10 | [&i](int v) { return v < i; }); 11 | } 12 | // test2 == true -------------------------------------------------------------------------------- /code_examples/algorithms/is_permutation.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main() { 12 | #include "is_permutation_code.h" 13 | assert(is_sorted); 14 | assert(is_permutation); 15 | std::cerr << "."; 16 | } 17 | -------------------------------------------------------------------------------- /code_examples/algorithms/is_permutation_code.h: -------------------------------------------------------------------------------- 1 | std::vector data = { 8, 1, 7, 3, 4, 6, 2, 5}; 2 | for (size_t i = 0; i < data.size()-1; ++i) 3 | for (size_t j = i+1; j < data.size(); ++j) 4 | if (data[i] > data[j]) 5 | std::swap(data[i], data[j]); 6 | 7 | bool is_sorted = std::ranges::is_sorted(data); 8 | // is_sorted == true 9 | 10 | bool is_permutation = std::ranges::is_permutation(data, 11 | std::vector{1, 2, 3, 4, 5, 6, 7, 8}); 12 | // is_permutation == true 13 | -------------------------------------------------------------------------------- /code_examples/algorithms/is_sorted.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | #include "is_sorted_code.h" 9 | assert(test1); 10 | assert(!test2); 11 | assert(test3); 12 | std::cerr << "."; 13 | } 14 | -------------------------------------------------------------------------------- /code_examples/algorithms/is_sorted_code.h: -------------------------------------------------------------------------------- 1 | std::vector data1 = {1, 2, 3, 4, 5}; 2 | bool test1 = std::is_sorted(data1.begin(), data1.end()); 3 | // test1 == true 4 | 5 | std::vector data2 = {5, 4, 3, 2, 1}; 6 | bool test2 = std::ranges::is_sorted(data2); 7 | // test2 == false 8 | bool test3 = std::ranges::is_sorted(data2, std::greater<>{}); 9 | // test3 == true 10 | -------------------------------------------------------------------------------- /code_examples/algorithms/is_sorted_until.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | #include "is_sorted_until_code.h" 9 | assert(it == data.begin()+3); 10 | assert(*it == 2); 11 | std::cerr << "."; 12 | } 13 | -------------------------------------------------------------------------------- /code_examples/algorithms/is_sorted_until_code.h: -------------------------------------------------------------------------------- 1 | std::vector data {1, 5, 9, 2, 4, 6}; 2 | auto it = std::is_sorted_until(data.begin(), data.end()); 3 | // *it == 2 -------------------------------------------------------------------------------- /code_examples/algorithms/iter_swap_partition.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "iter_swap_partition_code.h" 8 | 9 | int main() { 10 | std::vector data = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 11 | auto it = partition(data.begin(), data.end(), [](int v) { 12 | return v%2 == 0; 13 | }); 14 | assert(it == (data.begin() + 4)); 15 | auto cmp = {1, 2, 3, 4, 5, 6, 7, 8, 9}; 16 | assert(std::is_permutation(data.begin(), data.end(), cmp.begin())); 17 | assert(std::is_partitioned(data.begin(), data.end(), [](int v) { 18 | return v%2 == 0; 19 | })); 20 | std::cerr << "."; 21 | } 22 | -------------------------------------------------------------------------------- /code_examples/algorithms/iter_swap_partition_code.h: -------------------------------------------------------------------------------- 1 | template 2 | requires std::forward_iterator 3 | && std::indirectly_swappable 4 | && std::predicate 5 | auto partition(It first, It last, Cond cond) { 6 | while (first != last && cond(first)) ++first; 7 | if (first == last) return last; 8 | 9 | for (auto it = std::next(first); it != last; it++) { 10 | if (!cond(it)) continue; 11 | 12 | std::iter_swap(it, first); 13 | ++first; 14 | } 15 | return first; 16 | } 17 | -------------------------------------------------------------------------------- /code_examples/algorithms/iter_swap_unique_ptr.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | #include "iter_swap_unique_ptr_code.h" 8 | assert(p1.get() == p1_pre); 9 | assert(p2.get() == p2_pre); 10 | assert(*p1 == 2); 11 | assert(*p2 == 1); 12 | std::cerr << "."; 13 | } 14 | -------------------------------------------------------------------------------- /code_examples/algorithms/iter_swap_unique_ptr_code.h: -------------------------------------------------------------------------------- 1 | auto p1 = std::make_unique(1); 2 | auto p2 = std::make_unique(2); 3 | int* p1_pre = p1.get(); 4 | int* p2_pre = p2.get(); 5 | 6 | std::ranges::iter_swap(p1, p2); 7 | // p1.get() == p1_pre, *p1 == 2 8 | // p2.get() == p2_pre, *p2 == 1 -------------------------------------------------------------------------------- /code_examples/algorithms/lexicographical_compare.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | #include "lexicographical_compare_code.h" 9 | assert(cmp1); 10 | assert(cmp2); 11 | assert(cmp3); 12 | assert(cmp4); 13 | 14 | 15 | std::cerr << "."; 16 | } 17 | -------------------------------------------------------------------------------- /code_examples/algorithms/lexicographical_compare_code.h: -------------------------------------------------------------------------------- 1 | std::vector range1{1, 2, 3}; 2 | std::vector range2{1, 3}; 3 | std::vector range3{1, 3, 1}; 4 | 5 | bool cmp1 = std::lexicographical_compare(range1.begin(), range1.end(), 6 | range2.begin(), range2.end()); 7 | // same as 8 | bool cmp2 = range1 < range2; 9 | // cmp1 == cmp2 == true 10 | 11 | bool cmp3 = std::lexicographical_compare(range2.begin(), range2.end(), 12 | range3.begin(), range3.end()); 13 | // same as 14 | bool cmp4 = range2 < range3; 15 | // cmp3 == cmp4 == true 16 | -------------------------------------------------------------------------------- /code_examples/algorithms/lexicographical_compare_three_way.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | #include "lexicographical_compare_three_way_code.h" 9 | assert(cmp == std::strong_ordering::less); 10 | 11 | std::cerr << "."; 12 | } 13 | -------------------------------------------------------------------------------- /code_examples/algorithms/lexicographical_compare_three_way_code.h: -------------------------------------------------------------------------------- 1 | std::vector data1 = { 1, 1, 1 }; 2 | std::vector data2 = { 1, 2, 3 }; 3 | 4 | auto cmp = std::lexicographical_compare_three_way( 5 | data1.begin(), data1.end(), 6 | data2.begin(), data2.end()); 7 | // cmp == std::strong_ordering::less -------------------------------------------------------------------------------- /code_examples/algorithms/lexicographical_compare_useful.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | #include "lexicographical_compare_useful_code.h" 9 | assert(cmp1); 10 | assert(cmp2); 11 | assert(!cmp3); 12 | 13 | std::cerr << "."; 14 | } 15 | -------------------------------------------------------------------------------- /code_examples/algorithms/lexicographical_compare_useful_code.h: -------------------------------------------------------------------------------- 1 | // for demonstration only, prefer std::array 2 | int x[] = {1, 2, 3}; 3 | int y[] = {1, 4}; 4 | 5 | bool cmp1 = std::lexicographical_compare(&x[0], &x[3], &y[0], &y[2]); 6 | // cmp1 == true 7 | 8 | std::vector names1{"Zod", "Celeste"}; 9 | std::vector names2{"Adam", "Maria"}; 10 | 11 | bool cmp2 = std::ranges::lexicographical_compare(names1, names2, 12 | [](const std::string& left, const std::string& right) { 13 | return left.length() < right.length(); 14 | }); 15 | // different than 16 | bool cmp3 = names1 < names2; // Zod > Adam 17 | // cmp2 == true, cmp3 == false 18 | -------------------------------------------------------------------------------- /code_examples/algorithms/lower_bound.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | struct ExamResult { 9 | std::string student_name; 10 | uint16_t score; 11 | }; 12 | 13 | const std::vector& get_results() { 14 | static std::vector data{ 15 | {"a", 20}, {"b", 48}, {"c", 49}, {"d", 60}, {"e", 98}, {"f", 99}, {"g", 100} 16 | }; 17 | return data; 18 | } 19 | 20 | int main() { 21 | #include "lower_bound_code.h" 22 | assert(lb->score == 49); 23 | assert(ub->score == 100); 24 | 25 | std::cerr << "."; 26 | } 27 | -------------------------------------------------------------------------------- /code_examples/algorithms/lower_bound_code.h: -------------------------------------------------------------------------------- 1 | const std::vector& results = get_results(); 2 | 3 | auto lb = std::ranges::lower_bound(results, 49, {}, 4 | &ExamResult::score); 5 | // First element for which: it->score >= 49 6 | auto ub = std::ranges::upper_bound(results, 99, {}, 7 | &ExamResult::score); 8 | // First element for which: 99 < it->score 9 | 10 | for (auto it = results.begin(); it != lb; it++) { 11 | // Process exam fails, upto 48 12 | } 13 | 14 | for (auto it = lb; it != ub; it++) { 15 | // Process exam passes, 49-99 16 | } 17 | 18 | for (auto it = ub; it != results.end(); it++) { 19 | // Process exams with honors, 100+ 20 | } 21 | -------------------------------------------------------------------------------- /code_examples/algorithms/lower_bound_set.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main() { 10 | #include "lower_bound_set_code.h" 11 | assert(*lb == 6); 12 | assert(*ub == 7); 13 | assert(std::distance(data.begin(), lb) == 5); 14 | assert(std::distance(data.begin(), ub) == 8); 15 | 16 | std::cerr << "."; 17 | } 18 | -------------------------------------------------------------------------------- /code_examples/algorithms/lower_bound_set_code.h: -------------------------------------------------------------------------------- 1 | std::multiset data{1, 2, 3, 4, 5, 6, 6, 6, 7, 8, 9}; 2 | 3 | auto lb = data.lower_bound(6); 4 | // std::distance(data.begin(), lb) == 5, *lb == 6 5 | 6 | auto ub = data.upper_bound(6); 7 | // std::distance(data.begin(), ub) == 8, *ub == 7 8 | -------------------------------------------------------------------------------- /code_examples/algorithms/make_heap.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | #include "make_heap_code.h" 9 | assert(std::is_heap(data.begin(), data.end(), std::greater<>{})); 10 | 11 | std::cerr << "."; 12 | } 13 | -------------------------------------------------------------------------------- /code_examples/algorithms/make_heap_code.h: -------------------------------------------------------------------------------- 1 | std::vector data = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 2 | 3 | std::make_heap(data.begin(), data.end()); 4 | // data == {9, 8, 7, 4, 5, 6, 3, 2, 1} - different ordering possible 5 | // 9 >= 8, 9 >= 7 6 | // 8 >= 4, 8 >= 5 7 | // 7 >= 6, 7 >= 3 8 | // ... 9 | 10 | std::make_heap(data.begin(), data.end(), std::greater<>{}); 11 | // data == {1, 2, 3, 4, 5, 6, 7, 8, 9} - different ordering possible 12 | // 1 <= 2, 1 <= 3 13 | // 2 <= 4, 2 <= 5 14 | // 3 <= 6, 3 <= 7 15 | // ... -------------------------------------------------------------------------------- /code_examples/algorithms/merge.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main() { 10 | #include "merge_code.h" 11 | std::vector test = {{0, "second"}, {1, "first"}, {2, "first"}, {2, "second"}, {3, "first"}, {4, "second"}}; 12 | assert(std::equal(result.begin(), result.end(), test.begin(), 13 | [](const auto& left, const auto& right) { 14 | return left.value == right.value && left.label == right.label; 15 | })); 16 | 17 | std::cerr << "."; 18 | } 19 | -------------------------------------------------------------------------------- /code_examples/algorithms/merge_code.h: -------------------------------------------------------------------------------- 1 | struct LabeledValue { 2 | int value; 3 | std::string label; 4 | }; 5 | 6 | std::vector data1{ 7 | {1, "first"}, {2, "first"}, {3, "first"}}; 8 | std::vector data2{ 9 | {0, "second"}, {2, "second"}, {4, "second"}}; 10 | 11 | std::vector result; 12 | auto cmp = [](const auto& left, const auto& right) 13 | { return left.value < right.value; }; 14 | 15 | std::ranges::merge(data1, data2, std::back_inserter(result), cmp); 16 | // result == {0, second}, {1, first}, {2, first}, 17 | // {2, second}, {3, first}, {4, second} -------------------------------------------------------------------------------- /code_examples/algorithms/merge_par.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main() { 11 | #include "merge_par_code.h" 12 | auto cmp = {1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 8}; 13 | assert(std::ranges::equal(out, cmp)); 14 | 15 | std::cerr << "."; 16 | } 17 | -------------------------------------------------------------------------------- /code_examples/algorithms/merge_par_code.h: -------------------------------------------------------------------------------- 1 | std::vector data1{1, 2, 3, 4, 5, 6}; 2 | std::vector data2{3, 4, 5, 6, 7, 8}; 3 | 4 | std::vector out(data1.size()+data2.size(), 0); 5 | std::merge(std::execution::par_unseq, 6 | data1.begin(), data1.end(), 7 | data2.begin(), data2.end(), 8 | out.begin()); 9 | // out == {1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 8} 10 | -------------------------------------------------------------------------------- /code_examples/algorithms/min_element.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main() { 10 | #include "min_element_code.h" 11 | assert(*i == -2); 12 | assert(*j == 5); 13 | assert(*k.first == -2); 14 | assert(*k.second == 5); 15 | 16 | std::cerr << "."; 17 | } 18 | -------------------------------------------------------------------------------- /code_examples/algorithms/min_element_code.h: -------------------------------------------------------------------------------- 1 | std::vector data = { 5, 3, -2 , 0}; 2 | auto i = std::min_element(data.begin(), data.end()); 3 | // *i == -2 (i.e. data[2]) 4 | auto j = std::max_element(data.begin(), data.end()); 5 | // *j == 5 (i.e. data[0]) 6 | 7 | auto k = std::minmax_element(data.begin(), data.end()); 8 | // *k.first == -2, *k.second == 5 9 | -------------------------------------------------------------------------------- /code_examples/algorithms/min_element_dangling.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main() { 11 | #include "min_element_dangling_code.h" 12 | static_assert(std::is_same::value); 13 | assert(*j == 3); 14 | 15 | std::cerr << "."; 16 | } 17 | -------------------------------------------------------------------------------- /code_examples/algorithms/min_element_dangling_code.h: -------------------------------------------------------------------------------- 1 | auto i = std::ranges::min_element(std::vector{5, 3, -2, 0}); 2 | // decltype(i) == std::ranges::dangling 3 | 4 | std::vector data = { 5, 3, -2 , 0}; 5 | auto j = std::ranges::min_element(std::span(data.begin(), 2)); 6 | // *j == 3, std::span is a borrowed_range 7 | -------------------------------------------------------------------------------- /code_examples/algorithms/min_max.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | #include "min_max_code.h" 10 | assert(min == 10); 11 | assert(greeting == "hello universe"); 12 | assert(k == 20); 13 | std::cerr << "."; 14 | } 15 | -------------------------------------------------------------------------------- /code_examples/algorithms/min_max_code.h: -------------------------------------------------------------------------------- 1 | int x = 10, y = 20; 2 | int min = std::min(x, y); 3 | // min == 10 4 | 5 | std::string hello = "hello", world = "world"; 6 | std::string& universe = 7 | const_cast(std::max(hello, world)); 8 | universe = "universe"; 9 | 10 | std::string greeting = hello + " " + world; 11 | // greeting == "hello universe" 12 | 13 | int j = 20; 14 | auto& k = std::max(5, j); 15 | // IMPORTANT! only works because 5 < j 16 | // would produce dangling reference otherwise 17 | // k == 20 18 | -------------------------------------------------------------------------------- /code_examples/algorithms/minmax.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | #include "minmax_code.h" 10 | assert(first.rank == 1); 11 | assert(second.rank == 2); 12 | assert(result.first == 5); 13 | assert(result.second == 10); 14 | std::cerr << "."; 15 | } 16 | -------------------------------------------------------------------------------- /code_examples/algorithms/minmax_code.h: -------------------------------------------------------------------------------- 1 | struct X { 2 | int rank; 3 | auto operator <=> (const X&) const = default; 4 | }; 5 | 6 | X a{1}, b{2}; 7 | auto [first, second] = std::minmax(b, a); 8 | // first.rank == 1, second.rank == 2 9 | 10 | // Operating on prvalues requires capture by value 11 | std::pair result = std::minmax(5, 10); 12 | // result.first = 5, result.second = 10 -------------------------------------------------------------------------------- /code_examples/algorithms/minmax_extra.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main() { 10 | #include "minmax_extra_code.h" 11 | assert(min == -2); 12 | assert(minmax.first == -2); 13 | assert(minmax.second == 5); 14 | assert(max == 5); 15 | 16 | std::cerr << "."; 17 | } 18 | -------------------------------------------------------------------------------- /code_examples/algorithms/minmax_extra_code.h: -------------------------------------------------------------------------------- 1 | auto min = std::min({5, 3, -2, 0}); 2 | // min == -2 3 | 4 | auto minmax = std::minmax({5, 3, -2, 0}); 5 | // minmax.first == -2, minmax.second == 5 6 | 7 | std::list data{5, 3, -2, 0}; 8 | auto max = std::ranges::max(data); 9 | // max == 5 -------------------------------------------------------------------------------- /code_examples/algorithms/mismatch.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | #include "mismatch_code.h" 9 | assert(it_pair.first == first.begin()+2); 10 | assert(it_pair.second == second.begin()+2); 11 | 12 | std::cerr << "."; 13 | } 14 | -------------------------------------------------------------------------------- /code_examples/algorithms/mismatch_code.h: -------------------------------------------------------------------------------- 1 | std::vector first = { 1, 2, 3, 4, 5 }; 2 | std::vector second = { 1, 2, 2, 4, 5 }; 3 | 4 | auto it_pair = std::mismatch(first.begin(), first.end(), 5 | second.begin()); 6 | // *it_pair.first == 3, *it_pair.second == 2 -------------------------------------------------------------------------------- /code_examples/algorithms/move.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | int main() { 13 | #include "move_code.h" 14 | std::vector cmp{ "", "", "", "a", "b", "c" }; 15 | assert(std::ranges::equal(data, cmp)); 16 | 17 | std::cerr << "."; 18 | } 19 | -------------------------------------------------------------------------------- /code_examples/algorithms/move_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{ "a", "b", "c", "d", "e", "f"}; 2 | 3 | std::move(data.begin(), data.begin()+3, data.begin()+3); 4 | // data = { ?, ?, ?, "a", "b", "c" } 5 | // Note: most implementations will set 6 | // a moved-out-of std::string to empty. -------------------------------------------------------------------------------- /code_examples/algorithms/move_nomove.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | int main() { 13 | #include "move_nomove_code.h" 14 | std::cerr << "."; 15 | } 16 | -------------------------------------------------------------------------------- /code_examples/algorithms/move_nomove_code.h: -------------------------------------------------------------------------------- 1 | struct CopyOnly { 2 | CopyOnly() = default; 3 | CopyOnly(const CopyOnly&) = default; 4 | CopyOnly& operator=(const CopyOnly&) { 5 | std::cout << "Copy assignment.\n"; 6 | return *this; 7 | }; 8 | }; 9 | 10 | std::vector test(6); 11 | 12 | std::move(test.begin(), test.begin()+3, test.begin()+3); 13 | // 3x Copy assignment 14 | -------------------------------------------------------------------------------- /code_examples/algorithms/next_permutation.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main() { 12 | #include "next_permutation_code.h" 13 | auto cmp = {1, 2, 3}; 14 | assert(std::ranges::equal(data, cmp)); 15 | } 16 | -------------------------------------------------------------------------------- /code_examples/algorithms/next_permutation_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 2, 3}; 2 | do { 3 | // iterate over: 4 | // 1, 2, 3 5 | // 1, 3, 2 6 | // 2, 1, 3 7 | // 2, 3, 1 8 | // 3, 1, 2 9 | // 3, 2, 1 10 | } while (std::next_permutation(data.begin(), data.end())); 11 | // data == {1, 2, 3} 12 | -------------------------------------------------------------------------------- /code_examples/algorithms/nth_element.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | #include "nth_element_code.h" 10 | assert(data[7] == 2); 11 | auto cmp = { 3, 4, 5, 6, 7, 8, 9}; 12 | assert(std::is_permutation(data.begin(), data.begin()+7, cmp.begin())); 13 | 14 | std::cerr << "."; 15 | } 16 | -------------------------------------------------------------------------------- /code_examples/algorithms/nth_element_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{9, 1, 8, 2, 7, 3, 6, 4, 5}; 2 | std::nth_element(data.begin(), data.begin() + 4, data.end()); 3 | // data[4] == 5, data[0..3] < data[4] 4 | 5 | std::nth_element(data.begin(), data.begin() + 7, data.end(), 6 | std::greater<>()); 7 | // data[7] == 2, data[0..6] > data[7] -------------------------------------------------------------------------------- /code_examples/algorithms/partial_sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | #include "partial_sort_code.h" 9 | 10 | auto cmp = {9, 8, 7, 6, 5, 4, 3, 2, 1}; 11 | assert(std::is_permutation(data.begin(), data.end(), cmp.begin())); 12 | assert(std::equal(data.begin(), data.begin()+3, cmp.begin())); 13 | std::cerr << "."; 14 | } 15 | -------------------------------------------------------------------------------- /code_examples/algorithms/partial_sort_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{9, 8, 7, 6, 5, 4, 3, 2, 1}; 2 | std::partial_sort(data.begin(), data.begin()+3, data.end()); 3 | // data == {1, 2, 3, -unspecified order-} 4 | 5 | std::ranges::partial_sort(data, data.begin()+3, std::greater<>()); 6 | // data == {9, 8, 7, -unspecified order-} -------------------------------------------------------------------------------- /code_examples/algorithms/partial_sort_copy.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | #include "partial_sort_copy_code.h" 10 | } 11 | -------------------------------------------------------------------------------- /code_examples/algorithms/partial_sort_copy_code.h: -------------------------------------------------------------------------------- 1 | // input == "0 1 2 3 4 5 6 7 8 9" 2 | std::vector top(3); 3 | 4 | auto input = std::istream_iterator(std::cin); 5 | auto cnt = std::counted_iterator(input, 10); 6 | 7 | std::ranges::partial_sort_copy(cnt, std::default_sentinel, 8 | top.begin(), top.end(), 9 | std::greater<>{}); 10 | // top == { 9, 8, 7 } -------------------------------------------------------------------------------- /code_examples/algorithms/partial_sum.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main() { 12 | #include "partial_sum_code.h" 13 | auto cmp1 = {1, 2, 3, 4, 5, 6}; 14 | auto cmp2 = {1, 2, 6, 24, 120, 720}; 15 | assert(std::ranges::equal(data, cmp1)); 16 | assert(std::ranges::equal(out, cmp2)); 17 | 18 | std::cerr << "."; 19 | } 20 | -------------------------------------------------------------------------------- /code_examples/algorithms/partial_sum_code.h: -------------------------------------------------------------------------------- 1 | std::vector data(6, 1); 2 | // data == {1, 1, 1, 1, 1, 1} 3 | 4 | std::partial_sum(data.begin(), data.end(), data.begin()); 5 | // data == {1, 2, 3, 4, 5, 6} 6 | 7 | std::vector out; 8 | std::partial_sum(data.begin(), data.end(), 9 | std::back_inserter(out), std::multiplies<>{}); 10 | // out == {1, 2, 6, 24, 120, 720} -------------------------------------------------------------------------------- /code_examples/algorithms/partition.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | struct ExamResult { 11 | std::string student_name; 12 | uint16_t score; 13 | friend auto operator<=>(const ExamResult&, const ExamResult&)= default; 14 | }; 15 | 16 | std::vector get_results() { 17 | return { 18 | {"a", 10}, {"b", 40}, {"c", 50}, 19 | {"d", 60}, {"e", 70}, {"f", 80} 20 | }; 21 | } 22 | 23 | int main() { 24 | #include "partition_code.h" 25 | 26 | std::vector cmp1 = { {"c", 50}, {"d", 60}, {"e", 70}, {"f", 80}}; 27 | std::vector cmp2 = { {"a", 10}, {"b", 40}}; 28 | 29 | assert(std::is_permutation(results.begin(), pp, cmp1.begin(), cmp1.end())); 30 | assert(std::is_permutation(pp, results.end(), cmp2.begin(), cmp2.end())); 31 | 32 | std::cerr << "."; 33 | } 34 | -------------------------------------------------------------------------------- /code_examples/algorithms/partition_code.h: -------------------------------------------------------------------------------- 1 | std::vector results = get_results(); 2 | 3 | auto pp = std::partition(results.begin(), results.end(), 4 | [threshold = 49](const auto& r) { 5 | return r.score >= threshold; 6 | }); 7 | 8 | // process passing students 9 | for (auto it = results.begin(); it != pp; ++it) { 10 | std::cout << "[PASS] " << it->student_name << "\n"; 11 | } 12 | // process failed students 13 | for (auto it = pp; it != results.end(); ++it) { 14 | std::cout << "[FAIL] " << it->student_name << "\n"; 15 | } -------------------------------------------------------------------------------- /code_examples/algorithms/partition_copy.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | #include "partition_copy_code.h" 9 | auto cmp1 = {2, 4, 6}; 10 | auto cmp2 = {1, 3, 5}; 11 | assert(std::equal(even.begin(), even.end(), cmp1.begin())); 12 | assert(std::equal(odd.begin(), odd.end(), cmp2.begin())); 13 | 14 | std::cerr << "."; 15 | } 16 | -------------------------------------------------------------------------------- /code_examples/algorithms/partition_copy_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{2, 4, 6, 1, 3, 5}; 2 | auto is_even = [](int v) { return v % 2 == 0; }; 3 | 4 | std::vector even, odd; 5 | std::partition_copy(data.begin(), data.end(), 6 | std::back_inserter(even), 7 | std::back_inserter(odd), 8 | is_even); 9 | 10 | // even == {2, 4, 6} 11 | // odd == {1, 3, 5} -------------------------------------------------------------------------------- /code_examples/algorithms/partition_point.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main() { 10 | #include "partition_point_code.h" 11 | assert(*pp == 5); 12 | 13 | std::cerr << "."; 14 | } 15 | -------------------------------------------------------------------------------- /code_examples/algorithms/partition_point_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 2, 3, 4, 5, 6, 7, 8, 9}; 2 | auto pp = std::partition_point(data.begin(), data.end(), 3 | [](int v) { return v < 5; }); 4 | // *pp == 5 5 | -------------------------------------------------------------------------------- /code_examples/algorithms/push_heap.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | #include "push_heap_code.h" 9 | assert(std::is_heap(data.begin(), data.end()-2)); 10 | assert(data[4] == 7); 11 | assert(data[5] == 9); 12 | 13 | std::cerr << "."; 14 | } 15 | -------------------------------------------------------------------------------- /code_examples/algorithms/push_heap_code.h: -------------------------------------------------------------------------------- 1 | std::vector data = { 1, 1, 2, 2 }; 2 | std::make_heap(data.begin(), data.end()); 3 | // data == { 2, 2, 1, 1} - different ordering possible 4 | 5 | // Push 9 to the heap 6 | data.push_back(9); 7 | // data == { [heap_part], 9 } 8 | std::push_heap(data.begin(), data.end()); 9 | // data == { 9, 2, 1, 1, 2 } - different ordering possible 10 | 11 | // Push 7 to the heap 12 | data.push_back(7); 13 | // data == { [heap_part], 7 } 14 | std::push_heap(data.begin(), data.end()); 15 | // data == { 9, 2, 7, 1, 2, 1 } - different ordering possible 16 | 17 | std::pop_heap(data.begin(), data.end()); 18 | // data == { [heap_part], 9 } 19 | std::pop_heap(data.begin(), std::prev(data.end())); 20 | // data == { [heap_part], 7, 9 } -------------------------------------------------------------------------------- /code_examples/algorithms/qsort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | #include "qsort_code.h" 10 | auto cmp = {-8, -1, 1, 2, 7, 9}; 11 | assert(std::equal(&data[0], &data[size], cmp.begin())); 12 | std::cerr << "."; 13 | } 14 | -------------------------------------------------------------------------------- /code_examples/algorithms/qsort_code.h: -------------------------------------------------------------------------------- 1 | int data[] = {2, 1, 9, -1, 7, -8}; 2 | int size = sizeof data / sizeof(int); 3 | 4 | qsort(data, size, sizeof(int), 5 | [](const void* left, const void* right){ 6 | int vl = *(const int*)left; 7 | int vr = *(const int*)right; 8 | 9 | if (vl < vr) return -1; 10 | if (vl > vr) return 1; 11 | return 0; 12 | }); 13 | // data == {-8, -1, 1, 2, 7, 9} -------------------------------------------------------------------------------- /code_examples/algorithms/qsort_not.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | #include "qsort_not_code.h" 10 | auto cmp = {-8, -1, 1, 2, 7, 9}; 11 | assert(std::equal(&data[0], &data[size], cmp.begin())); 12 | std::cerr << "."; 13 | } 14 | -------------------------------------------------------------------------------- /code_examples/algorithms/qsort_not_code.h: -------------------------------------------------------------------------------- 1 | int data[] = {2, 1, 9, -1, 7, -8}; 2 | int size = sizeof data / sizeof(int); 3 | 4 | std::sort(&data[0], &data[size], std::less<>()); 5 | // data == {-8, -1, 1, 2, 7, 9} -------------------------------------------------------------------------------- /code_examples/algorithms/reduce.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main() { 12 | #include "reduce_code.h" 13 | assert(sum == 15); 14 | assert(product == 120); 15 | 16 | std::cerr << "."; 17 | } 18 | -------------------------------------------------------------------------------- /code_examples/algorithms/reduce_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 2, 3, 4, 5}; 2 | 3 | auto sum = std::reduce(data.begin(), data.end(), 0); 4 | // sum == 15 5 | 6 | sum = std::reduce(std::execution::par_unseq, 7 | data.begin(), data.end(), 0); 8 | // sum == 15 9 | 10 | auto product = std::reduce(data.begin(), data.end(), 1, 11 | std::multiplies<>{}); 12 | // product == 120 13 | 14 | product = std::reduce(std::execution::par_unseq, 15 | data.begin(), data.end(), 1, std::multiplies<>{}); 16 | // product == 120 -------------------------------------------------------------------------------- /code_examples/algorithms/reduce_noinit.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main() { 12 | #include "reduce_noinit_code.h" 13 | assert(final_duck.sound == "QuackQuackQuack"); 14 | 15 | std::cerr << "."; 16 | } 17 | -------------------------------------------------------------------------------- /code_examples/algorithms/reduce_noinit_code.h: -------------------------------------------------------------------------------- 1 | struct Duck { 2 | std::string sound = "Quack"; 3 | Duck operator+(const Duck& right) const { 4 | return {sound+right.sound}; 5 | } 6 | }; 7 | 8 | std::vector data(2, Duck{}); 9 | Duck final_duck = std::reduce(data.begin(), data.end()); 10 | // final_duck.sound == "QuackQuackQuack" -------------------------------------------------------------------------------- /code_examples/algorithms/remove.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main() { 11 | #include "remove_code.h" 12 | auto cmp = {1, 5}; 13 | assert(std::ranges::equal(data, cmp)); 14 | 15 | std::cerr << "."; 16 | } 17 | -------------------------------------------------------------------------------- /code_examples/algorithms/remove_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 2, 3, 4, 5}; 2 | 3 | auto it = std::remove(data.begin(), data.end(), 3); 4 | // data == { 1, 2, 4, 5, ?} 5 | 6 | data.erase(it, data.end()); // Erase sub-range 7 | // data == {1, 2, 4, 5} 8 | 9 | auto is_even = [](int v) { return v % 2 == 0; }; 10 | it = std::remove_if(data.begin(), data.end(), is_even); 11 | // data == {1, 5, ?, ?} 12 | 13 | data.resize(it - data.begin()); // Random Access Ranges only 14 | // data = {1, 5} 15 | -------------------------------------------------------------------------------- /code_examples/algorithms/replace.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main() { 11 | #include "replace_code.h" 12 | auto cmp = {-1, 2, -1, 0, -1, 6, -1}; 13 | assert(std::ranges::equal(data, cmp)); 14 | 15 | std::cerr << "."; 16 | } 17 | -------------------------------------------------------------------------------- /code_examples/algorithms/replace_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 2, 3, 4, 5, 6, 7}; 2 | 3 | std::ranges::replace(data, 4, 0); 4 | // data == {1, 2, 3, 0, 5, 6, 7} 5 | 6 | auto is_odd = [](int v) { return v % 2 != 0; }; 7 | std::ranges::replace_if(data, is_odd, -1); 8 | // data == {-1, 2, -1, 0, -1, 6, -1} 9 | -------------------------------------------------------------------------------- /code_examples/algorithms/replace_copy.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int main() { 15 | #include "replace_copy_code.h" 16 | auto cmp1 = { 1, 2, 3, 4, 10, 6, 7, 8, 9 }; 17 | auto cmp2 = { 1, -1, 3, -1, 5, -1, 7, -1, 9 }; 18 | assert(std::ranges::equal(out, cmp1)); 19 | assert(std::ranges::equal(odd, cmp2)); 20 | 21 | 22 | std::cerr << "."; 23 | } 24 | -------------------------------------------------------------------------------- /code_examples/algorithms/replace_copy_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 2, 3, 4, 5, 6, 7, 8, 9}; 2 | std::vector out, odd; 3 | 4 | std::ranges::replace_copy(data, std::back_inserter(out), 5, 10); 5 | // out == { 1, 2, 3, 4, 10, 6, 7, 8, 9 } 6 | 7 | auto is_even = [](int v) { return v % 2 == 0; }; 8 | std::ranges::replace_copy_if(data, std::back_inserter(odd), 9 | is_even, -1); 10 | // odd == { 1, -1, 3, -1, 5, -1, 7, -1, 9 } -------------------------------------------------------------------------------- /code_examples/algorithms/reverse.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main() { 11 | #include "reverse_code.h" 12 | auto cmp = {7, 6, 5, 4, 3, 2, 1}; 13 | assert(std::ranges::equal(data, cmp)); 14 | 15 | std::cerr << "."; 16 | } 17 | -------------------------------------------------------------------------------- /code_examples/algorithms/reverse_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 2, 3, 4, 5, 6, 7}; 2 | 3 | std::reverse(data.begin(), data.end()); 4 | // data == {7, 6, 5, 4, 3, 2, 1} 5 | 6 | for (auto it = data.rbegin(); it != data.rend(); ++it) { 7 | // iterate over: 1, 2, 3, 4, 5, 6, 7 8 | } 9 | -------------------------------------------------------------------------------- /code_examples/algorithms/reverse_copy.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int main() { 15 | #include "reverse_copy_code.h" 16 | auto cmp = { 9, 8, 7, 6, 5, 4, 3, 2, 1 }; 17 | assert(std::ranges::equal(out, cmp)); 18 | 19 | std::cerr << "."; 20 | } 21 | -------------------------------------------------------------------------------- /code_examples/algorithms/reverse_copy_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 2, 3, 4, 5, 6, 7, 8, 9}; 2 | std::vector out; 3 | 4 | std::ranges::reverse_copy(data, std::back_inserter(out)); 5 | // out == { 9, 8, 7, 6, 5, 4, 3, 2, 1 } -------------------------------------------------------------------------------- /code_examples/algorithms/rotate.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main() { 12 | #include "rotate_code.h" 13 | auto cmp = {4, 5, 6, 7, 1, 2, 3}; 14 | assert(std::ranges::equal(data, cmp)); 15 | 16 | std::cerr << "."; 17 | } 18 | -------------------------------------------------------------------------------- /code_examples/algorithms/rotate_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 2, 3, 4, 5, 6, 7}; 2 | std::rotate(data.begin(), data.begin()+3, data.end()); 3 | // data == {4, 5, 6, 7, 1, 2, 3} 4 | -------------------------------------------------------------------------------- /code_examples/algorithms/rotate_copy.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int main() { 15 | #include "rotate_copy_code.h" 16 | auto cmp = { 5, 6, 7, 8, 9, 1, 2, 3, 4 }; 17 | assert(std::ranges::equal(out, cmp)); 18 | 19 | std::cerr << "."; 20 | } 21 | -------------------------------------------------------------------------------- /code_examples/algorithms/rotate_copy_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 2, 3, 4, 5, 6, 7, 8, 9}; 2 | std::vector out; 3 | 4 | std::ranges::rotate_copy(data, data.begin() + 4, 5 | std::back_inserter(out)); 6 | // out == { 5, 6, 7, 8, 9, 1, 2, 3, 4 } -------------------------------------------------------------------------------- /code_examples/algorithms/sample.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int main() { 15 | #include "sample_code.h" 16 | assert(out.size() == 5); 17 | assert(std::is_sorted(out.begin(), out.end())); 18 | 19 | std::cerr << "."; 20 | } 21 | -------------------------------------------------------------------------------- /code_examples/algorithms/sample_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 2, 3, 4, 5, 6, 7, 8, 9}; 2 | std::vector out; 3 | 4 | std::sample(data.begin(), data.end(), std::back_inserter(out), 5 | 5, std::mt19937{std::random_device{}()}); 6 | // e.g. out == {2, 3, 4, 5, 9} 7 | // guaranteed ascending, because source range is ascending 8 | -------------------------------------------------------------------------------- /code_examples/algorithms/search.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main() { 11 | #include "search_code.h" 12 | 13 | assert(it1 == haystack.begin()+1); 14 | assert(it2 == haystack.begin()+4); 15 | 16 | std::cerr << "."; 17 | } 18 | -------------------------------------------------------------------------------- /code_examples/algorithms/search_code.h: -------------------------------------------------------------------------------- 1 | std::string haystack = "abbabba"; 2 | std::string needle = "bba"; 3 | 4 | auto it1 = std::search(haystack.begin(), haystack.end(), 5 | needle.begin(), needle.end()); 6 | // it1..end == "bbabba" 7 | 8 | auto it2 = std::find_end(haystack.begin(), haystack.end(), 9 | needle.begin(), needle.end()); 10 | // it2..end == "bba" -------------------------------------------------------------------------------- /code_examples/algorithms/search_n.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main() { 11 | #include "search_n_code.h" 12 | assert(it1 == data.begin()+4); 13 | assert(it2 == data.begin()+3); 14 | assert(it3 == data.end()); 15 | 16 | std::cerr << "."; 17 | } 18 | -------------------------------------------------------------------------------- /code_examples/algorithms/search_n_code.h: -------------------------------------------------------------------------------- 1 | std::vector data = { 1, 0, 5, 8, 3, 3, 2 }; 2 | 3 | auto it1 = std::search_n(data.begin(), data.end(), 2, 3); 4 | // *it1 == 3, i.e. {3, 3} 5 | 6 | auto it2 = std::search_n(data.begin(), data.end(), 3, 3, 7 | [](int l, int r) { return l % 5 == r % 5; }); 8 | // *it2 == 8, i.e. {8, 3, 3} 9 | 10 | auto it3 = std::search_n(data.begin(), data.end(), 2, 0); 11 | // it3 == data.end(), i.e. not found -------------------------------------------------------------------------------- /code_examples/algorithms/searchers.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main() { 12 | #include "searchers_code.h" 13 | assert(it1 == haystack.begin()+1); 14 | assert(it2 == haystack.begin()+1); 15 | assert(it3 == haystack.begin()+1); 16 | 17 | std::cerr << "."; 18 | } 19 | -------------------------------------------------------------------------------- /code_examples/algorithms/searchers_code.h: -------------------------------------------------------------------------------- 1 | std::string haystack = "abbabba"; 2 | std::string needle = "bba"; 3 | 4 | auto it1 = std::search(haystack.begin(), haystack.end(), 5 | std::default_searcher(needle.begin(), needle.end())); 6 | 7 | auto it2 = std::search(haystack.begin(), haystack.end(), 8 | std::boyer_moore_searcher(needle.begin(), needle.end())); 9 | 10 | auto it3 = std::search(haystack.begin(), haystack.end(), 11 | std::boyer_moore_horspool_searcher(needle.begin(), needle.end())); 12 | // it1 == it2 == it3 -------------------------------------------------------------------------------- /code_examples/algorithms/set_difference.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main() { 12 | #include "set_difference_code.h" 13 | auto cmp = {1, 2, 6}; 14 | assert(std::ranges::equal(difference, cmp)); 15 | 16 | std::cerr << "."; 17 | } 18 | -------------------------------------------------------------------------------- /code_examples/algorithms/set_difference_code.h: -------------------------------------------------------------------------------- 1 | std::vector data1{1, 2, 3, 4, 5, 6}; 2 | std::vector data2{3, 4, 5}; 3 | 4 | std::vector difference; 5 | std::ranges::set_difference(data1, data2, 6 | std::back_inserter(difference)); 7 | // difference == {1, 2, 6} 8 | -------------------------------------------------------------------------------- /code_examples/algorithms/set_difference_equal.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main() { 12 | #include "set_difference_equal_code.h" 13 | assert(equal_difference.size() == 2); 14 | assert(equal_difference[0].label == "first_c"); 15 | assert(equal_difference[1].label == "first_d"); 16 | 17 | std::cerr << "."; 18 | } 19 | -------------------------------------------------------------------------------- /code_examples/algorithms/set_difference_equal_code.h: -------------------------------------------------------------------------------- 1 | struct Labeled { 2 | std::string label; 3 | int value; 4 | }; 5 | 6 | auto cmp = [](const auto& l, const auto& r) { 7 | return l.value < r.value; 8 | }; 9 | 10 | std::vector equal1{{"first_a", 1}, {"first_b", 1}, 11 | {"first_c", 1}, {"first_d", 1}}; 12 | std::vector equal2{{"second_a", 1}, {"second_b", 1}}; 13 | 14 | std::vector equal_difference; 15 | std::ranges::set_difference(equal1, equal2, 16 | std::back_inserter(equal_difference), cmp); 17 | // equal_difference == { {"first_c", 1}, {"first_d", 1} } 18 | -------------------------------------------------------------------------------- /code_examples/algorithms/set_intersection.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main() { 12 | #include "set_intersection_code.h" 13 | auto cmp = {2, 4}; 14 | assert(std::ranges::equal(intersection, cmp)); 15 | 16 | std::cerr << "."; 17 | } 18 | -------------------------------------------------------------------------------- /code_examples/algorithms/set_intersection_code.h: -------------------------------------------------------------------------------- 1 | std::vector data1{1, 2, 3, 4, 5}; 2 | std::vector data2{2, 4, 6}; 3 | 4 | std::vector intersection; 5 | std::ranges::set_intersection(data1, data2, 6 | std::back_inserter(intersection)); 7 | // intersection == {2, 4} 8 | -------------------------------------------------------------------------------- /code_examples/algorithms/set_intersection_equal.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main() { 12 | #include "set_intersection_equal_code.h" 13 | std::ranges::transform(intersection, 14 | std::ostream_iterator(std::cout, ", "), 15 | &Labeled::label); 16 | 17 | assert(intersection.size() == 2); 18 | assert(intersection[0].label == "first_a"); 19 | assert(intersection[1].label == "first_b"); 20 | 21 | std::cerr << "."; 22 | } 23 | -------------------------------------------------------------------------------- /code_examples/algorithms/set_intersection_equal_code.h: -------------------------------------------------------------------------------- 1 | struct Labeled { 2 | std::string label; 3 | int value; 4 | }; 5 | 6 | auto cmp = [](const auto& l, const auto& r) { 7 | return l.value < r.value; 8 | }; 9 | 10 | std::vector equal1{{"first_a", 1}, {"first_b", 2}}; 11 | std::vector equal2{{"second_a", 1}, {"second_b", 2}, 12 | {"second_c", 2}}; 13 | 14 | std::vector intersection; 15 | std::ranges::set_intersection(equal1, equal2, 16 | std::back_inserter(intersection), cmp); 17 | // intersection == { {"first_a", 1}, {"first_b", 2} } 18 | -------------------------------------------------------------------------------- /code_examples/algorithms/set_symmetric_difference.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main() { 12 | #include "set_symmetric_difference_code.h" 13 | auto cmp = {1, 4, 6, 9}; 14 | assert(std::ranges::equal(symmetric_difference, cmp)); 15 | 16 | std::cerr << "."; 17 | } 18 | -------------------------------------------------------------------------------- /code_examples/algorithms/set_symmetric_difference_code.h: -------------------------------------------------------------------------------- 1 | std::vector data1{1, 3, 5, 7, 9}; 2 | std::vector data2{3, 4, 5, 6, 7}; 3 | 4 | std::vector symmetric_difference; 5 | std::ranges::set_symmetric_difference(data1, data2, 6 | std::back_inserter(symmetric_difference)); 7 | // symmetric_difference == {1, 4, 6, 9} 8 | -------------------------------------------------------------------------------- /code_examples/algorithms/set_symmetric_difference_equal.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main() { 12 | #include "set_symmetric_difference_equal_code.h" 13 | assert(equal_symmetric_difference.size() == 2); 14 | assert(equal_symmetric_difference[0].label == "second_b"); 15 | assert(equal_symmetric_difference[1].label == "first_c"); 16 | 17 | std::cerr << "."; 18 | } 19 | -------------------------------------------------------------------------------- /code_examples/algorithms/set_symmetric_difference_equal_code.h: -------------------------------------------------------------------------------- 1 | struct Labeled { 2 | std::string label; 3 | int value; 4 | }; 5 | 6 | auto cmp = [](const auto& l, const auto& r) { 7 | return l.value < r.value; 8 | }; 9 | 10 | std::vector equal1{{"first_a", 1}, {"first_b", 2}, 11 | {"first_c", 2}}; 12 | std::vector equal2{{"second_a", 1}, {"second_b", 1}, 13 | {"second_c", 2}}; 14 | 15 | std::vector equal_symmetric_difference; 16 | std::ranges::set_symmetric_difference(equal1, equal2, 17 | std::back_inserter(equal_symmetric_difference), cmp); 18 | // equal_symmetric_difference == { {"second_b", 1}, {"first_c", 2} } -------------------------------------------------------------------------------- /code_examples/algorithms/set_union.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main() { 12 | #include "set_union_code.h" 13 | auto cmp = {1, 2, 3, 4, 5, 6}; 14 | assert(std::ranges::equal(set_union, cmp)); 15 | 16 | std::cerr << "."; 17 | } 18 | -------------------------------------------------------------------------------- /code_examples/algorithms/set_union_code.h: -------------------------------------------------------------------------------- 1 | std::vector data1{1, 3, 5}; 2 | std::vector data2{2, 4, 6}; 3 | 4 | std::vector set_union; 5 | std::ranges::set_union(data1, data2, 6 | std::back_inserter(set_union)); 7 | // set_union == { 1, 2, 3, 4, 5, 6 } -------------------------------------------------------------------------------- /code_examples/algorithms/set_union_equal.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main() { 12 | #include "set_union_equal_code.h" 13 | assert(equal_union.size() == 4); 14 | assert(equal_union[0].label == "first_a"); 15 | assert(equal_union[1].label == "first_b"); 16 | assert(equal_union[2].label == "first_c"); 17 | assert(equal_union[3].label == "second_c"); 18 | 19 | std::cerr << "."; 20 | } 21 | -------------------------------------------------------------------------------- /code_examples/algorithms/set_union_equal_code.h: -------------------------------------------------------------------------------- 1 | struct Labeled { 2 | std::string label; 3 | int value; 4 | }; 5 | 6 | auto cmp = [](const auto& l, const auto& r) { 7 | return l.value < r.value; 8 | }; 9 | 10 | std::vector equal1{{"first_a", 1}, {"first_b", 1}, 11 | {"first_c", 2}}; 12 | std::vector equal2{{"second_a", 1}, {"second_b", 2}, 13 | {"second_c", 2}}; 14 | 15 | std::vector equal_union; 16 | std::ranges::set_union(equal1, equal2, 17 | std::back_inserter(equal_union), cmp); 18 | // equal_union == { {"first_a", 1}, {"first_b", 1}, 19 | // {"first_c", 2}, {"second_c", 2} } 20 | -------------------------------------------------------------------------------- /code_examples/algorithms/shift_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1,2,3,4,5,6,7,8,9}; 2 | std::shift_left(data.begin(), data.end(), 3); 3 | // data == {4, 5, 6, 7, 8, 9, 7, 8, 9} 4 | 5 | data = {1,2,3,4,5,6,7,8,9}; 6 | std::shift_right(data.begin(), data.end(), 3); 7 | // data == {1, 2, 3, 1, 2, 3, 4, 5, 6} -------------------------------------------------------------------------------- /code_examples/algorithms/shift_move_code.h: -------------------------------------------------------------------------------- 1 | struct EmptyOnMove { 2 | char value; 3 | EmptyOnMove(char value) : value(value) {} 4 | EmptyOnMove(EmptyOnMove&& src) : 5 | value(std::exchange(src.value,'-')) {} 6 | EmptyOnMove& operator=(EmptyOnMove&& src) { 7 | value = std::exchange(src.value, '-'); 8 | return *this; 9 | } 10 | EmptyOnMove(const EmptyOnMove&) = default; 11 | EmptyOnMove& operator=(const EmptyOnMove&) = default; 12 | }; 13 | 14 | int main() { 15 | std::vector nontrivial{ 16 | {'a'},{'b'},{'c'},{'d'},{'e'},{'f'},{'g'}}; 17 | 18 | std::shift_right(nontrivial.begin(), nontrivial.end(), 4); 19 | // nontrivial == { '-', '-', '-', 'd', 'a', 'b', 'c' } 20 | } -------------------------------------------------------------------------------- /code_examples/algorithms/shuffle.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "shuffle_code.h" 12 | -------------------------------------------------------------------------------- /code_examples/algorithms/shuffle_code.h: -------------------------------------------------------------------------------- 1 | struct Card { 2 | unsigned index; 3 | 4 | friend std::ostream& operator << (std::ostream& s, const Card& card) { 5 | static constexpr std::array ranks = 6 | {"Ace", "Two", "Three", "Four", "Five", "Six", "Seven", 7 | "Eight", "Nine", "Ten", "Jack", "Queen", "King"}; 8 | static constexpr std::array suits = 9 | {"Hearts", "Diamonds", "Clubs", "Spades"}; 10 | 11 | if (card.index >= 52) 12 | throw std::domain_error( 13 | "Card index has to be in the range 0..51"); 14 | 15 | s << ranks[card.index%13] << " of " << suits[card.index/13]; 16 | return s; 17 | } 18 | 19 | }; 20 | 21 | int main() { 22 | 23 | std::vector deck(52, Card{}); 24 | std::ranges::generate(deck, [i = 0u]() mutable { return Card{i++}; }); 25 | // deck == {Ace of Hearts, Two of Hearts, Three of Hearts, Four...} 26 | 27 | std::random_device rd; 28 | std::mt19937 gen{rd()}; 29 | 30 | std::ranges::shuffle(deck, gen); 31 | // deck == { random order } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /code_examples/algorithms/sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | #include "sort_code.h" 10 | auto cmp = {1, 2, 3, 4, 5, 6, 7, 8, 9}; 11 | 12 | assert(std::ranges::equal(data1, cmp)); 13 | assert(std::ranges::equal(data2, cmp)); 14 | 15 | std::cerr << "."; 16 | } 17 | -------------------------------------------------------------------------------- /code_examples/algorithms/sort_code.h: -------------------------------------------------------------------------------- 1 | std::vector data1 = {9, 1, 8, 2, 7, 3, 6, 4, 5}; 2 | std::sort(data1.begin(), data1.end()); 3 | // data1 == {1, 2, 3, 4, 5, 6, 7, 8, 9} 4 | 5 | std::list data2 = {9, 1, 8, 2, 7, 3, 6, 4, 5}; 6 | // std::sort(data.begin(), data.end()); // doesn't compile 7 | data2.sort(); 8 | // data2 == {1, 2, 3, 4, 5, 6, 7, 8, 9} -------------------------------------------------------------------------------- /code_examples/algorithms/sort_heap.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | #include "sort_heap_code.h" 9 | assert(std::is_sorted(data.begin(), data.end())); 10 | 11 | std::cerr << "."; 12 | } 13 | -------------------------------------------------------------------------------- /code_examples/algorithms/sort_heap_code.h: -------------------------------------------------------------------------------- 1 | std::vector data = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 2 | 3 | std::make_heap(data.begin(), data.end()); 4 | // data == {9, 8, 7, 4, 5, 6, 3, 2, 1} - different ordering possible 5 | 6 | std::sort_heap(data.begin(), data.end()); 7 | // data == {1, 2, 3, 4, 5, 6, 7, 8, 9} -------------------------------------------------------------------------------- /code_examples/algorithms/sort_projection.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | #include "sort_projection_code.h" 9 | auto cmp = {Account{0.3}, Account{0.1}, Account{0.05}, Account{0.01}}; 10 | auto cmp_fn = [](auto l, auto r) { return l.value_ == r.value_; }; 11 | assert(std::ranges::equal(accounts, cmp, cmp_fn)); 12 | 13 | std::cerr << "."; 14 | } 15 | -------------------------------------------------------------------------------- /code_examples/algorithms/sort_projection_code.h: -------------------------------------------------------------------------------- 1 | struct Account { 2 | double value() { return value_; } 3 | double value_; 4 | }; 5 | 6 | std::vector accounts{{0.1}, {0.3}, {0.01}, {0.05}}; 7 | std::ranges::sort(accounts, std::greater<>{}, &Account::value); 8 | // accounts = { {0.3}, {0.1}, {0.05}, {0.01} } -------------------------------------------------------------------------------- /code_examples/algorithms/stable_partition.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | struct Item { 8 | std::string label; 9 | bool is_selected_; 10 | bool is_selected() const { 11 | return is_selected_; 12 | } 13 | friend auto operator<=>(const Item&, const Item&) = default; 14 | }; 15 | 16 | struct Widget { 17 | std::vector items; 18 | }; 19 | 20 | Widget& get_widget() { 21 | static Widget widget{ .items = {{"a", true}, {"b", false}, {"c", true}, {"d", false}, {"e", true}, {"f", false}}}; 22 | return widget; 23 | } 24 | 25 | int main() { 26 | #include "stable_partition_code.h" 27 | std::vector cmp = {{"a", true}, {"c", true}, {"e", true}, {"b", false}, {"d", false}, {"f", false}}; 28 | assert(std::ranges::equal(widget.items, cmp)); 29 | std::cerr << "."; 30 | } 31 | -------------------------------------------------------------------------------- /code_examples/algorithms/stable_partition_code.h: -------------------------------------------------------------------------------- 1 | auto& widget = get_widget(); 2 | std::ranges::stable_partition(widget.items, &Item::is_selected); -------------------------------------------------------------------------------- /code_examples/algorithms/stable_sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | #include "stable_sort_code.h" 9 | 10 | std::vector cmp {{"a", 1}, {"f", 1}, {"q", 1}, {"c", 2}, {"d", 3}}; 11 | auto cmp_fn = [](auto l, auto r) { return l.label == r.label && l.rank == r.rank; }; 12 | assert(std::ranges::equal(data, cmp, cmp_fn)); 13 | 14 | std::cerr << "."; 15 | } 16 | -------------------------------------------------------------------------------- /code_examples/algorithms/stable_sort_code.h: -------------------------------------------------------------------------------- 1 | struct Record { 2 | std::string label; 3 | int rank; 4 | }; 5 | 6 | std::vector data {{"q", 1}, {"f", 1}, {"c", 2}, 7 | {"a", 1}, {"d", 3}}; 8 | 9 | std::ranges::stable_sort(data, {}, &Record::label); 10 | std::ranges::stable_sort(data, {}, &Record::rank); 11 | // Guarantted order: a-1, f-1, q-1, c-2, d-3 -------------------------------------------------------------------------------- /code_examples/algorithms/swap_calling.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "swap_calling_code.h" 8 | 9 | int main() { 10 | int x = 1, y = 2; 11 | some_algorithm(x, y); 12 | 13 | std::string i = "abcdefg", j = "jklmno"; 14 | some_algorithm(i,j); 15 | } 16 | -------------------------------------------------------------------------------- /code_examples/algorithms/swap_calling_code.h: -------------------------------------------------------------------------------- 1 | void some_algorithm(auto& x, auto& y) { 2 | using std::swap; 3 | swap(x, y); 4 | } -------------------------------------------------------------------------------- /code_examples/algorithms/swap_range.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "swap_range_code.h" 8 | -------------------------------------------------------------------------------- /code_examples/algorithms/swap_range_code.h: -------------------------------------------------------------------------------- 1 | namespace Library { 2 | struct Storage { 3 | int value; 4 | }; 5 | 6 | void swap(Storage& left, Storage& right) { 7 | std::ranges::swap(left.value, right.value); 8 | } 9 | } 10 | 11 | int main() { 12 | int a = 1, b = 2; 13 | std::ranges::swap(a, b); // 3-step-swap 14 | 15 | Library::Storage j{2}, k{3}; 16 | std::ranges::swap(j, k); // calls custom Library::swap() 17 | } 18 | -------------------------------------------------------------------------------- /code_examples/algorithms/swap_ranges.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | #include "swap_ranges_code.h" 9 | auto cmp = { 9, 8, 7, 4, 5, 6, 3, 2, 1 }; 10 | assert(std::equal(data.begin(), data.end(), cmp.begin())); 11 | std::cerr << "."; 12 | } 13 | -------------------------------------------------------------------------------- /code_examples/algorithms/swap_ranges_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{ 1, 2, 3, 4, 5, 6, 7, 8, 9}; 2 | std::swap_ranges(data.begin(), data.begin()+3, data.rbegin()); 3 | // data = { 9, 8, 7, 4, 5, 6, 3, 2, 1 } -------------------------------------------------------------------------------- /code_examples/algorithms/transactional.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "transactional_code.h" 10 | -------------------------------------------------------------------------------- /code_examples/algorithms/transactional_code.h: -------------------------------------------------------------------------------- 1 | struct Custom { 2 | static int cnt; 3 | Custom() { 4 | if (++cnt >= 3) 5 | throw std::runtime_error("Deliberate failure."); 6 | std::cout << "Custom()\n"; 7 | } 8 | ~Custom() { 9 | std::cout << "~Custom()\n"; 10 | } 11 | }; 12 | 13 | int Custom::cnt = 0; 14 | 15 | int main() { 16 | alignas(alignof(Custom)) char buffer[sizeof(Custom)*10]; 17 | auto *begin = reinterpret_cast(buffer); 18 | 19 | try { 20 | std::uninitialized_default_construct_n(begin, 10); 21 | std::destroy_n(begin, 10); // not reached 22 | } catch (std::exception& e) { 23 | std::cout << e.what() << "\n"; 24 | } 25 | } 26 | /* OUTPUT: 27 | Custom() 28 | Custom() 29 | ~Custom() 30 | ~Custom() 31 | Deliberate failure. 32 | */ 33 | -------------------------------------------------------------------------------- /code_examples/algorithms/transform.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main() { 10 | #include "transform_code.h" 11 | auto cmp = {10, 11, 12, 13, 14, 15, 16, 17}; 12 | assert(std::ranges::equal(data,cmp)); 13 | 14 | std::cerr << "."; 15 | } 16 | -------------------------------------------------------------------------------- /code_examples/algorithms/transform_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 2, 3, 4, 5, 6, 7, 8}; 2 | 3 | std::transform(data.begin(), data.end(), 4 | data.begin(), 5 | [](int v) { return v*2; }); 6 | // data == {2, 4, 6, 8, 10, 12, 14, 16} 7 | 8 | std::vector add{8, 7, 6, 5, 4, 3, 2, 1}; 9 | 10 | std::transform(data.begin(), data.end(), 11 | add.begin(), 12 | data.begin(), 13 | [](int left, int right) { return left+right; }); 14 | // data == {10, 11, 12, 13, 14, 15, 16, 17} 15 | -------------------------------------------------------------------------------- /code_examples/algorithms/transform_inclusive.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main() { 12 | #include "transform_inclusive_code.h" 13 | auto cmp1 = {-10, -7, -9, -4, 2}; 14 | auto cmp2 = {10, 13, 15, 20, 26}; 15 | assert(std::ranges::equal(out1, cmp1)); 16 | assert(std::ranges::equal(out2, cmp2)); 17 | 18 | std::cerr << "."; 19 | } 20 | -------------------------------------------------------------------------------- /code_examples/algorithms/transform_inclusive_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{-10, 3, -2, 5, 6}; 2 | 3 | std::vector out1; 4 | std::inclusive_scan(data.begin(), data.end(), 5 | std::back_inserter(out1), std::plus<>{}); 6 | // out1 == {-10, -7, -9, -4, 2} 7 | 8 | std::vector out2; 9 | std::transform_inclusive_scan(data.begin(), data.end(), 10 | std::back_inserter(out2), std::plus<>{}, 11 | [](int v) { return std::abs(v); }); 12 | // out2 == {10, 13, 15, 20, 26} -------------------------------------------------------------------------------- /code_examples/algorithms/transform_reduce.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main() { 12 | #include "transform_reduce_code.h" 13 | assert(sum_of_squares == 55); 14 | assert(result == 3); 15 | 16 | std::cerr << "."; 17 | } 18 | -------------------------------------------------------------------------------- /code_examples/algorithms/transform_reduce_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 2, 3, 4, 5}; 2 | auto sum_of_squares = std::transform_reduce(data.begin(), data.end(), 3 | 0, std::plus<>{}, [](int v) { return v*v; }); 4 | // sum_of_squares == 55 5 | 6 | std::vector coef{1, -1, 1, -1, 1}; 7 | auto result = std::transform_reduce(data.begin(), data.end(), 8 | coef.begin(), 0); 9 | // result == 1*1 + 2*(-1) + 3*1 + 4*(-1) + 5*1 == 3 -------------------------------------------------------------------------------- /code_examples/algorithms/uninitialized_constr.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main() { 10 | #include "uninitialized_constr_code.h" 11 | std::cerr << "."; 12 | } 13 | -------------------------------------------------------------------------------- /code_examples/algorithms/uninitialized_constr_code.h: -------------------------------------------------------------------------------- 1 | alignas(alignof(std::string)) char buffer[sizeof(std::string)*10]; 2 | auto *begin = reinterpret_cast(buffer); 3 | auto *it = begin; 4 | 5 | it = std::uninitialized_default_construct_n(it, 3); 6 | it = std::uninitialized_fill_n(it, 2, "Hello World!"); 7 | it = std::uninitialized_value_construct_n(it, 3); 8 | it = std::uninitialized_fill_n(it, 2, "Bye World!"); 9 | 10 | // {"", "", "", "Hello World!", "Hello World!", "", "", "", 11 | // "Bye World!", "Bye World!"} 12 | 13 | std::destroy_n(begin, 10); -------------------------------------------------------------------------------- /code_examples/algorithms/uninitialized_copy.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main() { 10 | #include "uninitialized_copy_code.h" 11 | std::cerr << "."; 12 | } 13 | -------------------------------------------------------------------------------- /code_examples/algorithms/uninitialized_copy_code.h: -------------------------------------------------------------------------------- 1 | alignas(alignof(std::string)) char buff1[sizeof(std::string)*5]; 2 | alignas(alignof(std::string)) char buff2[sizeof(std::string)*5]; 3 | std::vector data = { 4 | "hello", "world", "and", "everyone", "else"}; 5 | 6 | auto *bg1 = reinterpret_cast(buff1); 7 | std::uninitialized_copy(data.begin(), data.end(), bg1); 8 | // buff1 == { "hello", "world", "and", "everyone", "else"} 9 | // data == { "hello", "world", "and", "everyone", "else"} 10 | std::destroy_n(bg1, 5); 11 | 12 | auto *bg2 = reinterpret_cast(buff2); 13 | std::uninitialized_move(data.begin(), data.end(), bg2); 14 | // buff2 == { "hello", "world", "and", "everyone", "else"} 15 | // data == { ?, ?, ?, ?, ?} 16 | // In most implementations a moved-out-of string will be empty. 17 | std::destroy_n(bg2, 5); 18 | -------------------------------------------------------------------------------- /code_examples/algorithms/unique.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main() { 11 | #include "unique_code.h" 12 | auto cmp = {1, 2, 3, 4, 5, 6}; 13 | assert(std::ranges::equal(data, cmp)); 14 | 15 | std::cerr << "."; 16 | } 17 | -------------------------------------------------------------------------------- /code_examples/algorithms/unique_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 1, 2, 2, 3, 4, 5, 6, 6, 6}; 2 | 3 | auto it = std::unique(data.begin(), data.end()); 4 | // data == {1, 2, 3, 4, 5, 6, unspec, unspec, unspec, unspec} 5 | 6 | data.resize(std::distance(data.begin(), it)); 7 | // data == {1, 2, 3, 4, 5, 6} 8 | -------------------------------------------------------------------------------- /code_examples/algorithms/unique_copy.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main() { 11 | #include "unique_copy_code.h" 12 | 13 | auto cmp = {1, 2, 3, 4, 5, 6}; 14 | assert(std::ranges::equal(out, cmp)); 15 | 16 | std::cerr << "."; 17 | } 18 | -------------------------------------------------------------------------------- /code_examples/algorithms/unique_copy_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 1, 2, 2, 3, 4, 5, 6, 6, 6}; 2 | std::vector out; 3 | 4 | std::ranges::unique_copy(data, std::back_inserter(out)); 5 | // out == {1, 2, 3, 4, 5, 6} 6 | -------------------------------------------------------------------------------- /code_examples/extras/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # TODO: temporarily disabled, should be valid, but doesn't compile locally 2 | #add_executable(priority_queue priority_queue.cpp) 3 | #install(TARGETS priority_queue DESTINATION bin) 4 | 5 | add_executable(span_stringview span_stringview.cpp) 6 | # Compile only 7 | -------------------------------------------------------------------------------- /code_examples/extras/priority_queue.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "priority_queue_queue_code.h" 10 | #include "priority_queue_heap_code.h" 11 | 12 | int main() { 13 | std::vector data = {1, 2, 3, 4, 5, 6, 7, 8, 9}; 14 | 15 | auto result = topk_queue(data.begin(), data.end(), 4); 16 | assert(result.size() == 4); 17 | auto cmp = {9, 8, 7, 6}; 18 | assert(std::ranges::equal(result, cmp)); 19 | 20 | auto result2 = topk_heap(data.begin(), data.end(), 4); 21 | assert(result2.size() == 4); 22 | assert(std::ranges::equal(result2, cmp)); 23 | 24 | std::cerr << "."; 25 | } 26 | -------------------------------------------------------------------------------- /code_examples/extras/priority_queue_heap_code.h: -------------------------------------------------------------------------------- 1 | auto topk_heap( 2 | std::input_iterator auto begin, 3 | std::sentinel_for auto end, 4 | size_t k) { 5 | 6 | std::vector> result; 7 | 8 | while (begin != end) { 9 | result.push_back(*begin); 10 | std::ranges::push_heap(result, std::greater<>{}); 11 | 12 | if (result.size() > k) { 13 | std::ranges::pop_heap(result, std::greater<>{}); 14 | result.pop_back(); 15 | } 16 | 17 | ++begin; 18 | } 19 | 20 | std::ranges::sort_heap(result, std::greater<>{}); 21 | return result; 22 | } 23 | -------------------------------------------------------------------------------- /code_examples/extras/priority_queue_queue_code.h: -------------------------------------------------------------------------------- 1 | auto topk_queue( 2 | std::input_iterator auto begin, 3 | std::sentinel_for auto end, 4 | size_t k) { 5 | 6 | using vtype = std::iter_value_t; 7 | using arrtype = std::vector; 8 | 9 | std::priority_queue> pq; 10 | 11 | while (begin != end) { 12 | pq.push(*begin); 13 | if (pq.size() > k) 14 | pq.pop(); 15 | ++begin; 16 | } 17 | 18 | arrtype result(k); 19 | for (auto &el: result | std::views::reverse) { 20 | el = std::move(pq.top()); 21 | pq.pop(); 22 | } 23 | 24 | return result; 25 | } 26 | 27 | -------------------------------------------------------------------------------- /code_examples/extras/span_stringview.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main() { 12 | #include "span_stringview_code.h" 13 | std::cerr << "."; 14 | } 15 | -------------------------------------------------------------------------------- /code_examples/extras/span_stringview_code.h: -------------------------------------------------------------------------------- 1 | int c_array[] = {1, 2, 3, 4, 5, 6, 7}; 2 | auto arr_view = std::span(c_array, sizeof(c_array)/sizeof(int)); 3 | 4 | for (auto it = arr_view.rbegin(); it != arr_view.rend(); ++it) { 5 | // iterate over: {7, 6, 5, 4, 3, 2, 1} 6 | } 7 | 8 | const char* c_string = "No lemon, no melon"; 9 | auto str_view = std::string_view(c_string); 10 | 11 | for (auto it = str_view.rbegin(); it != str_view.rend(); ++it) { 12 | // iterate over: "nolem on ,nomel oN" 13 | } 14 | -------------------------------------------------------------------------------- /code_examples/introduction/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(history_cc98 history_cc98.cpp) 2 | install(TARGETS history_cc98 DESTINATION bin) 3 | 4 | add_executable(history_cc11 history_cc11.cpp) 5 | install(TARGETS history_cc11 DESTINATION bin) 6 | 7 | add_executable(history_cc17 history_cc17.cpp) 8 | install(TARGETS history_cc17 DESTINATION bin) 9 | 10 | add_executable(history_cc20 history_cc20.cpp) 11 | install(TARGETS history_cc20 DESTINATION bin) 12 | 13 | add_executable(iterators iterators.cpp) 14 | install(TARGETS iterators DESTINATION bin) 15 | 16 | add_executable(sentinels sentinels.cpp) 17 | install(TARGETS sentinels DESTINATION bin) 18 | 19 | add_executable(categories categories.cpp) 20 | install(TARGETS categories DESTINATION bin) 21 | 22 | add_executable(mental_range mental_range.cpp) 23 | install(TARGETS mental_range DESTINATION bin) 24 | 25 | add_executable(mental_sorted mental_sorted.cpp) 26 | # Compile only 27 | 28 | add_executable(mental_two mental_two.cpp) 29 | # Compile only 30 | 31 | add_executable(mental_find mental_find.cpp) 32 | # Compile only 33 | -------------------------------------------------------------------------------- /code_examples/introduction/categories.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | #include "categories_code.h" 9 | assert(dst1 == 6); 10 | assert(dst2 == 6); 11 | std::cerr << "."; 12 | } 13 | -------------------------------------------------------------------------------- /code_examples/introduction/categories_code.h: -------------------------------------------------------------------------------- 1 | std::vector arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 2 | auto it1 = arr.begin(); 3 | it1 += 5; // OK, std::vector provides random access iterator 4 | ++it1; // OK, all iterators provide advance operation 5 | 6 | ptrdiff_t dst1 = it1 - arr.begin(); // OK, random access iterator 7 | // dst1 == 6 8 | 9 | std::list lst = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 10 | auto it2 = lst.begin(); 11 | // it2 += 5; Would not compile. 12 | std::advance(it2, 5); // OK, linear advance by 5 steps 13 | ++it2; // OK, all iterators provide advance operation 14 | 15 | // it2 - lst.begin(); Would not compile 16 | ptrdiff_t dst2 = std::distance(lst.begin(), it2); // OK, linear calc. 17 | // dst2 == 6 18 | -------------------------------------------------------------------------------- /code_examples/introduction/history_cc11.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | #include "history_cc11_code.h" 8 | 9 | assert(cnt == 9); 10 | assert(sum == 45); 11 | 12 | std::cerr << "."; 13 | } 14 | -------------------------------------------------------------------------------- /code_examples/introduction/history_cc11_code.h: -------------------------------------------------------------------------------- 1 | int cnt = 0, sum = 0; 2 | std::vector data = {1, 2, 3, 4, 5, 6, 7, 8, 9}; 3 | std::for_each(data.begin(), data.end(), [&](int el) { 4 | cnt++; 5 | sum += el; 6 | }); 7 | // cnt == 9, sum == 45 8 | -------------------------------------------------------------------------------- /code_examples/introduction/history_cc17.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | #include "history_cc17_code.h" 10 | assert(cnt == 9); 11 | assert(sum == 45); 12 | std::cerr << "."; 13 | } 14 | -------------------------------------------------------------------------------- /code_examples/introduction/history_cc17_code.h: -------------------------------------------------------------------------------- 1 | std::atomic cnt = 0, sum = 0; 2 | std::vector data = {1, 2, 3, 4, 5, 6, 7, 8, 9}; 3 | std::for_each(std::execution::par_unseq, 4 | data.begin(), data.end(), 5 | [&](int el) { 6 | cnt++; 7 | sum += el; 8 | }); 9 | // cnt == 9, sum == 45 10 | -------------------------------------------------------------------------------- /code_examples/introduction/history_cc20.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | #include "history_cc20_code.h" 8 | assert(cnt == 9); 9 | assert(sum == 45); 10 | std::cerr << "."; 11 | } 12 | -------------------------------------------------------------------------------- /code_examples/introduction/history_cc20_code.h: -------------------------------------------------------------------------------- 1 | int cnt = 0, sum = 0; 2 | std::vector data = {1, 2, 3, 4, 5, 6, 7, 8, 9}; 3 | std::ranges::for_each(data, [&](int el) { 4 | cnt++; 5 | sum += el; 6 | }); 7 | // cnt == 9, sum == 45 8 | -------------------------------------------------------------------------------- /code_examples/introduction/history_cc98.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | #include "history_cc98_code.h" 8 | assert(result.cnt == 9); 9 | assert(result.sum == 45); 10 | std::cerr << "."; 11 | } 12 | -------------------------------------------------------------------------------- /code_examples/introduction/history_cc98_code.h: -------------------------------------------------------------------------------- 1 | struct StatsFn { 2 | int cnt = 0; 3 | int sum = 0; 4 | void operator()(int v) { 5 | cnt++; 6 | sum += v; 7 | } 8 | }; 9 | 10 | std::vector data = {1, 2, 3, 4, 5, 6, 7, 8, 9}; 11 | auto result = std::for_each(data.begin(), data.end(), StatsFn{}); 12 | // result == {9, 45} 13 | -------------------------------------------------------------------------------- /code_examples/introduction/iterators.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | #include "iterators_code.h" 8 | 9 | assert(it1 == data.begin()); 10 | assert(std::distance(it1, it2) == 2); 11 | assert(std::distance(it1, it3) == 5); 12 | assert(it4 == data.end()); 13 | std::cerr << "."; 14 | } 15 | -------------------------------------------------------------------------------- /code_examples/introduction/iterators_code.h: -------------------------------------------------------------------------------- 1 | std::vector data = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 2 | 3 | auto it1 = data.begin(); 4 | auto it2 = it1 + 2; 5 | std::for_each(it1, it2, [](int el) { 6 | std::cout << el << ", "; 7 | }); 8 | // Prints: 1, 2, 9 | 10 | auto it3 = data.begin() + 5; 11 | auto it4 = data.end(); 12 | std::for_each(it3, it4, [](int el) { 13 | std::cout << el << ", "; 14 | }); 15 | // Prints: 6, 7, 8, 9, 16 | -------------------------------------------------------------------------------- /code_examples/introduction/mental_find.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | #include "mental_find_code.h" 6 | } 7 | -------------------------------------------------------------------------------- /code_examples/introduction/mental_find_code.h: -------------------------------------------------------------------------------- 1 | std::string str("Hello World!"); 2 | 3 | // Returns the iterator to the first occurence of ' ' 4 | auto it = std::find(str.begin(), str.end(), ' '); 5 | 6 | // Range [begin, it) is the maximal prefix range 7 | // that doesn't contain ' ' 8 | for (auto v : std::string_view(str.begin(), it)) { 9 | // iterate over "Hello" 10 | } 11 | -------------------------------------------------------------------------------- /code_examples/introduction/mental_range.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | #include "mental_range_code.h" 8 | assert(std::ranges::equal(data, out)); 9 | std::cerr << "."; 10 | } 11 | -------------------------------------------------------------------------------- /code_examples/introduction/mental_range_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 2, 3, 4, 5, 6, 7}; 2 | std::vector out(7,0); 3 | 4 | std::copy(data.begin(), data.end(), // input range 5 | out.begin() // output range, end iterator is implied: 6 | // std::next(out.begin(), 7 | // std::distance(data.begin(), data.end())); 8 | ); 9 | -------------------------------------------------------------------------------- /code_examples/introduction/mental_sorted.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | #include "mental_sorted_code.h" 9 | } 10 | -------------------------------------------------------------------------------- /code_examples/introduction/mental_sorted_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 4, 5, 7, 9, 2, 3}; 2 | 3 | // is_sorted_until returns the first out of order element. 4 | auto result = std::is_sorted_until(data.begin(), data.end()); 5 | 6 | // [begin, result) is the maximal sorted sub-range 7 | for (auto it = data.begin(); it != result; it++) { 8 | // Iterate over all elements in the sorted sub-range. 9 | // {1, 4, 5, 7, 9} 10 | } 11 | for (auto v : std::ranges::subrange(data.begin(), result)) { 12 | // Same, but using a range-based for loop. 13 | } 14 | -------------------------------------------------------------------------------- /code_examples/introduction/mental_two.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | #include "mental_two_code.h" 9 | } 10 | -------------------------------------------------------------------------------- /code_examples/introduction/mental_two_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 2, 3, 4, 5, 6, 7, 8, 9}; 2 | 3 | // lower_bound returns the first element !(el < 4) 4 | auto lb = std::lower_bound(data.begin(), data.end(), 4); 5 | 6 | for (auto v : std::ranges::subrange(data.begin(), lb)) { 7 | // lower range [begin, lb): elements < 4 8 | } 9 | for (auto v : std::ranges::subrange(lb, data.end())) { 10 | // upper range [lb, end): elements >= 4 11 | } 12 | -------------------------------------------------------------------------------- /code_examples/introduction/sentinels.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | #include "sentinels_code.h" 8 | assert((data.begin() == Sentinel{data.begin(), 0})); 9 | assert((data.begin() != Sentinel{data.begin(), 1})); 10 | auto it = data.begin() + 5; 11 | assert((it == Sentinel{data.begin(), 0})); 12 | assert((it == Sentinel{data.begin(), 5})); 13 | assert((it != Sentinel{data.begin(), 6})); 14 | 15 | std::cerr << "."; 16 | } 17 | -------------------------------------------------------------------------------- /code_examples/introduction/sentinels_code.h: -------------------------------------------------------------------------------- 1 | std::vector data = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 2 | 3 | struct Sentinel { 4 | using iter_t = std::vector::iterator; 5 | iter_t begin; 6 | std::iter_difference_t cnt; 7 | bool operator==(const iter_t& l) const { 8 | return std::distance(begin, l) >= cnt; 9 | } 10 | }; 11 | 12 | auto it1 = data.begin(); 13 | std::ranges::for_each(it1, Sentinel{it1, 5}, [](int el) { 14 | std::cout << el << ", "; 15 | }); 16 | // Prints: 1, 2, 3, 4, 5, 17 | -------------------------------------------------------------------------------- /code_examples/ranges/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(concepts concepts.cpp) 2 | install(TARGETS concepts DESTINATION bin) 3 | 4 | add_executable(infinite infinite.cpp) 5 | # Compile-only 6 | 7 | add_executable(rangified rangified.cpp) 8 | install(TARGETS rangified DESTINATION bin) 9 | 10 | # Not-checked 11 | # projection_code.h 12 | 13 | add_executable(projected_type projected_type.cpp) 14 | install(TARGETS projected_type DESTINATION bin) 15 | 16 | add_executable(dangling dangling.cpp) 17 | install(TARGETS dangling DESTINATION bin) 18 | 19 | # Does not compile with GCC 11 20 | #add_executable(view_demo view_demo.cpp) 21 | # Compile-only 22 | -------------------------------------------------------------------------------- /code_examples/ranges/borrowed_optin_code.h: -------------------------------------------------------------------------------- 1 | template inline constexpr bool 2 | std::ranges::enable_borrowed_range> = true; 3 | -------------------------------------------------------------------------------- /code_examples/ranges/concepts.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "concepts_code.h" 9 | 10 | int main() { 11 | std::vector data{1, 2, 3, 4, 5, 6, 7, 8}; 12 | std::vector out; 13 | my_function(data, std::back_inserter(out)); 14 | assert(out.size() == 2); 15 | assert(out[0] == 5); 16 | assert(out[1] == 7); 17 | std::cerr << "."; 18 | } 19 | -------------------------------------------------------------------------------- /code_examples/ranges/concepts_code.h: -------------------------------------------------------------------------------- 1 | template 2 | auto my_function(T&& rng, 3 | std::output_iterator> auto it) { 4 | if (rng.size() >= 5) 5 | *it++ = rng[4]; 6 | if (rng.size() >= 7) 7 | *it++ = rng[6]; 8 | } 9 | -------------------------------------------------------------------------------- /code_examples/ranges/dangling.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | #include "dangling_code.h" 6 | std::cerr << "."; 7 | } 8 | -------------------------------------------------------------------------------- /code_examples/ranges/dangling_code.h: -------------------------------------------------------------------------------- 1 | const char* c_str = "1234567890"; 2 | 3 | // find on a temporary string_view 4 | auto sep1 = std::ranges::find(std::string_view(c_str), '0'); 5 | // OK, string_view is a borrowed range, *sep1 == '0', 6 | 7 | int bad = 1234567890; 8 | 9 | // find on a temporary string 10 | auto sep2 = std::ranges::find(std::to_string(bad), '0'); 11 | // decltype(sep2) == std::ranges::dangling, *sep2 would not compile 12 | -------------------------------------------------------------------------------- /code_examples/ranges/infinite.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main() { 11 | #include "infinite_code.h" 12 | } 13 | -------------------------------------------------------------------------------- /code_examples/ranges/infinite_code.h: -------------------------------------------------------------------------------- 1 | std::vector dt = { 1, 2, 3, 4, 5, 6, 7, 8, 9}; 2 | std::ranges::shuffle(dt, std::mt19937(std::random_device()())); 3 | 4 | auto pos = std::ranges::find( 5 | dt.begin(), 6 | std::unreachable_sentinel, 7 | 7); 8 | -------------------------------------------------------------------------------- /code_examples/ranges/projected_type.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | #include "projected_type_code.h" 9 | std::cerr << "."; 10 | } 11 | -------------------------------------------------------------------------------- /code_examples/ranges/projected_type_code.h: -------------------------------------------------------------------------------- 1 | struct A{}; 2 | struct B{}; 3 | 4 | std::vector data(5); 5 | 6 | std::vector out1; 7 | // std::vector out1; would not compile 8 | std::ranges::copy_if(data, std::back_inserter(out1), 9 | [](B) { return true; }, // predicate accepts B 10 | [](A) { return B{}; }); // projection projects A->B 11 | 12 | std::vector out2; 13 | std::ranges::transform(data, std::back_inserter(out2), 14 | [](auto x) { return x; }, // no-op transformation functor 15 | [](A) { return B{}; }); // projection projects A->B 16 | -------------------------------------------------------------------------------- /code_examples/ranges/projection_code.h: -------------------------------------------------------------------------------- 1 | struct Account{ 2 | double value(); 3 | }; 4 | 5 | std::vector data = get_data(); 6 | 7 | std::ranges::sort(data, std::greater<>{}, &Account::value); 8 | -------------------------------------------------------------------------------- /code_examples/ranges/rangified.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main() { 11 | #include "rangified_code.h" 12 | auto cmp = {1, 2, 3, 4}; 13 | assert(std::ranges::equal(cmp, dt)); 14 | } 15 | -------------------------------------------------------------------------------- /code_examples/ranges/rangified_code.h: -------------------------------------------------------------------------------- 1 | std::vector dt = {1, 4, 2, 3}; 2 | std::ranges::sort(dt); 3 | -------------------------------------------------------------------------------- /code_examples/ranges/stateful_code.h: -------------------------------------------------------------------------------- 1 | std::list data{1, 2, 3, 4, 5, 6, 7, 8}; 2 | auto view = data | std::views::drop(3); 3 | 4 | for (auto v : view) { 5 | // iterate over: 4, 5, 6, 7, 8 6 | } 7 | 8 | // Note, if we used std::vector, push could invalidate 9 | // the cached iterator inside of std::views::drop. 10 | data.push_front(99); 11 | for (auto v : view) { 12 | // iterate over: 4, 5, 6, 7, 8 13 | } 14 | 15 | // Fresh view 16 | for (auto v : data | std::views::drop(3)) { 17 | // iterate over: 3, 4, 5, 6, 7, 8 18 | } 19 | 20 | const auto view2 = data | std::views::drop(3); 21 | // for (auto v : view2) {} 22 | // Wouldn't compile, std::views::drop requires mutability. -------------------------------------------------------------------------------- /code_examples/ranges/view_demo.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | #include "view_demo_code.h" 7 | } 8 | -------------------------------------------------------------------------------- /code_examples/ranges/view_demo_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 2, 3, 4, 5, 6, 7, 8, 9}; 2 | for (auto v : data | std::views::reverse | 3 | std::views::take(3) | std::views::reverse) { 4 | // iterate over 7, 8, 9 (in order) 5 | } 6 | -------------------------------------------------------------------------------- /code_examples/theory/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(adl adl.cpp) 2 | # Compile only 3 | 4 | add_executable(adl_friend adl_friend.cpp) 5 | # Compile only 6 | 7 | add_executable(adl_default adl_default.cpp) 8 | # Compile only 9 | 10 | add_executable(const_cast const_cast.cpp) 11 | install(TARGETS const_cast DESTINATION bin) 12 | 13 | add_executable(initializer_list initializer_list.cpp) 14 | install(TARGETS initializer_list DESTINATION bin) 15 | 16 | add_executable(adl_unqalified adl_unqalified.cpp) 17 | # Compile only 18 | 19 | add_executable(adl_simple adl_simple.cpp) 20 | # Compile only 21 | 22 | add_executable(adl_nonfunc adl_nonfunc.cpp) 23 | # Compile only 24 | 25 | add_executable(adl_shutdown adl_shutdown.cpp) 26 | # Compile only 27 | 28 | add_executable(adl_niebloid adl_niebloid.cpp) 29 | # Compile only 30 | -------------------------------------------------------------------------------- /code_examples/theory/adl.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "adl_code.h" 8 | 9 | int main() { 10 | calling_site(); 11 | } 12 | -------------------------------------------------------------------------------- /code_examples/theory/adl_code.h: -------------------------------------------------------------------------------- 1 | namespace Custom { 2 | struct X {}; 3 | 4 | std::ostream& operator << (std::ostream& s, const X&) { 5 | s << "Output of X\n"; 6 | return s; 7 | } 8 | } 9 | 10 | void calling_site() { 11 | Custom::X x; 12 | Custom::operator << (std::cout, x); // OK, explicit call 13 | std::cout << x; // Requires ADL 14 | } 15 | -------------------------------------------------------------------------------- /code_examples/theory/adl_default.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "adl_default_code.h" 8 | 9 | int main() { 10 | calling_site(); 11 | } 12 | -------------------------------------------------------------------------------- /code_examples/theory/adl_default_code.h: -------------------------------------------------------------------------------- 1 | namespace Base { 2 | template 3 | std::string serialize(const T&) { 4 | return std::string{"{Unknown type}"}; 5 | } 6 | } 7 | 8 | namespace Custom { 9 | struct X { 10 | friend std::string serialize(const X&) { 11 | return std::string{"{X}"}; 12 | } 13 | }; 14 | 15 | struct Y {}; 16 | } 17 | 18 | void calling_site() { 19 | Custom::X x; 20 | Custom::Y y; 21 | 22 | auto serialized_x = serialize(x); 23 | // serialized_x == "{X}" 24 | 25 | // auto serialized_y = serialize(y); // Would not compile. 26 | 27 | using Base::serialize; // Pull in default version. 28 | auto serialized_y = serialize(y); 29 | // serialized_y == "{Unknown type}" 30 | } 31 | 32 | -------------------------------------------------------------------------------- /code_examples/theory/adl_friend.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "adl_friend_code.h" 8 | 9 | int main() { 10 | calling_site(); 11 | } 12 | -------------------------------------------------------------------------------- /code_examples/theory/adl_friend_code.h: -------------------------------------------------------------------------------- 1 | namespace Custom { 2 | struct X { 3 | friend std::ostream& operator << (std::ostream& s, const X&) { 4 | s << "Output of X\n"; 5 | return s; 6 | } 7 | }; 8 | } 9 | 10 | void calling_site() { 11 | Custom::X x; 12 | // Custom::operator << (std::cout, x); // Not visible 13 | std::cout << x; // OK, unqualified operator <<, ADL kicks in 14 | } 15 | -------------------------------------------------------------------------------- /code_examples/theory/adl_niebloid.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "adl_niebloid_code.h" 4 | int main() { 5 | calling_site(); 6 | } 7 | -------------------------------------------------------------------------------- /code_examples/theory/adl_niebloid_code.h: -------------------------------------------------------------------------------- 1 | namespace dflt { 2 | namespace impl { 3 | template 4 | concept HasCustomImpl = requires(T a) { do_something(a); }; 5 | 6 | struct DoSomethingFn { 7 | template void operator()(T&& arg) const 8 | requires HasCustomImpl { 9 | do_something(std::forward(arg)); 10 | } 11 | 12 | template void operator()(T&&) const 13 | requires (!HasCustomImpl) { /* default implementation */ } 14 | }; 15 | } 16 | 17 | inline namespace var { 18 | constexpr inline auto do_something = impl::DoSomethingFn{}; 19 | } 20 | } 21 | 22 | namespace custom { 23 | struct X { friend void do_something(const X&){}; }; 24 | struct Y {}; 25 | } 26 | 27 | void calling_site() { 28 | custom::X x; 29 | custom::Y y; 30 | dflt::do_something(x); // calls custom::do_something(const X&) 31 | dflt::do_something(y); // calls default implementation 32 | } 33 | -------------------------------------------------------------------------------- /code_examples/theory/adl_nonfunc.cpp: -------------------------------------------------------------------------------- 1 | #include "adl_nonfunc_code.h" 2 | 3 | int main() { 4 | calling_site(); 5 | } 6 | -------------------------------------------------------------------------------- /code_examples/theory/adl_nonfunc_code.h: -------------------------------------------------------------------------------- 1 | namespace Custom { 2 | struct X {}; 3 | 4 | constexpr inline auto some_func = [](const X&) {}; 5 | } 6 | 7 | void calling_site() { 8 | Custom::X x; 9 | // some_func(x); // Will not compile, not visible to ADL. 10 | Custom::some_func(x); // OK 11 | } 12 | -------------------------------------------------------------------------------- /code_examples/theory/adl_shutdown.cpp: -------------------------------------------------------------------------------- 1 | #include "adl_shutdown_code.h" 2 | int main() { 3 | calling_site(); 4 | } 5 | -------------------------------------------------------------------------------- /code_examples/theory/adl_shutdown_code.h: -------------------------------------------------------------------------------- 1 | namespace Custom { 2 | struct X { 3 | friend void some_func(const X&) {} 4 | }; 5 | } 6 | 7 | constexpr inline auto some_func = [](const auto&) {}; 8 | 9 | void calling_site() { 10 | Custom::X x; 11 | some_func(x); // calls ::some_func 12 | // Because ADL is skipped, Custom::some_func cannot be called. 13 | } 14 | -------------------------------------------------------------------------------- /code_examples/theory/adl_simple.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "adl_simple_code.h" 3 | int main() { 4 | calling_site(); 5 | } 6 | -------------------------------------------------------------------------------- /code_examples/theory/adl_simple_code.h: -------------------------------------------------------------------------------- 1 | namespace A { 2 | struct X {}; 3 | void some_func(const X&) {} 4 | } 5 | 6 | namespace B { 7 | struct Y {}; 8 | void some_func(const Y&) {} 9 | } 10 | 11 | void some_func(const auto&) {} 12 | 13 | void calling_site() { 14 | A::X x; B::Y y; 15 | some_func(x); // Calls A::some_func 16 | some_func(y); // Calls B::some_func 17 | } 18 | -------------------------------------------------------------------------------- /code_examples/theory/adl_unqalified.cpp: -------------------------------------------------------------------------------- 1 | #include "adl_unqalified_code.h" 2 | int main() { 3 | A::B::calling_site(); 4 | } 5 | -------------------------------------------------------------------------------- /code_examples/theory/adl_unqalified_code.h: -------------------------------------------------------------------------------- 1 | namespace A { 2 | void some_call(int) {} 3 | void some_call(const char*) {} 4 | namespace B { 5 | void some_call(double) {} 6 | 7 | void calling_site() { 8 | some_call(1); // A::B::some_call 9 | some_call(2.0); // A::B::some_call 10 | // some_call("hello world"); will not compile 11 | // no conversion from const char* -> double 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /code_examples/theory/comparable_code.h: -------------------------------------------------------------------------------- 1 | struct Point { 2 | 3 | int x; 4 | int y; 5 | 6 | // pre-C++20 lexicographical less-than 7 | friend bool operator<(const Point& left, const Point& right) { 8 | if (left.x != right.x) 9 | return left.x < right.x; 10 | return left.y < right.y; 11 | } 12 | 13 | // default C++20 spaceship version of lexicographical comparison 14 | friend auto operator<=>(const Point&, const Point&) = default; 15 | 16 | // manual version of lexicographical comparison using operator <=> 17 | friend auto operator<=>(const Point& left, const Point& right) { 18 | if (left.x != right.x) 19 | return left.x <=> right.x; 20 | return left.y <=> right.y; 21 | } 22 | 23 | }; 24 | -------------------------------------------------------------------------------- /code_examples/theory/const_cast.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | #include "const_cast_code.h" 7 | std::cerr << "."; 8 | } 9 | -------------------------------------------------------------------------------- /code_examples/theory/const_cast_code.h: -------------------------------------------------------------------------------- 1 | int x = 10, y = 20; 2 | 3 | auto& v = const_cast(std::min(x, y)); 4 | v = 5; 5 | // x == 5, y == 20 6 | 7 | // !IMPORTANT! the following compiles, but is undefined behaviour 8 | // i.e. the program is ill-formed 9 | const int z = 3; 10 | auto& w = const_cast(std::min(x, z)); 11 | w = 10; 12 | -------------------------------------------------------------------------------- /code_examples/theory/deduction_algorithm.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 2, 3, 4, 5, 6, 7, 8, 9}; 2 | 3 | auto v = std::accumulate(data.begin(), data.end(), 0); 4 | // 0 is a literal of type int. Internally this means that 5 | // the accumulator (and result) type of the algorithm will be 6 | // int, despite iterating over a container of type unsigned. 7 | 8 | // v == 45, decltype(v) == int -------------------------------------------------------------------------------- /code_examples/theory/deduction_concepts.h: -------------------------------------------------------------------------------- 1 | template concept IsInt = std::same_as; 2 | void function(const IsInt auto&) {} 3 | 4 | function(0); // OK 5 | // function(0u); // will fail to compile, deduced type unsigned -------------------------------------------------------------------------------- /code_examples/theory/floating_point.h: -------------------------------------------------------------------------------- 1 | auto src = UINT64_MAX - UINT32_MAX; 2 | auto m = (1.0f * src) * 1.0L; 3 | auto n = 1.0f * (src * 1.0L); 4 | // decltype(m) == decltype(n) == long double 5 | 6 | std::cout << std::fixed << m << "\n" << n << "\n" << src << "\n"; 7 | // 18446744073709551616.000000 8 | // 18446744069414584320.000000 9 | // 18446744069414584320 -------------------------------------------------------------------------------- /code_examples/theory/floating_point_ordering.h: -------------------------------------------------------------------------------- 1 | float v = 1.0f; 2 | float next = std::nextafter(v, 2.0f); 3 | // next is the next higher floating pointer number 4 | float diff = (next-v)/2; 5 | // diff is below the resolution of float 6 | // importantly: v + diff == v 7 | 8 | std::vector data1(100, diff); 9 | data1.front() = v; // data1 == { v, ... } 10 | float r1 = std::accumulate(data1.begin(), data1.end(), 0.f); 11 | // r1 == v 12 | // we added diff 99 times, but each time, the value did not change 13 | 14 | std::vector data2(100, diff); 15 | data2.back() = v; // data2 == { ..., v } 16 | float r2 = std::accumulate(data2.begin(), data2.end(), 0.f); 17 | // r2 != v 18 | // we added diff 99 times, but we did that before adding to v 19 | // the sum of 99 diffs is above the resolution threshold -------------------------------------------------------------------------------- /code_examples/theory/initializer_list.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "initializer_list_code.h" 9 | 10 | int main() { 11 | example(); 12 | assert(X::copy_cnt == 6); 13 | std::cerr << "."; 14 | } 15 | -------------------------------------------------------------------------------- /code_examples/theory/initializer_list_code.h: -------------------------------------------------------------------------------- 1 | struct X { 2 | static int copy_cnt; 3 | X(int v) : value(v) {} 4 | X(const X& other) : value(other.value) { 5 | ++copy_cnt; 6 | } 7 | int value; 8 | friend auto operator <=>(const X&, const X&) = default; 9 | }; 10 | 11 | int X::copy_cnt = 0; 12 | 13 | void example() { 14 | X a{1}, b{2}, c{3}, d{4}, e{5}; 15 | auto max = std::max({a, b, c, d, e}); 16 | // max.value == 5 17 | // X::copy_cnt == 6 18 | } 19 | -------------------------------------------------------------------------------- /code_examples/theory/integral_conversions_different_a.h: -------------------------------------------------------------------------------- 1 | int a = -100; 2 | unsigned b = 0; 3 | 4 | auto v = a + b; 5 | // v ~ -100 + (UINT_MAX + 1), decltype(v) == unsigned -------------------------------------------------------------------------------- /code_examples/theory/integral_conversions_different_b.h: -------------------------------------------------------------------------------- 1 | unsigned a = 100; 2 | long int b = -200; 3 | 4 | auto v = a + b; 5 | // v = -100, decltype(v) == long int -------------------------------------------------------------------------------- /code_examples/theory/integral_conversions_different_c.h: -------------------------------------------------------------------------------- 1 | long long a = -100; 2 | unsigned long b = 0; // assuming sizeof(long) == sizeof(long long) 3 | 4 | auto v = a + b; 5 | // v ~ -100 + (ULLONG_MAX + 1), decltype(v) == unsigned long long -------------------------------------------------------------------------------- /code_examples/theory/integral_conversions_problems.h: -------------------------------------------------------------------------------- 1 | int x = -1; 2 | unsigned y = 1; 3 | long z = -1; 4 | 5 | auto t1 = x > y; 6 | // x -> unsigned, t1 == true 7 | 8 | auto t2 = z < y; 9 | // y -> long, t2 == true -------------------------------------------------------------------------------- /code_examples/theory/integral_conversions_same.h: -------------------------------------------------------------------------------- 1 | int a = -100; 2 | long int b = 500; 3 | 4 | auto v = a + b; 5 | // v == 400, decltype(v) == long int -------------------------------------------------------------------------------- /code_examples/theory/integral_promotions.h: -------------------------------------------------------------------------------- 1 | uint16_t a = 1; 2 | uint16_t b = 2; 3 | 4 | auto v = a - b; 5 | // v == -1, decltype(v) == int -------------------------------------------------------------------------------- /code_examples/theory/references.h: -------------------------------------------------------------------------------- 1 | void function(const int& v) {} 2 | 3 | long a = 0; 4 | long long b = 0; 5 | // Even when long and long long have the same size 6 | static_assert(sizeof(a) == sizeof(b)); 7 | // The two types are unrelated in the context of references 8 | // The following two statements wouldn't compile: 9 | // long long& c = a; 10 | // long& d = b; 11 | 12 | // OK, but dangerous, implict conversion to int 13 | // int temporary can bind to const int& 14 | function(a); 15 | function(b); -------------------------------------------------------------------------------- /code_examples/theory/safe_compare.h: -------------------------------------------------------------------------------- 1 | int x = -1; 2 | unsigned y = 1; 3 | long z = -1; 4 | 5 | auto t1 = x > y; 6 | auto t2 = std::cmp_greater(x,y); 7 | // t1 == true, t2 == false 8 | 9 | auto t3 = z < y; 10 | auto t4 = std::cmp_less(z,y); 11 | // t3 == true, t4 == true -------------------------------------------------------------------------------- /code_examples/theory/safe_in_range.h: -------------------------------------------------------------------------------- 1 | auto t1 = std::in_range(UINT_MAX); 2 | // t1 == false 3 | auto t2 = std::in_range(0); 4 | // t2 == true 5 | auto t3 = std::in_range(-1); 6 | // t3 == false -------------------------------------------------------------------------------- /code_examples/theory/safe_ssize.h: -------------------------------------------------------------------------------- 1 | std::vector data{1,2,3,4,5,6,7,8,9}; 2 | // std::ssize returns ptrdiff_t, avoiding mixing 3 | // a signed and unsigned integer in the comparison 4 | for (ptrdiff_t i = 0; i < std::ssize(data); i++) { 5 | std::cout << data[i] << " "; 6 | } 7 | std::cout << "\n"; 8 | // prints: "1 2 3 4 5 6 7 8 9" -------------------------------------------------------------------------------- /code_examples/verify.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | CMAKE="/usr/bin/cmake" 3 | set -e 4 | 5 | $CMAKE -S. -B build -G "Unix Makefiles" 6 | $CMAKE --build build 7 | $CMAKE --install build --prefix . 8 | 9 | for executable in bin/*; do 10 | $executable 1> /dev/null 11 | done 12 | 13 | echo "All good!" 14 | -------------------------------------------------------------------------------- /code_examples/views/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Doesn't compile with GCC 11 2 | #add_executable(keys_values keys_values.cpp) 3 | #install(TARGETS keys_values DESTINATION bin) 4 | 5 | # Doesn't compile with GCC 11 6 | #add_executable(elements elements.cpp) 7 | #install(TARGETS elements DESTINATION bin) 8 | 9 | # Doesn't compile with GCC 11 10 | #add_executable(take take.cpp) 11 | #install(TARGETS take DESTINATION bin) 12 | 13 | # Doesn't compile with GCC 11 14 | #add_executable(drop drop.cpp) 15 | #install(TARGETS drop DESTINATION bin) 16 | 17 | # Doesn't compile with GCC 11 18 | #add_executable(filter filter.cpp) 19 | #install(TARGETS filter DESTINATION bin) 20 | 21 | # Doesn't compile with GCC 11 22 | #add_executable(reverse_view reverse.cpp) 23 | #install(TARGETS reverse_view DESTINATION bin) 24 | 25 | # Doesn't compile with GCC 11 26 | #add_executable(counted_view counted.cpp) 27 | #install(TARGETS counted_view DESTINATION bin) 28 | 29 | # Doesn't compile with GCC 11 30 | #add_executable(common_view common.cpp) 31 | #install(TARGETS common_view DESTINATION bin) 32 | 33 | # Doesn't compile with GCC 11 34 | #add_executable(all_view all.cpp) 35 | #install(TARGETS all_view DESTINATION bin) 36 | 37 | # Doesn't compile with GCC 11 38 | #add_executable(split_view split.cpp) 39 | #install(TARGETS split_view DESTINATION bin) 40 | 41 | # Doesn't compile with GCC 11 42 | #add_executable(transform_view transform.cpp) 43 | #install(TARGETS transform_view DESTINATION bin) 44 | 45 | # Doesn't compile with GCC 11 46 | #add_executable(join_view join.cpp) 47 | #install(TARGETS join_view DESTINATION bin) 48 | 49 | # Doesn't compile with GCC 11 50 | #add_executable(single_view single.cpp) 51 | #install(TARGETS single_view DESTINATION bin) 52 | 53 | # Doesn't compile with GCC 11 54 | #add_executable(iota_view iota.cpp) 55 | #install(TARGETS iota_view DESTINATION bin) 56 | 57 | # Doesn't compile with GCC 11 58 | #add_executable(istream_view istream.cpp) 59 | #install(TARGETS istream_view DESTINATION bin) 60 | -------------------------------------------------------------------------------- /code_examples/views/all.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | #include "all_code.h" 10 | auto cmp1 = {1, 2, 3, 4}; 11 | assert(std::ranges::equal(out, cmp1)); 12 | } 13 | -------------------------------------------------------------------------------- /code_examples/views/all_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 2, 3, 4}; 2 | 3 | std::vector out; 4 | std::ranges::copy(std::views::all(data), std::back_inserter(out)); 5 | // out == {1, 2, 3, 4} 6 | -------------------------------------------------------------------------------- /code_examples/views/common.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | #include "common_code.h" 10 | auto cmp1 = {2, 4, 6, 8}; 11 | assert(std::ranges::equal(out, cmp1)); 12 | } 13 | -------------------------------------------------------------------------------- /code_examples/views/common_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 2, 3, 4, 5, 6, 7, 8}; 2 | 3 | std::vector out; 4 | auto view = data | 5 | std::views::filter([](int v) { return v % 2 == 0; }) | 6 | std::views::common; 7 | 8 | std::copy(view.begin(), view.end(), std::back_inserter(out)); 9 | // out == {2, 4, 6, 8} 10 | -------------------------------------------------------------------------------- /code_examples/views/counted.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | #include "counted_code.h" 10 | auto cmp1 = {2, 3, 4}; 11 | assert(std::ranges::equal(out, cmp1)); 12 | } 13 | -------------------------------------------------------------------------------- /code_examples/views/counted_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 2, 3, 4, 5, 6, 7, 8}; 2 | 3 | std::vector out; 4 | std::ranges::copy(std::views::counted(std::next(data.begin()), 3), 5 | std::back_inserter(out)); 6 | // out == {2, 3, 4} 7 | -------------------------------------------------------------------------------- /code_examples/views/drop.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | #include "drop_code.h" 10 | auto cmp1 = {7, 2, 4, 6, 8}; 11 | assert(std::ranges::equal(out1, cmp1)); 12 | auto cmp2 = {2, 4, 6, 8}; 13 | assert(std::ranges::equal(out2, cmp2)); 14 | } 15 | -------------------------------------------------------------------------------- /code_examples/views/drop_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 3, 5, 7, 2, 4, 6, 8}; 2 | 3 | std::vector out1; 4 | std::ranges::copy(data | std::views::drop(3), 5 | std::back_inserter(out1)); 6 | // out1 == {7, 2, 4, 6, 8} 7 | 8 | std::vector out2; 9 | std::ranges::copy(data | 10 | std::views::drop_while([](int v) { return v % 2 != 0; }), 11 | std::back_inserter(out2)); 12 | // out2 == {2, 4, 6, 8} 13 | -------------------------------------------------------------------------------- /code_examples/views/elements.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | #include "elements_code.h" 10 | std::vector cmp1 = {"Cat", "Dog", "Car"}; 11 | assert(std::ranges::equal(third, cmp1)); 12 | auto cmp2 = {100, 99, 17}; 13 | assert(std::ranges::equal(second, cmp2)); 14 | std::cerr << "."; 15 | } 16 | -------------------------------------------------------------------------------- /code_examples/views/elements_code.h: -------------------------------------------------------------------------------- 1 | std::vector> data{ 2 | {1, 100, "Cat"}, {2, 99, "Dog"}, {3, 17, "Car"}, 3 | }; 4 | 5 | std::vector second; 6 | std::ranges::copy(data | std::views::elements<1>, 7 | std::back_inserter(second)); 8 | // second == {100, 99, 17} 9 | 10 | std::vector third; 11 | std::ranges::copy(data | std::views::elements<2>, 12 | std::back_inserter(third)); 13 | // third == {"Cat", "Dog", "Car"} -------------------------------------------------------------------------------- /code_examples/views/filter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | #include "filter_code.h" 10 | auto cmp1 = {2, 4, 6, 8}; 11 | assert(std::ranges::equal(even, cmp1)); 12 | std::cerr << "."; 13 | } 14 | -------------------------------------------------------------------------------- /code_examples/views/filter_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 2, 3, 4, 5, 6, 7, 8}; 2 | 3 | std::vector even; 4 | std::ranges::copy(data | 5 | std::views::filter([](int v) { return v % 2 == 0; }), 6 | std::back_inserter(even)); 7 | // even == {2, 4, 6, 8} 8 | -------------------------------------------------------------------------------- /code_examples/views/iota.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | #include "iota_code.h" 9 | auto cmp1 = {2, 3, 4}; 10 | assert(std::ranges::equal(cmp1, out1)); 11 | auto cmp2 = {42, 43, 44, 45, 46}; 12 | assert(std::ranges::equal(cmp2, out2)); 13 | } 14 | -------------------------------------------------------------------------------- /code_examples/views/iota_code.h: -------------------------------------------------------------------------------- 1 | std::vector out1; 2 | std::ranges::copy(std::views::iota(2,5), std::back_inserter(out1)); 3 | // finite view [2, 5), out == {2, 3, 4} 4 | 5 | std::vector out2; 6 | std::ranges::copy(std::views::iota(42) | std::views::take(5), 7 | std::back_inserter(out2)); 8 | // infinite view starting with 42, take(5) takes the first five elements from this view 9 | // out2 == {42, 43, 44, 45, 46} 10 | -------------------------------------------------------------------------------- /code_examples/views/istream.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | #include "istream_code.h" 9 | } 10 | -------------------------------------------------------------------------------- /code_examples/views/istream_code.h: -------------------------------------------------------------------------------- 1 | std::ranges::for_each(std::views::istream(std::cin), [](int v) { 2 | // iterate over integers on standard input 3 | }); 4 | -------------------------------------------------------------------------------- /code_examples/views/join.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main() { 12 | #include "join_code.h" 13 | assert(out == "CarDogWindow"); 14 | std::vector cmp = {"Car", "Dog", "Window"}; 15 | assert(std::ranges::equal(cmp, words)); 16 | } 17 | -------------------------------------------------------------------------------- /code_examples/views/join_code.h: -------------------------------------------------------------------------------- 1 | std::string_view data = "Car Dog Window"; 2 | std::vector words; 3 | std::ranges::for_each(data | std::views::lazy_split(' '), 4 | [&words](auto const& view) { 5 | // string constructor needs common range. 6 | auto common = view | std::views::common; 7 | words.emplace_back(common.begin(), common.end()); 8 | }); 9 | // words == {"Car", "Dog", "Window"} 10 | 11 | auto joined = data | std::views::lazy_split(' ') | std::views::join | std::views::common; 12 | std::string out(joined.begin(), joined.end()); 13 | // out == "CarDogWindow" 14 | -------------------------------------------------------------------------------- /code_examples/views/keys_values.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | #include "keys_values_code.h" 10 | 11 | auto cmp1 = {0, 1, 2, 3}; 12 | auto cmp2 = {1.0, 1.5, 2.0, 2.5}; 13 | assert(std::ranges::is_permutation(keys, cmp1)); 14 | assert(std::ranges::is_permutation(values, cmp2)); 15 | 16 | std::cerr << "."; 17 | } 18 | -------------------------------------------------------------------------------- /code_examples/views/keys_values_code.h: -------------------------------------------------------------------------------- 1 | std::unordered_map map{ 2 | {0, 1.0}, {1, 1.5}, {2, 2.0}, {3, 2.5} 3 | }; 4 | 5 | std::vector keys; 6 | std::ranges::copy(std::views::keys(map), std::back_inserter(keys)); 7 | // keys == {0, 1, 2, 3} in unspecified order (std::unordered_map) 8 | 9 | std::vector values; 10 | std::ranges::copy(std::views::values(map), 11 | std::back_inserter(values)); 12 | // values == {1.0, 1.5, 2.0, 2.5} 13 | // in unspecified order matching order of keys -------------------------------------------------------------------------------- /code_examples/views/reverse.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | #include "reverse_code.h" 10 | auto cmp1 = {4, 3, 2, 1}; 11 | assert(std::ranges::equal(out, cmp1)); 12 | } 13 | -------------------------------------------------------------------------------- /code_examples/views/reverse_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 2, 3, 4}; 2 | 3 | std::vector out; 4 | std::ranges::copy(data | std::views::reverse, 5 | std::back_inserter(out)); 6 | // out == {4, 3, 2, 1} 7 | -------------------------------------------------------------------------------- /code_examples/views/single.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | #include "single_code.h" 9 | assert(out.size() == 1); 10 | assert(out[0] == 42); 11 | } 12 | -------------------------------------------------------------------------------- /code_examples/views/single_code.h: -------------------------------------------------------------------------------- 1 | std::vector out; 2 | std::ranges::copy(std::views::empty, std::back_inserter(out)); 3 | // out == {} 4 | 5 | std::ranges::copy(std::views::single(42), std::back_inserter(out)); 6 | // out == {42} 7 | -------------------------------------------------------------------------------- /code_examples/views/split.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main() { 10 | #include "split_code.h" 11 | auto cmp1 = {1, 23, 13, 42}; 12 | assert(std::ranges::equal(parsed, cmp1)); 13 | } 14 | -------------------------------------------------------------------------------- /code_examples/views/split_code.h: -------------------------------------------------------------------------------- 1 | std::string version = "1.23.13.42"; 2 | std::vector parsed; 3 | 4 | std::ranges::copy(version | 5 | std::views::split('.') | 6 | std::views::transform([](auto v) { 7 | int result = 0; 8 | // from_chars requires contiguous range 9 | std::from_chars(v.data(), v.data()+v.size(), result); 10 | return result; 11 | }), 12 | std::back_inserter(parsed)); 13 | // parsed == {1, 23, 13, 42} 14 | -------------------------------------------------------------------------------- /code_examples/views/take.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | #include "take_code.h" 10 | auto cmp1 = {1, 3, 5}; 11 | assert(std::ranges::equal(out1, cmp1)); 12 | auto cmp2 = {1, 3, 5, 7}; 13 | assert(std::ranges::equal(out2, cmp2)); 14 | } 15 | -------------------------------------------------------------------------------- /code_examples/views/take_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1, 3, 5, 7, 2, 4, 6, 8}; 2 | 3 | std::vector out1; 4 | std::ranges::copy(data | std::views::take(3), 5 | std::back_inserter(out1)); 6 | // out1 == {1, 3, 5} 7 | 8 | std::vector out2; 9 | std::ranges::copy(data | 10 | std::views::take_while([](int v) { return v % 2 != 0; }), 11 | std::back_inserter(out2)); 12 | // out2 == {1, 3, 5, 7} 13 | -------------------------------------------------------------------------------- /code_examples/views/transform.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main() { 10 | #include "transform_code.h" 11 | auto cmp1 = {1, 5, 9, 20, 50, 67}; 12 | assert(std::ranges::equal(out, cmp1)); 13 | } 14 | -------------------------------------------------------------------------------- /code_examples/views/transform_code.h: -------------------------------------------------------------------------------- 1 | std::vector data{1.2, 2.3, 3.1, 4.5, 7.1, 8.2}; 2 | 3 | std::vector out; 4 | std::ranges::copy(data | 5 | std::views::transform([](auto v) -> int { 6 | return v*v; 7 | }), std::back_inserter(out)); 8 | // out == {1, 5, 9, 20, 50, 67} 9 | -------------------------------------------------------------------------------- /packages/custom_commands/CC.tex: -------------------------------------------------------------------------------- 1 | % Manually micro-typed "C++" 2 | 3 | %\newcommand{\CC}{C\nolinebreak[4]\hspace{-.1em}\raisebox{.25ex}{\small ++}\hspace{.1em}} 4 | \newcommand{\CC}{C\nolinebreak[4]\hspace{-.1em}\sbox0{$1$}\sbox2{\small++}\raise\dimexpr(\ht0-\ht2)/2\relax\box2\hspace{.1em}} -------------------------------------------------------------------------------- /packages/custom_commands/ExternalLink.tex: -------------------------------------------------------------------------------- 1 | % Sourced from 2 | % https://tex.stackexchange.com/questions/99316/symbol-for-external-links 3 | \newcommand{\ExternalLink}{% 4 | \tikz[x=1.2ex, y=1.2ex, baseline=-0.05ex]{% 5 | \begin{scope}[x=1ex, y=1ex] 6 | \clip (-0.1,-0.1) 7 | --++ (-0, 1.2) 8 | --++ (0.6, 0) 9 | --++ (0, -0.6) 10 | --++ (0.6, 0) 11 | --++ (0, -1); 12 | \path[draw, 13 | line width = 0.5, 14 | rounded corners=0.5] 15 | (0,0) rectangle (1,1); 16 | \end{scope} 17 | \path[draw, line width = 0.5] (0.5, 0.5) 18 | -- (1, 1); 19 | \path[draw, line width = 0.5] (0.6, 1) 20 | -- (1, 1) -- (1, 0.6); 21 | } 22 | } -------------------------------------------------------------------------------- /packages/custom_commands/circled.tex: -------------------------------------------------------------------------------- 1 | \usepackage{enumitem} 2 | \newcommand*\circled[1]{\tikz[baseline=(char.base)]{ 3 | \node[shape=circle,draw,inner sep=1pt] (char) {#1};}} -------------------------------------------------------------------------------- /packages/custom_commands/codebox.tex: -------------------------------------------------------------------------------- 1 | \usepackage[many]{tcolorbox} % for COLORED BOXES (tikz and xcolor included) 2 | 3 | \newtcolorbox{codebox}[2][]{ 4 | sharpish corners, % better drop shadow 5 | boxrule = 0pt, 6 | toprule = 4.5pt, % top rule weight 7 | enhanced, 8 | enlarge top by=5pt, 9 | colback = white, 10 | before skip = 0.2cm, % add extra space before the box 11 | after skip = 0.5cm, % add extra space after the box 12 | drop fuzzy shadow = black!35, 13 | fontupper=\footnotesize\sffamily, 14 | fonttitle=\footnotesize\sffamily\color{black}, 15 | title=Open in Compiler Explorer #2, 16 | attach boxed title to bottom right={xshift=6pt,yshift=6pt}, 17 | boxed title style={ 18 | enhanced, 19 | arc=0pt, 20 | outer arc=0pt, 21 | boxrule = 0pt, 22 | colback = white, 23 | drop fuzzy shadow = black!35, 24 | }, 25 | #1, 26 | } -------------------------------------------------------------------------------- /packages/custom_commands/constraints.tex: -------------------------------------------------------------------------------- 1 | % Command to consistently format the algorithm info table. 2 | \newcommand{\constraints}[4]{ 3 | \begin{center} 4 | \footnotesize 5 | \begin{tabular}{|m{\dimexpr.22\textwidth-2\tabcolsep}|m{\dimexpr.30\textwidth-2\tabcolsep}|m{\dimexpr.45\textwidth-2\tabcolsep}|} 6 | \hline 7 | \rowcolor{black!80} \multicolumn{3}{l}{\textcolor{white}{constraints}} \\ 8 | 9 | \hline 10 | domain & \multicolumn{2}{m{\dimexpr.75\textwidth-2\tabcolsep}|}{#1} \\ 11 | 12 | 13 | \ifx\hfuzz#2\hfuzz\else 14 | \hline 15 | parallel domain & \multicolumn{2}{m{\dimexpr.75\textwidth-2\tabcolsep}|}{#2} \\ 16 | \fi 17 | 18 | \ifx\hfuzz#3#4\hfuzz\else 19 | \hline 20 | \multirow{2}{.15\textwidth}{invocable} & \cellcolor{black!80} \textcolor{white}{default} & \cellcolor{black!80} \textcolor{white}{custom} \\ 21 | \cline{2-3} 22 | & #3 & #4 \\ 23 | \fi 24 | 25 | \hline 26 | \end{tabular} 27 | \end{center} 28 | } -------------------------------------------------------------------------------- /packages/custom_commands/cpp.tex: -------------------------------------------------------------------------------- 1 | % Overleaf botch. Normally we use minted files in the build folder, but Overleaf needs special care. 2 | \def\StripPrefix#1>{} 3 | \def\isOverleaf{\fi 4 | \def\overleafJobname{output}% overleaf defaults to 'output' as \jobname 5 | \edef\overleafJobname{\expandafter\StripPrefix\meaning\overleafJobname}% 6 | \edef\job{\jobname}% 7 | \ifx\job\overleafJobname 8 | } 9 | 10 | \if\isOverleaf% 11 | \usepackage[newfloat=true]{minted} 12 | \else 13 | \usepackage[newfloat=true,cachedir=mint,outputdir=build]{minted} 14 | \fi 15 | 16 | \usepackage[]{xcolor} 17 | \usemintedstyle{xcode} 18 | \renewcommand\theFancyVerbLine{\footnotesize\arabic{FancyVerbLine}} 19 | 20 | \newmintedfile[cppfile]{cpp}{ 21 | linenos=true, 22 | firstnumber=1, 23 | tabsize=4, 24 | obeytabs, 25 | xleftmargin=1em, 26 | breaklines, 27 | fontsize=\footnotesize, 28 | numbersep=0.75em 29 | } 30 | 31 | \newmintinline[cpp]{cpp}{} -------------------------------------------------------------------------------- /packages/custom_commands/cppversions.tex: -------------------------------------------------------------------------------- 1 | % Command to consistently format side-panel with C++ versions 2 | % that introduced different variants of the algorithm. 3 | \newcommand{\cppversions}[5]{ 4 | \begin{margintable} 5 | \footnotesize 6 | \begin{tabular}{|m{\dimexpr.5\marginparwidth-2\tabcolsep-1pt}|m{\dimexpr.5\marginparwidth-2\tabcolsep-1pt}|} 7 | \rowcolor{black!80} \multicolumn{2}{c}{\textcolor{white}{#1}} \\ 8 | introduced & #2 \\ 9 | \hline 10 | constexpr & #3 \\ 11 | \hline 12 | parallel & #4 \\ 13 | \hline 14 | rangified & #5 \\ 15 | \hline 16 | \end{tabular} 17 | \end{margintable} 18 | } -------------------------------------------------------------------------------- /packages/custom_commands/version.tex: -------------------------------------------------------------------------------- 1 | \newcommand{\version}{1.0.1} -------------------------------------------------------------------------------- /packages/fonts.tex: -------------------------------------------------------------------------------- 1 | \usepackage{microtype} 2 | \usepackage{fontspec} 3 | 4 | \setromanfont{Brygada1918}[ 5 | Path=./static/fonts/brygada/, 6 | Extension = .ttf, 7 | UprightFont=*-Regular, 8 | BoldFont=*-Bold, 9 | ItalicFont=*-Italic, 10 | BoldItalicFont=*-BoldItalic 11 | ] 12 | 13 | 14 | \setsansfont{Asap}[ 15 | Path=./static/fonts/asap/, 16 | Scale=0.9, 17 | Extension = .ttf, 18 | UprightFont=*-Regular, 19 | BoldFont=*-Bold, 20 | ItalicFont=*-Italic, 21 | BoldItalicFont=*-BoldItalic 22 | ] 23 | 24 | \setmonofont{JetBrainsMono}[ 25 | Path=./static/fonts/jetbrains/, 26 | Scale=0.85, 27 | Extension = .ttf, 28 | UprightFont=*-Regular, 29 | BoldFont=*-Bold, 30 | ItalicFont=*-Italic, 31 | BoldItalicFont=*-BoldItalic, 32 | Contextuals=AlternateOff 33 | ] 34 | 35 | \renewcommand{\familydefault}{\sfdefault} -------------------------------------------------------------------------------- /packages/hyperref.tex: -------------------------------------------------------------------------------- 1 | \usepackage{hyperref} 2 | \hypersetup{ 3 | colorlinks=true, 4 | linkcolor=blue, 5 | filecolor=magenta, 6 | urlcolor=cyan, 7 | pdftitle={Standard C++ Algorithms}, 8 | pdfpagemode=FullScreen, 9 | } -------------------------------------------------------------------------------- /packages/packages.tex: -------------------------------------------------------------------------------- 1 | \usepackage{sidenotes} % Required 2 | \usepackage{multirow} % Required 3 | \usepackage{diagbox} % Used for boolean algorithms. 4 | \usepackage{tikz} % Used for External link icon 5 | 6 | \usepackage{imakeidx} 7 | \makeindex 8 | 9 | \input{packages/fonts} 10 | \input{packages/hyperref} 11 | 12 | % Custom commands 13 | \input{packages/custom_commands/ExternalLink} 14 | \input{packages/custom_commands/cppversions} 15 | \input{packages/custom_commands/constraints} 16 | \input{packages/custom_commands/CC} 17 | \input{packages/custom_commands/circled} 18 | \input{packages/custom_commands/version} 19 | \input{packages/custom_commands/codebox} 20 | \input{packages/custom_commands/cpp} -------------------------------------------------------------------------------- /static/book_cover.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/book_cover.pdf -------------------------------------------------------------------------------- /static/book_cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/book_cover.png -------------------------------------------------------------------------------- /static/fonts/asap/Asap-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/asap/Asap-Bold.ttf -------------------------------------------------------------------------------- /static/fonts/asap/Asap-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/asap/Asap-BoldItalic.ttf -------------------------------------------------------------------------------- /static/fonts/asap/Asap-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/asap/Asap-Italic.ttf -------------------------------------------------------------------------------- /static/fonts/asap/Asap-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/asap/Asap-Medium.ttf -------------------------------------------------------------------------------- /static/fonts/asap/Asap-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/asap/Asap-MediumItalic.ttf -------------------------------------------------------------------------------- /static/fonts/asap/Asap-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/asap/Asap-Regular.ttf -------------------------------------------------------------------------------- /static/fonts/asap/Asap-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/asap/Asap-SemiBold.ttf -------------------------------------------------------------------------------- /static/fonts/asap/Asap-SemiBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/asap/Asap-SemiBoldItalic.ttf -------------------------------------------------------------------------------- /static/fonts/brygada/Brygada1918-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/brygada/Brygada1918-Bold.ttf -------------------------------------------------------------------------------- /static/fonts/brygada/Brygada1918-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/brygada/Brygada1918-BoldItalic.ttf -------------------------------------------------------------------------------- /static/fonts/brygada/Brygada1918-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/brygada/Brygada1918-Italic.ttf -------------------------------------------------------------------------------- /static/fonts/brygada/Brygada1918-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/brygada/Brygada1918-Medium.ttf -------------------------------------------------------------------------------- /static/fonts/brygada/Brygada1918-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/brygada/Brygada1918-MediumItalic.ttf -------------------------------------------------------------------------------- /static/fonts/brygada/Brygada1918-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/brygada/Brygada1918-Regular.ttf -------------------------------------------------------------------------------- /static/fonts/brygada/Brygada1918-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/brygada/Brygada1918-SemiBold.ttf -------------------------------------------------------------------------------- /static/fonts/brygada/Brygada1918-SemiBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/brygada/Brygada1918-SemiBoldItalic.ttf -------------------------------------------------------------------------------- /static/fonts/jetbrains/JetBrainsMono-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/jetbrains/JetBrainsMono-Bold.ttf -------------------------------------------------------------------------------- /static/fonts/jetbrains/JetBrainsMono-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/jetbrains/JetBrainsMono-BoldItalic.ttf -------------------------------------------------------------------------------- /static/fonts/jetbrains/JetBrainsMono-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/jetbrains/JetBrainsMono-ExtraBold.ttf -------------------------------------------------------------------------------- /static/fonts/jetbrains/JetBrainsMono-ExtraBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/jetbrains/JetBrainsMono-ExtraBoldItalic.ttf -------------------------------------------------------------------------------- /static/fonts/jetbrains/JetBrainsMono-ExtraLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/jetbrains/JetBrainsMono-ExtraLight.ttf -------------------------------------------------------------------------------- /static/fonts/jetbrains/JetBrainsMono-ExtraLightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/jetbrains/JetBrainsMono-ExtraLightItalic.ttf -------------------------------------------------------------------------------- /static/fonts/jetbrains/JetBrainsMono-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/jetbrains/JetBrainsMono-Italic.ttf -------------------------------------------------------------------------------- /static/fonts/jetbrains/JetBrainsMono-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/jetbrains/JetBrainsMono-Light.ttf -------------------------------------------------------------------------------- /static/fonts/jetbrains/JetBrainsMono-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/jetbrains/JetBrainsMono-LightItalic.ttf -------------------------------------------------------------------------------- /static/fonts/jetbrains/JetBrainsMono-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/jetbrains/JetBrainsMono-Medium.ttf -------------------------------------------------------------------------------- /static/fonts/jetbrains/JetBrainsMono-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/jetbrains/JetBrainsMono-MediumItalic.ttf -------------------------------------------------------------------------------- /static/fonts/jetbrains/JetBrainsMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/jetbrains/JetBrainsMono-Regular.ttf -------------------------------------------------------------------------------- /static/fonts/jetbrains/JetBrainsMono-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/jetbrains/JetBrainsMono-SemiBold.ttf -------------------------------------------------------------------------------- /static/fonts/jetbrains/JetBrainsMono-SemiBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/jetbrains/JetBrainsMono-SemiBoldItalic.ttf -------------------------------------------------------------------------------- /static/fonts/jetbrains/JetBrainsMono-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/jetbrains/JetBrainsMono-Thin.ttf -------------------------------------------------------------------------------- /static/fonts/jetbrains/JetBrainsMono-ThinItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HappyCerberus/book-cpp-algorithms/58c4122b5e0cda0afa351d7fd0436b878fff0daa/static/fonts/jetbrains/JetBrainsMono-ThinItalic.ttf --------------------------------------------------------------------------------