diff --git a/.all-contributorsrc b/.all-contributorsrc deleted file mode 100644 index 9741cb97..00000000 --- a/.all-contributorsrc +++ /dev/null @@ -1,115 +0,0 @@ -{ - "projectName": "cpluspluscourse", - "projectOwner": "hsf-training", - "repoType": "github", - "repoHost": "https://github.com", - "contributorsSortAlphabetically": true, - "files": [ - "README.md" - ], - "imageSize": 100, - "commit": true, - "commitConvention": "gitmoji", - "contributors": [ - { - "login": "chavid", - "name": "David Chamont", - "avatar_url": "https://avatars.githubusercontent.com/u/4421289?v=4", - "profile": "https://github.com/chavid", - "contributions": [ - "content" - ] - }, - { - "login": "hageboeck", - "name": "Stephan Hageboeck", - "avatar_url": "https://avatars.githubusercontent.com/u/16205615?v=4", - "profile": "https://github.com/hageboeck", - "contributions": [ - "content" - ] - }, - { - "login": "bernhardmgruber", - "name": "Bernhard Manfred Gruber", - "avatar_url": "https://avatars.githubusercontent.com/u/1224051?v=4", - "profile": "https://github.com/bernhardmgruber", - "contributions": [ - "content" - ] - }, - { - "login": "eguiraud", - "name": "Enrico Guiraud", - "avatar_url": "https://avatars.githubusercontent.com/u/10999034?v=4", - "profile": "https://github.com/eguiraud", - "contributions": [ - "content" - ] - }, - { - "login": "roiser", - "name": "Stefan Roiser", - "avatar_url": "https://avatars.githubusercontent.com/u/807095?v=4", - "profile": "https://github.com/roiser", - "contributions": [ - "content" - ] - }, - { - "login": "sponce", - "name": "Sebastien Ponce", - "avatar_url": "https://avatars.githubusercontent.com/u/731524?v=4", - "profile": "https://github.com/sponce", - "contributions": [ - "content" - ] - }, - { - "login": "theanalyst", - "name": "Abhishek L", - "avatar_url": "https://avatars.githubusercontent.com/u/1433152?v=4", - "profile": "http://includeio.stream/", - "contributions": [ - "content" - ] - }, - { - "login": "graeme-a-stewart", - "name": "Graeme A Stewart", - "avatar_url": "https://avatars.githubusercontent.com/u/8511620?v=4", - "profile": "https://github.com/graeme-a-stewart", - "contributions": [ - "content" - ] - }, - { - "login": "krasznaa", - "name": "Attila Krasznahorkay", - "avatar_url": "https://avatars.githubusercontent.com/u/30694331?v=4", - "profile": "https://github.com/krasznaa", - "contributions": [ - "content" - ] - }, - { - "login": "bcouturi", - "name": "bcouturi", - "avatar_url": "https://avatars.githubusercontent.com/u/7208288?v=4", - "profile": "https://github.com/bcouturi", - "contributions": [ - "content" - ] - }, - { - "login": "klieret", - "name": "Kilian Lieret", - "avatar_url": "https://avatars.githubusercontent.com/u/13602468?v=4", - "profile": "https://www.lieret.net/", - "contributions": [ - "infra" - ] - } - ], - "contributorsPerLine": 7 -} diff --git a/.github/config.yml b/.github/config.yml deleted file mode 100644 index eb7b72f8..00000000 --- a/.github/config.yml +++ /dev/null @@ -1,37 +0,0 @@ -# === IMPORTANT: CENTRALLY MAINTAINED FILE === -# This file was automatically added via the scripts at the maintenance repository. -# Please do not change it. Rather, update the blueprint in the maintenance repository and propagate -# the changes from there. -# IF YOU REALLY WANT TO MAKE REPOSITORY SPECIFIC CHANGES TO THIS FILE, PLEASE REMOVE THIS NOTICE! -# Tag @klieret for any questions. -# ====== - -# Configuration for welcome - https://github.com/behaviorbot/welcome - -# Configuration for new-issue-welcome - https://github.com/behaviorbot/new-issue-welcome - -# Comment to be posted to on first time issues -newIssueWelcomeComment: > - Thanks for opening your first issue here! If you have any questions, feel free - to mention one of the conveners, previous contributors, or attend our weekly meeting (see - https://hepsoftwarefoundation.org/workinggroups/training.html). - Also, sometimes issues go unnoticed, so don't hesitate to @mention some of - us, if we do not come back to you within a few days. - -# Configuration for new-pr-welcome - https://github.com/behaviorbot/new-pr-welcome - -# Comment to be posted to on PRs from first time contributors in your repository -newPRWelcomeComment: > - Thanks for opening your first pull request here! If you have any questions, feel free - to mention one of the conveners, previous contributors, or attend our weekly meeting (see - https://hepsoftwarefoundation.org/workinggroups/training.html). - Also, sometimes PRs go unnoticed, so don't hesitate to @mention some of - us, if we do not come back to you within a few days. - -# Configuration for first-pr-merge - https://github.com/behaviorbot/first-pr-merge - -# Comment to be posted to on pull requests merged by a first time user -firstPRMergeComment: > - Congrats on merging your first pull request! We at HSF are proud of you! - -# It is recommended to include as many gifs and emojis as possible! diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 6fddca0d..00000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,7 +0,0 @@ -version: 2 -updates: - # Maintain dependencies for GitHub Actions - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "weekly" diff --git a/.github/stale.yml b/.github/stale.yml deleted file mode 100644 index 1a80ec3b..00000000 --- a/.github/stale.yml +++ /dev/null @@ -1,62 +0,0 @@ -# Configuration for probot-stale - https://github.com/probot/stale - -# Number of days of inactivity before an Issue or Pull Request becomes stale -daysUntilStale: 365 - -# Number of days of inactivity before an Issue or Pull Request with the stale label is closed. -# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. -daysUntilClose: false - -# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) -onlyLabels: [] - -# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable -exemptLabels: - - pinned - - security - - "[Status] Maybe Later" - -# Set to true to ignore issues in a project (defaults to false) -exemptProjects: false - -# Set to true to ignore issues in a milestone (defaults to false) -exemptMilestones: true - -# Set to true to ignore issues with an assignee (defaults to false) -exemptAssignees: true - -# Label to use when marking as stale -staleLabel: stale - -# Comment to post when marking as stale. Set to `false` to disable -markComment: > - This issue or pull request has been automatically marked as stale because it has not had - recent activity. Please manually close it, if it is no longer relevant, - or ask for help or support to help getting it unstuck. - Let me bring this to the attention of @klieret @wdconinc @michmx for now. - -# Comment to post when removing the stale label. -# unmarkComment: > -# Your comment here. - -# Comment to post when closing a stale Issue or Pull Request. -# closeComment: > -# Your comment here. - -# Limit the number of actions per hour, from 1-30. Default is 30 -limitPerRun: 30 - -# Limit to only `issues` or `pulls` -# only: issues - -# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': -# pulls: -# daysUntilStale: 30 -# markComment: > -# This pull request has been automatically marked as stale because it has not had -# recent activity. It will be closed if no further activity occurs. Thank you -# for your contributions. - -# issues: -# exemptLabels: -# - confirmed diff --git a/.github/workflows/build-exercises.yml b/.github/workflows/build-exercises.yml deleted file mode 100644 index c67368f6..00000000 --- a/.github/workflows/build-exercises.yml +++ /dev/null @@ -1,124 +0,0 @@ -name: Build exercises -on: - push: - paths: - - 'exercises/**' - pull_request: - paths: - - 'exercises/**' - - '.github/workflows/**' - -# Cancel running jobs on force-push -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} - cancel-in-progress: true - -jobs: - # Native (non-container) build jobs. - native: - # The "build matrix". - strategy: - matrix: - EXERCISE: - - NAME: "asan" - - NAME: "basicTypes" - - NAME: "callgrind" - - NAME: "concepts" - - NAME: "condition_variable" - - NAME: "constness" - SKIP_DEFAULT: true - SKIP_SOLUTION: true - - NAME: "control" - - NAME: "cppcheck" - - NAME: "debug" - - NAME: "functions" - - NAME: "helgrind" - - NAME: "hello" - SKIP_SOLUTION: true - - NAME: "loopsRefsAuto" - - NAME: "memcheck" - - NAME: "modern_oo" - - NAME: "move" - - NAME: "classes" - SKIP_DEFAULT: true - - NAME: "operators" - - NAME: "optional" - - NAME: "polymorphism" - - NAME: "python" - SKIP_SOLUTION: true - - NAME: "race" - - NAME: "smartPointers" - - NAME: "spaceship" - - NAME: "stl" - SKIP_DEFAULT: true - - NAME: "templates" - - NAME: "valgrind" - - NAME: "variadic" - SKIP_DEFAULT: true - - NAME: "variant" - - NAME: "virtual_inheritance" - PLATFORM: - - OS: "ubuntu-22.04" - GENERATOR: -G "Unix Makefiles" - env: - CXX: g++-11 - - OS: "macos-latest" - GENERATOR: -G "Xcode" - - OS: "windows-latest" - GENERATOR: - exclude: - - EXERCISE: - NAME: "helgrind" - PLATFORM: - OS: "windows-latest" - GENERATOR: - - EXERCISE: - NAME: "python" - SKIP_SOLUTION: true - PLATFORM: - OS: "windows-latest" - GENERATOR: - - EXERCISE: - NAME: "stl" - SKIP_DEFAULT: true - PLATFORM: - OS: "windows-latest" - GENERATOR: - - EXERCISE: - NAME: "stl" - SKIP_DEFAULT: true - PLATFORM: - OS: "macos-latest" - GENERATOR: -G "Xcode" - - # The system to run on. - runs-on: ${{ matrix.PLATFORM.OS }} - - # The build/test steps to execute. - steps: - # Use a standard checkout of the code. - - uses: actions/checkout@v4 - # Run the CMake configuration. - - name: CMake Configure - run: cmake -S ${{ github.workspace }}/exercises/${{ matrix.EXERCISE.NAME }} - -B build - ${{ matrix.PLATFORM.GENERATOR }} - # Perform the build of the "main exercise" with CMake. - - name: CMake Build Main - run: cmake --build build - if: ${{ !matrix.EXERCISE.SKIP_DEFAULT || false }} - # Perform the build of the "solution" with CMake. - - name: CMake Build Solution - run: cmake --build build --target solution - if: ${{ !matrix.EXERCISE.SKIP_SOLUTION || false }} - # Perform the build of the "main exercise" with GNU Make. - - name: GNU Make Build Main - run: make -C ${{ github.workspace }}/exercises/${{ matrix.EXERCISE.NAME }} - if: ${{ matrix.PLATFORM.OS != 'windows-latest' && - (!matrix.EXERCISE.SKIP_DEFAULT || false) }} - # Perform the build of the "solution" with GNU Make. - - name: GNU Make Build Solution - run: make -C ${{ github.workspace }}/exercises/${{ matrix.EXERCISE.NAME }} - solution - if: ${{ matrix.PLATFORM.OS != 'windows-latest' && - (!matrix.EXERCISE.SKIP_SOLUTION || false) }} diff --git a/.github/workflows/build-slides.yml b/.github/workflows/build-slides.yml deleted file mode 100644 index e2814296..00000000 --- a/.github/workflows/build-slides.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: Build LaTeX slides -on: - push: - paths: - - 'talk/**' - pull_request: - paths: - - 'talk/**' - - '.github/workflows/**' - -# Cancel running jobs on force-push -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} - cancel-in-progress: true - -jobs: - build_latex: - runs-on: ubuntu-latest - strategy: - matrix: - version: [ essentials, full ] - steps: - - name: Set up Git repository - uses: actions/checkout@v4 - - name: Compile essentials - uses: xu-cheng/latex-action@v3 - if: matrix.version == 'essentials' - with: - root_file: C++Course.tex - latexmk_shell_escape: true - latexmk_use_xelatex: true - args: -pdf -interaction=nonstopmode -halt-on-error -usepretex=\def\makebasic{} - working_directory: talk - extra_system_packages: "py-pygments" - - name: Compile full course - uses: xu-cheng/latex-action@v3 - if: matrix.version == 'full' - with: - root_file: C++Course.tex - latexmk_shell_escape: true - latexmk_use_xelatex: true - args: -pdf -interaction=nonstopmode -halt-on-error - working_directory: talk - extra_system_packages: "py-pygments" - - name: Upload PDF as artifact - uses: actions/upload-artifact@v4 - with: - name: PDF_${{matrix.version}} - path: | - talk/C++Course.pdf diff --git a/.github/workflows/check-links.yaml b/.github/workflows/check-links.yaml deleted file mode 100644 index 0990af83..00000000 --- a/.github/workflows/check-links.yaml +++ /dev/null @@ -1,14 +0,0 @@ -name: Check Markdown links - -on: - push: - pull_request: - schedule: - - cron: "0 0 1 * *" - -jobs: - markdown-link-check: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@master - - uses: gaurav-nelson/github-action-markdown-link-check@v1 diff --git a/.github/workflows/publish-slides.yml b/.github/workflows/publish-slides.yml deleted file mode 100644 index 63d2f45c..00000000 --- a/.github/workflows/publish-slides.yml +++ /dev/null @@ -1,54 +0,0 @@ -name: Publish LaTeX slides -on: - push: - paths: - - 'talk/**' - branches: - - master - -jobs: - publish-slides: - runs-on: ubuntu-latest - strategy: - matrix: - version: [ essentials, full ] - steps: - - uses: actions/checkout@v4 - - name: Compile Essentials document - if: matrix.version == 'essentials' - uses: xu-cheng/latex-action@v3 - with: - root_file: C++Course.tex - latexmk_use_xelatex: true - args: -f -pdf -interaction=nonstopmode -shell-escape -usepretex=\def\makebasic{} - working_directory: talk - extra_system_packages: "py-pygments" - - name: Compile Full document - if: matrix.version == 'full' - uses: xu-cheng/latex-action@v3 - with: - root_file: C++Course.tex - latexmk_use_xelatex: true - args: -f -pdf -interaction=nonstopmode -shell-escape - working_directory: talk - extra_system_packages: "py-pygments" - - name: Commit to download repository - run: | - set -x - git clone -b download https://${GITHUB_ACTOR}:${{secrets.GITHUB_TOKEN}}@github.com/${{github.repository}}.git download - cd download - mkdir -p talk - cp ../talk/C++Course.pdf "talk/C++Course_${{ matrix.version }}.pdf" - git config --global user.name 'github-actions[bot]' - git config --global user.email 'github-actions[bot]@users.noreply.github.com' - git add -f "talk/C++Course_${{ matrix.version }}.pdf" - if (git diff --quiet) || (git diff --staged --quiet) - then - git commit --amend -m "Update C++Course.pdf" - until git push --force-with-lease origin download; do - git pull --rebase origin download - done - else - echo "No changes to commit" - fi - git push diff --git a/.gitignore b/.gitignore deleted file mode 100644 index c32d5754..00000000 --- a/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# just for the allcontributors cli installation... -package-lock.json -package.json -node_modules/** - -# Temporary latex files: -talk/C++Course.* -talk/_minted diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index 20be3b7a..00000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,21 +0,0 @@ -repos: -- repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 - hooks: - - id: check-added-large-files - - id: check-case-conflict - - id: check-merge-conflict - - id: detect-private-key - - id: end-of-file-fixer - - id: trailing-whitespace -- repo: https://github.com/codespell-project/codespell - rev: 'v2.4.1' - hooks: - - id: codespell - args: ["-I", "codespell.txt"] - types_or: ["tex", "markdown"] - -exclude: '.*\.sty' - -ci: - autoupdate_schedule: monthly diff --git a/CREDITS.md b/CREDITS.md deleted file mode 100644 index df274922..00000000 --- a/CREDITS.md +++ /dev/null @@ -1,16 +0,0 @@ -Credits -======= - - - Adaptations for CERN sessions (2020, 2025) - * [Sebastien Ponce](https://github.com/sponce) [CERN](http://cern.ch)/[LHCb](http://lhcb.cern.ch) - * [David Chamont](https://gitlab.cern.ch/chamont) [IN2P3](https://informatique.in2p3.fr) - * [Attila Krasznahorkay](https://gitlab.cern.ch/akraszna) [CERN](http://cern.ch)/[Atlas](https://atlas.cern/) - * [Ben Couturier](https://gitlab.cern.ch/bcouturi) [CERN](http://cern.ch)/[LHCb](http://lhcb.cern.ch) - * [Stephan Hageboeck](https://github.com/hageboeck) [CERN](http://cern.ch)/[Atlas](https://atlas.cern/) - * [Bernhard Manfred Gruber](https://gitlab.cern.ch/bgruber) [CERN](http://cern.ch)/EP-SFT - * [Enrico Guiraud](https://github.com/eguiraud) [CERN](http://cern.ch)/EP-SFT - * [Stefan Roiser](https://github.com/roiser) [CERN](http://cern.ch)/IT-SC-RD - * [Abhishek Lekshmananit](https://github.com/theanalyst) [CERN](http://cern.ch)/IT-ST-PDS - - - Original content (2015-2020) - * [Sebastien Ponce](https://github.com/sponce) [CERN](http://cern.ch)/[LHCb](http://lhcb.cern.ch) diff --git a/LICENSE b/LICENSE deleted file mode 100644 index a6f28baf..00000000 --- a/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2020 Sebastien Ponce - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/README.md b/README.md index e08580bc..436154b2 100644 --- a/README.md +++ b/README.md @@ -1,129 +1 @@ -# C++ course - -[![HSF Training Center](https://img.shields.io/badge/HSF%20Training%20Center-browse-ff69b4)](https://hepsoftwarefoundation.org/training/curriculum.html) - -[![All Contributors](https://img.shields.io/badge/all_contributors-11-orange.svg?style=flat-square)](#contributors-) - - -[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/hsf-training/cpluspluscourse/master.svg)](https://results.pre-commit.ci/latest/github/hsf-training/cpluspluscourse/master) -[![gh actions](https://github.com/hsf-training/cpluspluscourse/actions/workflows/build-slides.yml/badge.svg)](https://github.com/hsf-training/cpluspluscourse/actions) -[![gh actions](https://github.com/hsf-training/cpluspluscourse/actions/workflows/build-exercises.yml/badge.svg)](https://github.com/hsf-training/cpluspluscourse/actions) -[![gh actions](https://github.com/hsf-training/cpluspluscourse/actions/workflows/publish-slides.yml/badge.svg)](https://github.com/hsf-training/cpluspluscourse/actions) - -This repository contains all material for the C++ Course taught at CERN from -Sebastien Ponce (LHCb). - -## Next events - -Please check the [Indico agenda](https://indico.cern.ch/category/11733/). - -## 📎 Getting the latest PDF - -For each commit to master, the slides are compiled to a PDF and uploaded to the [download](https://github.com/hsf-training/cpluspluscourse/tree/download) branch. - - - Latest [essentials course PDF](https://github.com/hsf-training/cpluspluscourse/raw/download/talk/C%2B%2BCourse_essentials.pdf). - - Latest [full course PDF](https://github.com/hsf-training/cpluspluscourse/raw/download/talk/C%2B%2BCourse_full.pdf). - -## 📹 Video recordings & events - -Video recordings are available in the past events. - -* [8th HEP C++ Course and Hands-on Training (essentials), Manchester, August 2023](https://indico.cern.ch/event/1266661/) -* [7th HEP C++ Course and Hands-on Training (essentials), JLAB, May 2023](https://indico.cern.ch/event/1266632/) -* [6th HEP C++ Course and Hands-on Training (essentials), CERN, March 2023](https://indico.cern.ch/event/1229412/) -* [5th HEP C++ Course and Hands-on Training (advanced), CERN, October 2022](https://indico.cern.ch/event/1172498/) -* [4nd HEP C++ Course and Hands-on Training (essentials), CERN, March 2022](https://indico.cern.ch/event/1119339/) -* [3rd HEP C++ Course and Hands-on Training, CERN, August 2021](https://indico.cern.ch/event/1019089/) -* [2nd HEP C++ Course and Hands-on Training, virtual, January 2021](https://indico.cern.ch/event/979067/) -* [1st HEP C++ Course and Hands-on Training (2020 October)](https://indico.cern.ch/event/946584/) - -Check [this page](https://hepsoftwarefoundation.org/Schools/events.html) for announcements of upcoming training events (including those with this material). - -## 🧰 Development setup - -Make sure to install the pre-commit hooks: - -```bash -pip3 install pre-commit -# cd to repository -pre-commit install -``` - -### Spell checking - -Spell check is performed with the [codespell](https://github.com/codespell-project/codespell) -pre-commit hook on every commit. To ignore words you can put them in the -`codespell.txt` file. This file should list the supposedly misspelled words with -one word per line and is case-sensitive. - -## C++ guidelines - -- Prefer "east const" for new stuff. - -## Exercises guidelines - -### Instructions for mentors and students - -Students should start with the README in the respective exercise folders. These have the basic building instructions, give the name of the main program file, and possibly give a summary of the exercise goals and steps. - -Inside the code, one gets more precise help on what should/could be done. If the code is longer and only some parts need to be touched, this is often pointed out with comments. - -### Solutions to exercises - -Each exercise should provide a solution in the `solution` subdirectory. For any `.cpp` exercise, the solution should be called `solution/.sol.cpp`. -We invite students to only consult the solution when they completed an exercise or when they are really stuck. The preferred order is: -1. Work on the exercise and consult the slides -2. Discuss problems and questions with the class and the mentor -3. Consult the solution - -### About building - -For the time being, we maintain both a raw `Makefile` and a `CMakeLists.txt`. - -The `make` command should work directly on any linux-like system. The `make solution` command should build the solution. - -The `cmake` tool adds support for building on Windows. It is meant to be used in a `build` subdirectory: -``` -mkdir build -cd build -cmake .. -make -make solution -``` - -### For Mentors - -Depending on which course is running, consult the schedule for exercise sessions in [essentials](exercises/ExerciseSchedule_EssentialCourse.md) or [advanced](exercises/ExerciseSchedule_AdvancedCourse.md). -For mentors, there is a [cheat sheet](exercises/ExercisesCheatSheet.md) with hints towards the solutions and key points to discuss during the exercise sessions. - -## Contributors ✨ - -Thanks go to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): - - - - - - - - - - - - - - - - - - - - -

Abhishek L

🖋

Attila Krasznahorkay

🖋

Bernhard Manfred Gruber

🖋

David Chamont

🖋

Enrico Guiraud

🖋

Graeme A Stewart

🖋

Kilian Lieret

🚇

Sebastien Ponce

🖋

Stefan Roiser

🖋

Stephan Hageboeck

🖋

bcouturi

🖋
- - - - - - -This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! +The files on this branch are created by CI runs. diff --git a/codespell.txt b/codespell.txt deleted file mode 100644 index f4c6c466..00000000 --- a/codespell.txt +++ /dev/null @@ -1,6 +0,0 @@ -hist -heist -Hist -Heist -his -ro diff --git a/docker/Dockerfile b/docker/Dockerfile deleted file mode 100644 index 5b81df61..00000000 --- a/docker/Dockerfile +++ /dev/null @@ -1,53 +0,0 @@ - -# Version 2, en Python3 - -FROM gcc:11.2.0 - -# Ensure use of bash - -SHELL ["/bin/bash","-c"] - -# Timezone - -ENV TZ=Europe/Paris - -# Apt-get General Preparation - -RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections -ARG DEBIAN_FRONTEND=noninteractive -RUN apt-get update \ -&& apt-get install -y apt-utils - -# C++ Tools - -RUN apt-get install -y build-essential \ -&& apt-get install -y cmake \ -&& apt-get install -y cppcheck \ -&& apt-get install -y libc6-dbg gdb \ -&& apt-get install -y binutils graphviz \ -&& apt-get install -y valgrind kcachegrind - -# For GDB not to complain - -RUN echo "set auto-load safe-path /" > /root/.gdbinit - -# Python -# It seems I MUST say 3.7 for dev :s - -RUN apt-get install -y python3 \ -&& apt-get install -y python3-dev \ -&& apt-get install -y python3-pip \ -&& apt-get install -y python3-tk - -RUN pip3 install numpy -RUN pip3 install matplotlib - -# Other - -RUN rm -rf /var/lib/apt/lists/* -ENV PATH=${PATH}:. -ENV LD_LIBRARY_PATH=. - -# Start a shell by default - -CMD bash diff --git a/docker/README.md b/docker/README.md deleted file mode 100644 index 6b98bbc4..00000000 --- a/docker/README.md +++ /dev/null @@ -1,43 +0,0 @@ - ---- -# Building and sharing the image - -* `build.sh` : apply the Dokerfile recipe, building a local image whose name is taken from `name.txt`. -* `push.sh` (unavailable since migratiom to github): push the image `name.txt` to the registry, which requires access rights to this registry. - - ---- -# Starting a container - -* `run.sh` : start a container from the image `name.txt`, and run the command given as arguments (default is `bash`). The current directory is mounted as `/work`, and this is where the command is executed. -* `run_x11_macos.sh` : same as `run.sh`, plus X11 forwarding, in macOS flavor. It requires some prerequisites: see next section. -* `run_x11_linux.sh` : same as `run.sh`, plus X11 forwarding, in linux flavor. -* `run_x11_win.sh` : same as `run.sh`, plus X11 forwarding, in windows flavor. It requires some prerequisites: see next section. -* `versions.sh` : type `./run.sh ./versions.sh` within the `docker` directory, and you should check the version of the installed tools in the image. - - ---- -# X11 applications - -For the use of applications with X11 graphics, especially `kcachegrind`, one must setup the forwarding of X11 commands from the container to the host machine, which may be turn complex, depending on your system. We provide a set of scripts `run_x11_.sh`. Except for linux, it requires to start an X11 server emulator, and define some environment variable `MYIP`, which should contain the IP number associated your host and X11 session. We give below some tricks for each system. Once you think it should work, try the script `xeyes_.sh`. - -## macOS - -1. Install and start XQuartz. -1. Search for your IP number, using terminal command `ifconfig` and searching for `inet` lines. -1. Define `export MYIP=`. -1. Check with `xeyes_macos.sh`. -1. Run `run_x11_macos.sh`. - -## Linux - -1. Check with `xeyes_linux.sh`. -1. Run `run_x11_linux.sh`. - -## Windows - -1. Install and start Xming or Exceed. For Xming, we recommend those options: `Xming :0 -multiwindow -clipboard -ac`. -1. The applications above should enable you to get some IP number, typically `10.0.75.1` for Exceed. -1. Define `export MYIP=`. -1. Check with `xeyes_win.sh`. -1. Run `run_x11_win.sh`. diff --git a/docker/build.sh b/docker/build.sh deleted file mode 100755 index e287973c..00000000 --- a/docker/build.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -SCRIPT_NAME=${BASH_SOURCE[0]} -SCRIPT_DIR=`dirname ${SCRIPT_NAME}` -cd ${SCRIPT_DIR} - -docker build -f Dockerfile -t `cat name.txt` . -# --force-rm --no-cache diff --git a/docker/name.txt b/docker/name.txt deleted file mode 100644 index d9d1b7aa..00000000 --- a/docker/name.txt +++ /dev/null @@ -1 +0,0 @@ -cpluspluscourse:v6 diff --git a/docker/push.sh b/docker/push.sh deleted file mode 100755 index 7126ff5c..00000000 --- a/docker/push.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -SCRIPT_NAME=${BASH_SOURCE[0]} -SCRIPT_DIR=`dirname ${SCRIPT_NAME}` - -docker push `cat ${SCRIPT_DIR}/name.txt` diff --git a/docker/run.sh b/docker/run.sh deleted file mode 100755 index c1e1320d..00000000 --- a/docker/run.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -SCRIPT_NAME=${BASH_SOURCE[0]} -SCRIPT_DIR=`dirname ${SCRIPT_NAME}` - -docker run --security-opt seccomp=unconfined -it --rm -v $PWD:/work -w /work `cat ${SCRIPT_DIR}/name.txt` $* diff --git a/docker/run_x11_linux.sh b/docker/run_x11_linux.sh deleted file mode 100755 index 769e4e0b..00000000 --- a/docker/run_x11_linux.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -SCRIPT_NAME=${BASH_SOURCE[0]} -SCRIPT_DIR=`dirname ${SCRIPT_NAME}` - -xhost + - -docker run -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix:rw --security-opt seccomp=unconfined -it --rm -v $PWD:/work -w /work `cat ${SCRIPT_DIR}/name.txt` $* diff --git a/docker/run_x11_macos.sh b/docker/run_x11_macos.sh deleted file mode 100755 index 5d6ff6c4..00000000 --- a/docker/run_x11_macos.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -SCRIPT_NAME=${BASH_SOURCE[0]} -SCRIPT_DIR=`dirname ${SCRIPT_NAME}` - -export DISPLAY=${MYIP}:0 -xhost + ${MYIP} - -docker run -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix:rw --security-opt seccomp=unconfined -it --rm -v $PWD:/work -w /work `cat ${SCRIPT_DIR}/name.txt` $* diff --git a/docker/run_x11_win.sh b/docker/run_x11_win.sh deleted file mode 100755 index a03150d1..00000000 --- a/docker/run_x11_win.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -SCRIPT_NAME=${BASH_SOURCE[0]} -SCRIPT_DIR=`dirname ${SCRIPT_NAME}` - -export DISPLAY=${MYIP}:0 -xhost + ${MYIP} - -docker run -e DISPLAY=$DISPLAY --security-opt seccomp=unconfined -it --rm -v $PWD:/work -w /work `cat ${SCRIPT_DIR}/name.txt` $* diff --git a/docker/versions.sh b/docker/versions.sh deleted file mode 100755 index 42f64413..00000000 --- a/docker/versions.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -echo -g++ --version - -echo -make --version - -echo -cppcheck --version - -echo -gdb --version - -echo -valgrind --version - -echo diff --git a/docker/xeyes_linux.sh b/docker/xeyes_linux.sh deleted file mode 100755 index 7d564b02..00000000 --- a/docker/xeyes_linux.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -xhost + - -docker run -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix:rw gns3/xeyes diff --git a/docker/xeyes_macos.sh b/docker/xeyes_macos.sh deleted file mode 100755 index b0d00d20..00000000 --- a/docker/xeyes_macos.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -export DISPLAY=${MYIP}:0 -xhost + ${MYIP} - -docker run -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix:rw gns3/xeyes diff --git a/docker/xeyes_win.sh b/docker/xeyes_win.sh deleted file mode 100755 index 13075abc..00000000 --- a/docker/xeyes_win.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -export DISPLAY=${MYIP}:0 -xhost + ${MYIP} - -docker run -e DISPLAY=$DISPLAY gns3/xeyes diff --git a/exercises/.clang-format b/exercises/.clang-format deleted file mode 100644 index 182c5b70..00000000 --- a/exercises/.clang-format +++ /dev/null @@ -1,3 +0,0 @@ -BasedOnStyle: WebKit -InsertNewlineAtEOF: True -Standard: Latest diff --git a/exercises/.gitignore b/exercises/.gitignore deleted file mode 100644 index b624e076..00000000 --- a/exercises/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -# generic files and directories -build -*.a -*.o -*.so - -# tools -CMakeCache.txt -CMakeFiles -cmake_install.cmake -callgrind.out.* diff --git a/exercises/CMakeLists.txt b/exercises/CMakeLists.txt deleted file mode 100644 index 6438cc2d..00000000 --- a/exercises/CMakeLists.txt +++ /dev/null @@ -1,44 +0,0 @@ -# -# Main project for building all of the exercises at once. -# - -# Set up the project. -cmake_minimum_required( VERSION 3.12 ) -project( cpluspluscourse LANGUAGES CXX ) - -# Make sure that the project is built "out of source". As an "in source" build -# would interfere with the simple Makefiles coming with the code. -if( "${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}" ) - message( FATAL_ERROR "The tutorial code must be built out of source!" ) -endif() - -# Include the exercises that (should) work on all platforms. -add_subdirectory( asan ) -add_subdirectory( basicTypes ) -add_subdirectory( callgrind ) -add_subdirectory( condition_variable ) -add_subdirectory( constness ) -add_subdirectory( control ) -add_subdirectory( cppcheck ) -add_subdirectory( debug ) -add_subdirectory( functions ) -add_subdirectory( hello ) -add_subdirectory( loopsRefsAuto ) -add_subdirectory( memcheck ) -add_subdirectory( modern_oo ) -add_subdirectory( move ) -add_subdirectory( operators ) -add_subdirectory( polymorphism ) -add_subdirectory( race ) -add_subdirectory( smartPointers ) -add_subdirectory( stl ) -add_subdirectory( templates ) -add_subdirectory( valgrind ) -add_subdirectory( variadic ) -add_subdirectory( virtual_inheritance ) - -# Include the non-Windows-native exercises. -if( NOT MSVC ) - add_subdirectory( helgrind ) - add_subdirectory( python ) -endif() diff --git a/exercises/ExerciseSchedule_AdvancedCourse.md b/exercises/ExerciseSchedule_AdvancedCourse.md deleted file mode 100644 index c4e31398..00000000 --- a/exercises/ExerciseSchedule_AdvancedCourse.md +++ /dev/null @@ -1,56 +0,0 @@ -HEP C++ Advanced Course's exercise schedule -=========================================== - -- List of exercises per day, with preferred order. -- Solutions and hints can be found in the ExercisesCheatSheet.md file located in the same directory. -- Each exercise is in its own directory and referred to in the following by the name of the directory - -There are far too many exercises on each day. They are given in order in which they should be done. - -Day 1 ------ - -### Hello World (directory: [`hello`](hello), [CheatSheet](ExercisesCheatSheet.md#hello-world-directory-hello)) - -### Operator overloading (directory: [`operators`](operators), [cheatSheet](ExercisesCheatSheet.md#operator-overloading-directory-operators)) - -### Move semantic (directory: [`move`](move), [cheatSheet](ExercisesCheatSheet.md#move-semantic-directory-move)) - -### Debugging (directory: [`debug`](debug), [cheatSheet](ExercisesCheatSheet.md#debugging-directory-debug)) -This was actually covered in the essential course, but it's always good to be fluent with gdb when writing C++ ! - - -Day 2 ------ - -The tools exercises of day 2 are special as they will have been played (quickly) during the course. -People should replay them and discover the tools by themselves. - -### Smart pointers (directory: [`smartPointers`](smartPointers), [cheatSheet](ExercisesCheatSheet.md#smart-pointers-directory-smartpointers)) - -### std::optional (directory: [`optional`](optional), [cheatSheet](ExercisesCheatSheet.md#stdoptional-directory-optional)) - -### std::variant (directory: [`variant`](variant), [cheatSheet](ExercisesCheatSheet.md#stdvariant-directory-variant)) - -### Generic programming / templates (directory: [`templates`](templates), [cheatSheet](ExercisesCheatSheet.md#generic-programming--templates-directory-templates)) - -### (optional) Address sanitizer (directory: [`asan`](asan), [cheatSheet](ExercisesCheatSheet.md#address-sanitizer-directory-asan)) - -### (optional) Undefined behaviour sanitizer (directory: [`ubsan`](ubsan) - - -Day 3 ------ - -### Race conditions (directory: [`race`](race), [cheatSheet](ExercisesCheatSheet.md#race-conditions-directory-race)) - -### Condition variables (directory: [`condition_variable`](condition_variable), [cheatSheet](ExercisesCheatSheet.md#condition-variables-directory-condition_variable)) - -### Generic programming / templates (directory: [`templates`](templates), [cheatSheet](ExercisesCheatSheet.md#generic-programming--templates-directory-templates)) -As a prerequisite for variadic templates, and in case it was not covered in day 2 session - -### Variadic templates (directory: [`variadic`](variadic), [cheatSheet](ExercisesCheatSheet.md#variadic-templates-directory-variadic)) - -### Spaceship operator <=> (directory: [`spaceship`](spaceship), [cheatSheet](ExercisesCheatSheet.md#spaceship-operator-directory-spaceship)) - -### Concepts (directory: [`concepts`](concepts), [cheatSheet](ExercisesCheatSheet.md#concepts-directory-concepts)) diff --git a/exercises/ExerciseSchedule_EssentialCourse.md b/exercises/ExerciseSchedule_EssentialCourse.md deleted file mode 100644 index 4eed3641..00000000 --- a/exercises/ExerciseSchedule_EssentialCourse.md +++ /dev/null @@ -1,58 +0,0 @@ -HEP C++ Essential Course's exercise schedule -============================================ - - - List of exercises per day, with preferred order. - - Solutions and hints can be found in the ExercisesCheatSheet.md file located in the same directory. - - Each exercise is in its own directory and referred to in the following by the name of the directory - -For each day, the exercises are given in order in which they should be done. - -Day 1 - Basics Exercises ------------------------- - -### Hello World (directory: [`hello`](hello), [CheatSheet](ExercisesCheatSheet.md#hello-world-directory-hello)) - -### Basic types (directory: [`basicTypes`](basicTypes), [CheatSheet](ExercisesCheatSheet.md#basic-types-directory-basictypes)) - -### Functions (directory: [`functions`](functions), [CheatSheet](ExercisesCheatSheet.md#functions-directory-functions)) - -### Control Structures (directory: [`control`](control), [CheatSheet](ExercisesCheatSheet.md#control-structures-directory-control)) - -### Auto and references (directory: [`loopsRefsAuto`](loopsRefsAuto), [CheatSheet](ExercisesCheatSheet.md#auto-and-references-directory-loopsrefsauto)) - - -Day 2 - Tools Exercises ------------------------ - -The tools exercises of day 2 are special as they will have been played (quickly) during the course. -People should replay them and discover the tools by themselves. - -### Compiler (directory: [`polymorphism`](polymorphism), [CheatSheet](ExercisesCheatSheet.md#compiler)) - -### Debugging (directory: [`debug`](debug), [CheatSheet](ExercisesCheatSheet.md#debugging-directory-debug)) - -### Clang-format ([CheatSheet](ExercisesCheatSheet.md#clang-format)) - - -Day 2 - OO Exercises --------------------- - -### My first classes (directory: [`classes`](classes), [CheatSheet](ExercisesCheatSheet.md#classes-directory-classes)) - -### Operator overloading (directory: [`operators`](operators), [CheatSheet](ExercisesCheatSheet.md#operator-overloading-directory-operators)) - -### Polymorphism (directory: [`polymorphism`](polymorphism), [CheatSheet](ExercisesCheatSheet.md#polymorphism-directory-polymorphism)) - -### Virtual inheritance (directory: [`virtual_inheritance`](virtual_inheritance), [CheatSheet](ExercisesCheatSheet.md#virtual-inheritance-directory-virtual_inheritance)) - - -Day 3 - Modern C++ Exercises ----------------------------- - -### Constness (directory: [`constness`](constness), [CheatSheet](ExercisesCheatSheet.md#constness-directory-constness)) - -### Generic programming / templates (directory: [`templates`](templates), [CheatSheet](ExercisesCheatSheet.md#generic-programming--templates-directory-templates)) - -### Smart pointers part 1 and 2 (directory: [`smartPointers`](smartPointers), [CheatSheet](ExercisesCheatSheet.md#smart-pointers-directory-smartpointers)) - -### Standard algorithms and lambdas (directory: [`stl`](stl), [CheatSheet](ExercisesCheatSheet.md#standard-algorithms-and-lambdas-directory-stl)) diff --git a/exercises/ExercisesCheatSheet.md b/exercises/ExercisesCheatSheet.md deleted file mode 100644 index 702d8874..00000000 --- a/exercises/ExercisesCheatSheet.md +++ /dev/null @@ -1,378 +0,0 @@ -HEP C++ Course cheat sheet -========================== - -List of exercises per day, with preferred order and solution overview. -Each exercise is in its own directory and referred to in the following by the name of the directory -For each day, the exercises are given in order in which they should be done. - -Basics Exercises ----------------- - -### Hello World (directory: [`hello`](hello)) - -Just try to compile and run `./hello` to make sure that everything is set up correctly. - -### Basic types (directory: [`basicTypes`](basicTypes)) - -The goal is to observe the behaviour of a few basic types, correctly employ integer and floating-point literals, and to be aware of conversions and the effect of operators in expressions with such types. - -### Functions (directory: [`functions`](functions)) - -pass by copy / pass by reference - -- Write a `printFiveCharacters(SlowToCopy)` function using the existing function as a model. Change its name - if overloading isn't desired. -- Call it in `main()`. -- Make sure that the signature is `(SlowToCopy const & a)` to avoid copies. -- Try to modify the data in the structs. Compare what happens for each of `(SlowToCopy a), (SlowToCopy & a), (SlowToCopyy const & a)`. - -### Control Structures (directory: [`control`](control)) - -The idea of this exercise is to play with all kinds of possible loops and control structures and to understand how they work. - -- change from a C++98 style for loop to range-based loop -- replace if / else statement with conditional operator -- change from a for loop to while and do/while loop -- change an if statement to a switch statement - -### Auto and references (directory: [`loopsRefsAuto`](loopsRefsAuto)) - -- Write an indexed for loop to initialise the members of the structs. The program should not print garbage numbers. -- Use `auto const &` to prevent copies in the second loop. -- Understand the difference to `auto &`, get in the habit of using const references. - - -Object-orientation Exercises ----------------------------- - -### Classes (directory: [`classes`](classes)) - -This exercise is about doing a basic class, not using any operator overloading. It also paves the way for object-functions, making a first algo-like class. - -You may discuss with the students: -- pros and cons of making the constructor explicit or not, -- pros and cons of having multiply() and equal() either as member functions, - friend free functions or external free functions. -- optionally, thed difference between equality and equivalence. - -NOTE: I did not find a justified need to add operator=... - -### Operator overloading (directory: [`operators`](operators)) - -Here we take the class from the previous exercise, and we try to make -anything an operator that makes sense. - -Tips and tricks: -- When the argument of CHECK() has a comma not between parentheses, for example - curly braces, add an additional global level of parenthesis, or CHECK() will - think it has several arguments. - -You may discuss with the students: -- the chaining of operator<< -- in a set of consistent operators (such as == and !=), - reusing versus performance. -- object-functions. -- for what concerns the related operators, such as * and *=, - the choice to be made consistent reuse or performant - specialization of each operator. - -### Polymorphism (directory: [`polymorphism`](polymorphism)) - -First create a Pentagon and an Hexagon and call computePerimeter. Can be used to break the ice. -Second step is to call parent's computePerimeter methods meaning : - -```cpp -Polygon *poly = new Hexagon(1.0); -poly->computePerimeter(); -``` -and check what is called, in regular and virtual method case - -### Modern object-orientation (directory: [`modern_oo`](modern_oo)) - -Insert one `= delete`, one `= default` and one `override`. - -### Virtual inheritance (directory: [`virtual_inheritance`](virtual_inheritance)) - -First create a TextBox and try to call draw. -There will be an error that the member is ambiguous, due to multiple inheritance. -Fix code by calling it on both parents using types : - -```cpp - TextBox *tb = new TextBox(...) - Rectangle *r = tb; - r->draw(); -``` - -See the output and check the ids printed, 2 different ones. - -Retry with virtual inheritance. -See and solve the compilation issue about missing Drawable constructor. Understand that it's now called directly from TextBox constructor and call it explicitly from there with a new id. -See the new id being printed twice. - - -Modern C++ Exercises --------------------- - -### Constness (directory: [`constness`](constness)) - -The idea is to find out which lines are not correct, due to constness. -Ideal to break the ice as can be organized as a quizz of which line would fail or not with correction under the form of compiler validation. - -### Move semantic (directory: [`move`](move)) - -See with valgrind the number of copies and memory allocations in the problem, due to lack of move semantic. -Implement the move semantic based on swap (copy paste from the slides). -See in valgrind the improvements. - -### Generic programming / templates (directory: [`templates`](templates)) - -This exercise has several levels. People not at ease can stop after the first level and go to next exercise. Alternatively, they may do level 1 and 3 and skip 2. - -Level 1: just use the given `Complex` alias (`Complex_t`) inside an `OrderedVector`, fill and print it. See that it works out of the box thanks to generic code in `OrderedVector`. - -Level 2: add a template argument for the ordering in OrderedVector. -The idea is to add an extra template argument "Compare" that is a functor comparing 2 arguments and an extra member "m_compare" of type "Compare" to the OrderedVector class. Then the comparison in the add function can be replaced by - -```cpp -m_compare(arg1, arg2); -``` -It can then be tried with e.g. reverse ordering of strings or an order of Complex based on Manhattan distance (https://en.wikipedia.org/wiki/Taxicab_geometry) - -Level 3 : use the genericity of the Complex class and play with Complex of integers or Complex of Complex - -### Standard algorithms and lambdas (directory: [`stl`](stl)) - -The goal is to use STL algorithms. I would advise to start in this order : - - - random_shuffle - - adjacent_difference - - first accumulate (the one for sums) - - second accumulate (using lambda to compute sum of squares) - - generate (involves a state to be captured by reference) - -### Smart pointers (directory: [`smartPointers`](smartPointers)) - -Here we have five code snippets that will benefit from using smart pointers. -**Essentials**: Work on part 1 and 2 -**Advanced**: Try all parts - -- `problem1` is a simple case of usage of `make_unique` with an observer pattern where the raw pointer should be used. -- `problem2` is an example of a collection of pointers. Move semantic has to be used to transfer ownership of newly created objects to the container (alternatively, `emplace_back`). -- `problem3` is an example of shared ownership where `std::shared_pointer` should be used. -- `problem4` demonstrates the usage of `shared_ptr` as class members. -- `problem5` demonstrates the usage of `weak_ptr` can be used, but can be skipped if not enough time. - -### std::optional (directory: [`optional`](optional)) - -Use std::optional to signify disallowed values in a computation. -1. Use std::optional as return value of the mysqrt function. Use `nullopt_t` for negative arguments. Note that `return {}` will create a `nullopt_t` automatically. -2. Given that the return type changes, modify the square function accordingly to take into account cases where a `nullopt_t` is given as input. Note that `std::optional` can be directly used in an if statement as if it would be a boolean to check whether is value is present - -### std::variant (directory: [`variant`](variant)) - -Use the variant as an alternative to inheritance. The goal is to understand -1. That the base class is unnecessary when variant is used -2. That no dynamic allocations and polymorphism are necessary because the variant can directly be pushed into the vector -3. That there's multiple ways to "visit" the vector. - - Either with explicit checking of the type (solution 1) - - Or automatic visitation with std::visit (solution 2). Note that generic lambdas make the std::visit solution extremely short. - - -Expert Exercises ----------------- - -### Variadic templates (directory: [`variadic`](variadic)) - -The goal of the exercise is to implement a simple tuple, ignoring const correctness (to make it simpler). -If students encounter any constness problems, make sure they pass by value or mutable reference. -When you are unsure yourself, check the solution. - -Solutions: - -1. Add a default constructor -2. Add an `explicit` to the tuple constructor -3. `head(tuple&)` should just return the member `m_head` -4. `get(tuple&)` should be implemented recursively. - You can use SFINAE (like on the slides), but prefer `if constexpr`. -5. Specialize `std::tuple_size`. - The value of the trait is `sizeof...(Ts)` of the template parameter pack in `tuple` -6. Specialize `std::tuple_element`. - You can implement this recursively with Head/Tail... template parameters. - But since `get()` already does something like that, it is the easiest to just `decltype(get(...))` -7. `tuple_cat(tuple, tuple)`: Delegate to a `helper tuple_cat(tuple, tuple, index_seq, index_seq)`. - Then just construct a result `tuple{get(t1)..., get(t2)...}`. -8. `sum(tuple)`: you need a helper again with a single index sequence, but make it a local lambda this time. - Inside the lambda, fold over `get(t)`. -9. `operator<<`: again, needs a helper for the index sequence. - To intersperse the ", " between elements, you need more logic so a fold over << won't work. Use a fold over comma. - Finally, to omit the last ", ", just use a conditional expression comparing the expanded index pack against the index pack size - - -### Spaceship operator <=> (directory: [`spaceship`](spaceship)) -The goal is to write a custom <=>, and to understand that when ordering according to the norm of a complex, a `partial_ordering` is required. -Many numbers can have the same norm, but a different phase. -Given that an implementation for <=> is provided, an implementation for == is required as well. It's OK to default it. It is not possible to -derive it from equivalence (<=> evaluates to 0). - -### Concepts (directory: [`concepts`](concepts)) - -To be filled - -### Modules (directory: [`modules`](modules)) - -For this exercise you will convert a header file into a module. -Students should understand that a module is something different from a header. -In fact, since a module needs to be compiled, it needs to be its own translation unit. -That's why we should also rename `Complex.h` to `Complex.cpp` -(There is a discussion about having different file suffixes for module files in the C++ community, but it has not settled yet). -Also, we need to have a separate rule in the `Makefile` because we now need to build the module, -whereas a header was just included and built with the source file including it. - -You can ask the students to look into the compiler output files and see that there is also an object file created for `Complex.cpp`. -Furthermore, GCC creates the compiled module interface as well, which you can find in `gcm.cache/`. -Make sure students understand the different build process and the artifacts involved. - -Furthermore, `export` is required to make entities visible outside the module. -You can let students play with exporting/not-exporting `Complex`. -Also point out, that even though `Complex_t` is not exported, `main.cpp` can still use it via the type alias `Complex`. -But in `main.cpp` we cannot use `Complex_t` directly if it is not exported. -That is the difference between visibility and reachabilty. - -Avoid getting stuck in `Makefile` specifics, help the students with the syntax early. -Also remind students that this is all experimental and that better build system support (e.g. in cmake) is on its way. - -### Header units (directory: [`header_units`](header_units)) - -For this exercise you will convert `#include`s to `import`s -The key takeaway is that header units are easy to migrate to within the C++ source. - -Since header units need to be prebuilt, extra build steps are necessary. -In practice, this should speed up builds, which this small example cannot demonstrate. - -Avoid getting stuck in `Makefile` specifics, help the students with the syntax early. -Also remind students that this is all experimental and that better build system support (e.g. in cmake) is on its way. - -Tools Exercises ---------------- - -Some exercises i nthis chapter are special as they will have been played (quickly) during the course. But people should still replay them and discover the tools by themselves. - -### Clang-format - -The goal is to understand that automatic code formatting is easy and can be customized - -Steps: - -1. Go to literally any example (e.g. `variadic`), which has no changes yet (we are going to revert it later) - Please warn the students: If they want to revert later, they should pick an example with no local changes. -2. Format code with: `clang-format --style=GNU -i ` -3. Inspect changes, try `git diff .` -4. Revert changes using `git checkout -- ` or `git checkout .` -5. You can repeat this with various other styles if you want. Supported are: LLVM, Google, Chromium, Mozilla, WebKit, Microsoft. -6. Go to `exercises` directory and create a `.clang-format` file: - `clang-format -style=LLVM -dump-config > .clang-format`. - Have a look at the file. - You can also show this webpage so students can get an idea of what's possible: https://clang.llvm.org/docs/ClangFormatStyleOptions.html - Then run `clang-format -i /*.cpp`. - You will see that all cpp files in that directory have been formatted. -7. Revert changes using `git checkout ` -8. Please advise the students they should use `.clang-format` files from their projects before they start developing their own one. - -### Compiler (directory: [`polymorphism`](polymorphism)) - -We replay the compilation steps manually. -Concrete details in the polymorphism README.md. - -A "break the ice" exercise here would be to ask people to do the first step (preprocessor) and make a poll on how many lines of C++ are present in the output. -It will vary depending on setups, versions, OS, etc... - -Then the important part is to play with `nm` and the `-C` option of `C++filt` to be able to decode symbols, find them and thus address a build error that mentions missing symbols. - -Another important bit is ldd and inspecting library dependencies. - -Notes: -- `--std=` >= c++11 is needed to initialise the structs. -- The Makefile skips the generation of the object file for functions.cpp. This might surprise some people. - -### Debugging (directory: [`debug`](debug)) - -The goal there is really to play, look around and try things. Tutors may have a lot of questions here on "how do you...". - -The solution of the crash is simply an inversion of 2 lines in the code where definition of v and it's randomization are inverted. - -### Address sanitizer (directory: [`asan`](asan)) - -The goal is to play with asan, and learn to read the very detailed hints it gives when it detects an error. - -There's two bugs and one memory leak: -- `stackOverflow()` overflows the stack by writing past the end of an array in the for loop. -- `useAfterFree()` returns a reference to a temporary. One should return a copy. -- `memoryLeak()` lets a string leak. - -### Valgrind (directory: [`valgrind`](valgrind)) - -Again the point is to play with the tool. -In this example, we use an already deleted array. Simply the delete statement in the code appears too early - -Second part of the exercise goes back to the gdb exercise. Here we see an access out of array bound. It's due to bad case in 'len' in createAndFillVector (or why should you name your variables wisely and avoid macros). -Interestingly this out of bound access will usually not fail but read the next variable in memory and thus biais the computation. -Second part can be skipped if time is missing - -### Memcheck (directory: [`memcheck`](memcheck)) - -Simple example of a memory leak and how valgrind helps a lot with this. -Not so simple solution here. And the use of gdb with steping at the level of the destructor call is recommended. Give it as a hint to people. - -The solution is that the wrong destructor is called when calling "delete hexa" because the constructor is not virtual while it should be. - -### Callgrind (directory: [`callgrind`](callgrind)) - -The goal is again to play. With the optimized version, it's interesting to see how much the startup time dominates the few computations done. -This exercise can be skipped - -### Helgrind (directory: [`helgrind`](helgrind)) - -This is a concurrency exercise and thus rather be kept for Day 5 although the tool is presented on Day 3. -Usually the program works fine, and valgrind is happy. The race condition is indeed hard to trigger, but nevertheless spotted easily by helgrind. -The title string is just deleted too early. -This exercise should be skipped if time is missing - -### Cppcheck (directory: [`cppcheck`](cppcheck)) - -Simple example of a static analysis tool. -The code shows no problem, even with valgrind and still mayb biais its result. - -The basic goal is to run the tool, find the problem and fix it. The problem is a typo in the declaration of the v vector where + has become -, thus creating a out of bound error. - -The second goal is to understand why it os not crashing neither detected by valgrind. Here gdb is useful and one needs to inspect the address of variables in memory to understand that the compiler aligns variables and thus leaves space after v that is considered allocated by valgrind. -That second part can be skipped. - -### Clang-tidy - -To be filled - - -Concurrency Exercises ---------------------- - -### Race conditions (directory: [`race`](race)) - -Typical race condition where a simple mutex and lock_guard "solves" the problem. - -The second step is to look at the execution time and find out that it's not really a solution. - -Try then to use an `atomic` to solve the issue and compare the execution time with the lock solution. - -### Condition variables (directory: [`condition_variable`](condition_variable)) - -Small example where 4 consumer threads are notified by a producer. -1. The production phase is not protected by a lock. -2. When the consumers are waking up, they don't release the lock that's tied to the condition variable, so they cannot wake up in parallel. - - -Python Exercises ----------------- - -### Python (directory: [`python`](python)) - -This is playing with low level C++/python interfacing. All the c code is provided, so the only task is to use the different implementations (C, C++ manual interface, ctype) from python and see the speed of each of them. diff --git a/exercises/Makefile b/exercises/Makefile deleted file mode 100644 index 5c7e7613..00000000 --- a/exercises/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -TESTDIRS = asan callgrind condition_variable control cppcheck debug functions \ - header_units helgrind hello loopsRefsAuto memcheck modern_oo modules \ - move operators polymorphism python race smartPointers templates \ - valgrind virtual_inheritance -NOCOMPILETESTDIRS = basicTypes constness stl variadic - -all: - for dir in ${TESTDIRS}; do \ - cd $${dir}; \ - make $@; \ - cd ..; \ - done - -solution clean: - for dir in ${TESTDIRS} ${NOCOMPILETESTDIRS}; do \ - cd $${dir}; \ - make $@; \ - cd ..; \ - done - -clobber: clean diff --git a/exercises/README.md b/exercises/README.md deleted file mode 100644 index 160793fe..00000000 --- a/exercises/README.md +++ /dev/null @@ -1,266 +0,0 @@ -Exercises: HowTo -=============== - - - Each exercise is in its own directory and referred to in the following by the name of the directory. - - Almost each exercise contains a solution. - - We tried to provide more material than many participants can finish during the sessions. Participants are welcome to finish the more complicated ones in - self study, but questions regarding the solutions are welcome in the lecture and especially during the following hands-on sessions. - - For each day, the exercises are given in order in which they should be done in - - Essentials: [`ExerciseSchedule_EssentialCourse.md`](ExerciseSchedule_EssentialCourse.md) - - Advanced: [`ExerciseSchedule_AdvancedCourse.md`](ExerciseSchedule_AdvancedCourse.md) - -Getting the code ----------------- - -```bash -git clone https://github.com/hsf-training/cpluspluscourse.git -cd cpluspluscourse/exercises -``` - -Recommended setup ------------------ - -### Required - - - decent C++ editor - - any C++ compiler supporting C++20 - - C++17 compiler will do for most of the exercises though - - git for getting/managing your code - -### Good to have - - - `gdb` to debug your problems - - `valgrind`, `kcachegrind`, `cppcheck`, `clang-format` and `clang-tidy` for corresponding exercises - - `g++` or `clang++` as C++ compiler for sanitizer exercises - -### More setup for the advanced course - -#### C++ and python specific needs - - - `python3`, `libpython3-dev` - - `ctypes`, `matplotlib`, `numpy` python packages - -#### A word on timing - - - several exercises ask you to "time" things - - here it's always sufficient to use the `time` command line: - ```shell - time ./racing - real 0m0.022s - user 0m0.011s - sys 0m0.021s - ``` - - and just take the first number (real time) - - -How to test your setup ----------------------- - - **Please run [`check_setup.sh`](check_setup.sh) to check your setup on Linux / Mac.** - The optional tools are not required for the essentials course. - - go to [`exercises/hello`](hello) - - follow the `README.md` - -### How to compile and run? - -```bash -cd exercises/hello -make -export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:. -./hello -``` - -### Optionally: check for valgrind/cppcheck - - - `valgrind --tool=callgrind ./hello; kcachegrind` - - `cppcheck .` - - -Anatomy of an exercise ----------------------- - -Each exercise is in a subdirectory with mainly 4 sets of files - -### Instructions - - - Each exercise comes with a set of instructions in the course slides - - Most of them also with a `README.md` in the `exercises` subdir - - And with instructions in the code - -### *.hpp and *.cpp files - - - the code to understand and fix/complete - - you never start from scratch - -### Makefile / cmake - - - prepared Makefile for easy compilation - - `make` and `make clean` are available - - CMake is also supported: - - Create a build directory such as `mkdir build` - - `cd build` - - Configure using `cmake ..` - - Compile e.g. using `make` - -### solution subdirectory - - - the solution to the exercise (`make solution`) - - please do not use before trying! - - -Examples of working environments -================================ - -Using lxplus ------------- - - - lxplus9 at CERN is perfectly suitable for the exercises - - it has all the needed compilers/tools - - run e.g. -```bash -ssh lxplus9.cern.ch -export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:. -git clone https://github.com/hsf-training/cpluspluscourse.git -cd cpluspluscourse/exercises/hello -make -./hello -``` - -Using OS/X ----------- -- Install xcode and the command line tools -- Compiling, running, debugging will work, but a few tools such as valgrind are not available - - - -Using Windows -------------- - -There are multiple options if you bring a Windows machine to the course: - -1. Use the Windows Subsystem for Linux (WSL) -2. Use an ssh client and connect to lxplus -3. Use Visual Studio and the native Windows compiler (MSVC) - -We advise to use either [WSL](#wsl) or [lxplus](#lxplus), so a non-Windows experience. -This way, you can follow all exercises, especially the ones on tools, which are mostly Linux focused. -Also, we can ensure that mentors can help you in case you get stuck. -Using lxplus is probably the easiest, but if you have a really hard time using the terminal, -you can go for WSL and use Visual Studio Code. - -### WSL - -Important: if you have [VirtualBox](https://www.virtualbox.org/) installed on Windows do not try to install WSL2, -due to [this issue](https://github.com/MicrosoftDocs/WSL/issues/798). -It will either not work or run very slow. -Instead, we recommend you use VirtualBox directly to set up a suitable virtualised Linux environment. -Or use [lxplus](#lxplus). - -The procedure is described in detail [here](https://docs.microsoft.com/en-us/windows/wsl/install). - -#### Windows 10 (version 2004 or higher) - -The installation of WSL is as easy as running (with Administrator privileges): - - wsl --install - # and reboot - -This will activate WSL 2 and install Ubuntu 22.04. -If you prefer a different Linux distribution, run: - - wsl --list --online - wsl --install -d - -#### Older Windows 10 versions - -On older Windows versions, the procedure is more involved and documented [here](https://learn.microsoft.com/en-us/windows/wsl/install-manual). - -It's lightly recommended to use WSL 2 as the Linux compatibility is better, -but everything in the C++ course should work on either the WSL 1 or 2 backends. - -#### Setup your Linux - -Start your Linux inside a terminal by calling either `wsl` or `bash`. -When you start for the first time you'll be asked to create a user account. -Then you can login and install the packages which are necessary for the tutorial: - - sudo -s # will ask for your password - apt update - apt upgrade - apt install git g++ gdb valgrind cppcheck cmake clang-format clang-tidy python3 - -Verify that the tools are there by running: - - $ g++ --version - g++-11 (Ubuntu 11.2.0-19ubuntu1) 11.2.0 - Copyright (C) 2021 Free Software Foundation, Inc. - This is free software; see the source for copying conditions. There is NO - warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -You can install an editor inside the WSL system itself, -but we recommend to use [VS Code](#visual-studio-code) in Windows natively. - -### Connect to lxplus from Windows - -Recent versions of Windows 10 (version 1809 or higher) come with an ssh client. -If that does not work, you can install a third-party ssh client for Windows. -We have good experience with https://www.putty.org/. - -Open Windows Terminal, or PowerShell if you run an older version of Windows. -Use `ssh lxplus9.cern.ch` to connect to lxplus. -Follow the [lxplus guide](#using-lxplus) from here. - -If you are having troubles with the terminal based environment, -you can also try to use [VS Code](#visual-studio-code) natively on your Windows to connect to lxplus. -We have not tested this seriously yet, but it should work. - -### Visual Studio - -If you want to stay on Windows, make sure you have Visual Studio and cmake installed. -Visual Studio comes in a few distributions, some requiring a paid license. -The Community edition is free for academic use or for working on open source software. -During installation of Visual Studio, select the `Desktop development with C++` workload. - -Visual Studio Community: https://visualstudio.microsoft.com/vs/community/ -CMake: https://cmake.org/download/ - -For the exercises, you will use the standard CMake workflow as described in the course slides (create a build directory, run cmake, etc.). -CMake will create a Visual Studio solution file `.sln` in the build directory, -which you can open to start working on an example within the Visual Studio IDE. - -### Visual Studio Code - -For developing on Windows natively, -but compiling and running on a remote Linux system (including WSL), -we recommend using Visual Studio Code (VS Code). -VS Code is a more lightweight code editor and not to be confused with the full-blown IDE Visual Studio. -Please install VS Code from [this website](https://code.visualstudio.com/Download). - -For remote development you will also need the following extensions to VS Code: - - - WSL - - Remote - SSH - - C/C++ Extension Pack - -You can install them from the extension menu (Ctrl + Shift + X). - -There are two ways to launch VS Code for working with WSL: - -1. GUI first: Launch VS Code on Windows. - Run from the command palette (Ctrl + Shift + P), `Remote-WSL New Window`. - VS Code will now begin a session running inside the WSL Linux on your system. - You can click on `Clone Git Repository...` or, if you already cloned the GitHub repository, click `Open Folder...`. - You can also open a terminal with bash via the menu `Terminal` -> `New Terminal`. - Use the newly opened terminal to type commands for building, debugging, etc. -2. Terminal first: Launch `bash` or `wsl` either via a powershell or from Windows Terminal (if installed). - Navigate to your cloned GitHub repository, or `git clone` it if you have not done it yet. - Inside the `/exercises` or any `/exercises/example` directory, run `code .`. - This will launch VS Code on Windows, already connected to your WSL and set to the right folder. - Use your initial terminal to type commands for building, debugging etc. - -More documentation on using WSL with Visual Studio Code can be found [here](https://code.visualstudio.com/docs/remote/wsl). - -Experimental (we have not tested this seriously): -You can also use VS Code to work on lxplus. -Run from the command palette (Ctrl + Shift + P), `Remote-SSH Connect to host...`. -Then enter `@lxplus9.cern.ch`, then your password. -The first connection takes a while for VS Code to setup its server on lxplus. diff --git a/exercises/asan/.gitignore b/exercises/asan/.gitignore deleted file mode 100644 index 2283c96d..00000000 --- a/exercises/asan/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -asan -asan.sol diff --git a/exercises/asan/CMakeLists.txt b/exercises/asan/CMakeLists.txt deleted file mode 100644 index a45b0070..00000000 --- a/exercises/asan/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -# Set up the project. -cmake_minimum_required( VERSION 3.12 ) -project( asan LANGUAGES CXX ) - -# Set up the compilation environment. -include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) - -# Create the user's executable. -add_executable( asan "asan.cpp" ) - -# Create the "solution executable". -add_executable( asan.sol EXCLUDE_FROM_ALL "solution/asan.sol.cpp" ) -add_dependencies( solution asan.sol ) diff --git a/exercises/asan/Makefile b/exercises/asan/Makefile deleted file mode 100644 index 9c635be0..00000000 --- a/exercises/asan/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -all: asan -solution: asan.sol - -clean: - rm -f *o *so asan *~ asan.sol - -asan : asan.cpp - $(CXX) -std=c++17 -o $@ $^ - -asan.sol : solution/asan.sol.cpp - $(CXX) -std=c++17 -o $@ $^ diff --git a/exercises/asan/README.md b/exercises/asan/README.md deleted file mode 100644 index 9cea5dc5..00000000 --- a/exercises/asan/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Using address sanitizer - -Here, we explore address sanitizer (asan). The program `asan.cpp` has two bugs and a memory leak, -which should be relatively easy to find. It might or might not crash when run in its current state. -The goal is to compile the program with and without asan instrumentation and learn to read the very -detailed analysis of the program it generates. - -## Instructions -There's three tasks listed in the source code. diff --git a/exercises/asan/asan.cpp b/exercises/asan/asan.cpp deleted file mode 100644 index e537777d..00000000 --- a/exercises/asan/asan.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include -#include -#include - -// Task 1: -// Here we write past the end of a character array on the stack. -// This doesn't necessarily crash the program, but it's certainly a bad idea, -// as it will corrupt data. -// -// - Compile and run the program without address sanitizer. Maybe you are lucky -// and it doesn't crash, but the arrays are probably corrupted now. -// (To make it crash, you can write more characters, but that's not necessary for -// what we want to try with asan.) -// - Add -// -fsanitize=address -fno-omit-frame-pointer -g -// to the compile options and retry. -// - For the Makefile, just add the above flags to the command line. -// - For CMake, either add to asan/CMakeLists.txt: -// target_compile_options(asan PUBLIC -fsanitize=address -fno-omit-frame-pointer -g) -// target_link_libraries(asan PUBLIC -fsanitize=address) -// or reconfigure the entire project with: -// cmake -DCMAKE_CXX_FLAGS="-fsanitize=address -fno-omit-frame-pointer -g" -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address" . -// Note: If you reconfigure everything, all other exercises will also be built with asan instrumentation! -// - Run the program, and inspect asan's output. It should give a detailed description of -// the problem, where the memory was allocated, etc. -// - Fix the problem. -void stackOverflow() { - char a[] = "1234"; - char b[] = "5678"; - - std::cout << "a='" << a << "\'\n"; - std::cout << "b='" << b << "\'\n"; - - char* ptr = a; - - std::cout << "Now writing into the array:\n"; - for (unsigned int i = 0; i < 10; ++i) { - ptr[i] = static_cast('a' + i); - } - - std::cout << "a='" << a << "\'\n"; - std::cout << "b='" << b << "\'\n"; -} - -// Task 2: -// Never return references or pointers to stack memory -// or temporary variables. They vanish when the function returns. -// - After you fixed the problem in Task 1, asan should immediately point to the function below. Try it. -// - If asan doesn't report a "use-after-free", the compiler might have inlined the function. -// You can try different optimisation flags such as -O0 / -O1 / -O2 -// - Fix the problem. -std::string& useAfterFree() { - auto str = std::make_unique("A temporary string"); - return *str; -} - -// Task 3: -// Use this functions to test leak sanitizer. -// - Start the program with -// ASAN_OPTIONS=detect_leaks=1 ./asan -// and see how the information given there helps tracing down the leak. -// - The fix is relatively easy: -// - Option 1: Do as in useAfterFree() -// - Option 2: Put the string on the stack. -std::string& memoryLeak() { - auto str = new std::string("This string will leak"); - return *str; -} - -int main() { - stackOverflow(); - std::cout << "String from useAfterFree is:'" << useAfterFree() << "\'\n"; - std::cout << "Dynamically allocated string is:'" << memoryLeak() << "\'\n"; - - return 0; -} diff --git a/exercises/asan/solution/asan.sol.cpp b/exercises/asan/solution/asan.sol.cpp deleted file mode 100644 index e38cb75a..00000000 --- a/exercises/asan/solution/asan.sol.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include -#include -#include - -// Task 1: -// Here we write past the end of a character array on the stack. -// This doesn't necessarily crash the program, but it's certainly a bad idea, -// as it will corrupt data. -// -// - Compile and run the program without address sanitizer. Maybe you are lucky -// and it doesn't crash, but the arrays are probably corrupted now. -// (To make it crash, you can write more characters, but that's not necessary for -// what we want to try with asan.) -// - Add -// -fsanitize=address -fno-omit-frame-pointer -g -// to the compile options and retry. -// - For the Makefile, just add the above flags to the command line. -// - For CMake, either add to asan/CMakeLists.txt: -// target_compile_options(asan PUBLIC -fsanitize=address -fno-omit-frame-pointer -g) -// target_link_libraries(asan PUBLIC -fsanitize=address) -// or reconfigure the entire project with: -// cmake -DCMAKE_CXX_FLAGS="-fsanitize=address -fno-omit-frame-pointer -g" -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address" . -// Note: If you reconfigure everything, all other exercises will also be built with asan instrumentation! -// - Run the program, and inspect asan's output. It should give a detailed description of -// the problem, where the memory was allocated, etc. -// - Fix the problem. -void stackOverflow() { - char a[] = "1234"; - char b[] = "5678"; - - std::cout << "a='" << a << "\'\n"; - std::cout << "b='" << b << "\'\n"; - - char* ptr = a; - - std::cout << "Now writing into the array:\n"; - for (unsigned int i = 0; i < std::size(a)-1; ++i) { // do not touch the 0 byte at the end - ptr[i] = static_cast('a' + i); - } - - std::cout << "a='" << a << "\'\n"; - std::cout << "b='" << b << "\'\n"; -} - -// Task 2: -// Never return references or pointers to stack memory -// or temporary variables. They vanish when the function returns. -// - After you fixed the problem in Task 1, asan should immediately point to the function below. Try it. -// - If asan doesn't report a "use-after-free", the compiler might have inlined the function. -// You can try different optimisation flags such as -O0 / -O1 / -O2 -// - Fix the problem. -std::string useAfterFree() { - return "A temporary string"; -} - -// Task 3: -// Use this functions to test leak sanitizer. -// - Start the program with -// ASAN_OPTIONS=detect_leaks=1 ./asan -// and see how the information given there helps tracing down the leak. -// - The fix is relatively easy: -// - Option 1: Do as in useAfterFree() -// - Option 2: Put the string on the stack. -std::string memoryLeak() { - return "This string will not leak"; -} - -int main() { - stackOverflow(); - std::cout << "String from useAfterFree is:'" << useAfterFree() << "\'\n"; - std::cout << "Dynamically allocated string is:'" << memoryLeak() << "\'\n"; - - return 0; -} diff --git a/exercises/basicTypes/.gitignore b/exercises/basicTypes/.gitignore deleted file mode 100644 index c8d7d09f..00000000 --- a/exercises/basicTypes/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -basicTypes -basicTypes.sol diff --git a/exercises/basicTypes/CMakeLists.txt b/exercises/basicTypes/CMakeLists.txt deleted file mode 100644 index 16b2d5c8..00000000 --- a/exercises/basicTypes/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -# Set up the project. -cmake_minimum_required( VERSION 3.12 ) -project( basicTypes LANGUAGES CXX ) - -# Set up the compilation environment. -include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) -set( CMAKE_CXX_STANDARD 20 ) - -# Create the user's executable. -add_executable( basicTypes PrintHelper.h basicTypes.cpp ) - -# Create the "solution executable". -add_executable( basicTypes.sol EXCLUDE_FROM_ALL PrintHelper.h solution/basicTypes.sol.cpp ) -target_include_directories( basicTypes.sol PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ) -add_dependencies( solution basicTypes.sol ) diff --git a/exercises/basicTypes/Makefile b/exercises/basicTypes/Makefile deleted file mode 100644 index 285197b9..00000000 --- a/exercises/basicTypes/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -all: basicTypes -solution: basicTypes.sol - -clean: - rm -f *o *so basicTypes *~ basicTypes.sol - -% : %.cpp PrintHelper.h - $(CXX) -g -std=c++20 -Wall -Wextra -o $@ $< - -%.sol : solution/%.sol.cpp PrintHelper.h - $(CXX) -g -std=c++20 -Wall -Wextra -o $@ $< -I . diff --git a/exercises/basicTypes/PrintHelper.h b/exercises/basicTypes/PrintHelper.h deleted file mode 100644 index 7df4c126..00000000 --- a/exercises/basicTypes/PrintHelper.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -/* - * NOTE: You don't need to understand the print helpers here. - * Their purpose is to show each expression, the type it evaluates to, and the value it evaluates to. - * Please go back to the main file now. :-) - */ - -#ifdef _MSC_VER -std::string demangle(std::string_view input) { return std::string{input}; } -#else -#include -std::string demangle(std::string_view input) { - int status; - return abi::__cxa_demangle(input.data(), NULL, NULL, &status); -} -#endif - -// This helper prints type and value of an expression -void printWithTypeInfo(std::string expression, auto const & t, bool useBitset = false) { - const auto & ti = typeid(t); - const std::string realname = demangle(ti.name()); - - std::cout << std::left << std::setw(30) << expression << " type=" << std::setw(20) << realname << "value="; - if (useBitset) { - std::cout << "0b" << std::bitset<16>(t) << "\n"; - } else { - std::cout << std::setprecision(25) << t << "\n"; - } -} - -// This macro both prints and evaluates an expression: -#define print(A) printWithTypeInfo("Line " + std::to_string(__LINE__) + ": "#A, A); -#define printBinary(A) printWithTypeInfo("Line " + std::to_string(__LINE__) + ": "#A, A, true); diff --git a/exercises/basicTypes/README.md b/exercises/basicTypes/README.md deleted file mode 100644 index 132a0a6e..00000000 --- a/exercises/basicTypes/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Fundamental types and expressions - -## Tasks: -- Compile the program and analyse the output of the different expressions -- Discuss with other students or your tutor in case the result of an expression is a surprise -- Fix the marked expressions by changing types such that they produce meaningful results -- Answer the questions in the code diff --git a/exercises/basicTypes/basicTypes.cpp b/exercises/basicTypes/basicTypes.cpp deleted file mode 100644 index b67bccb8..00000000 --- a/exercises/basicTypes/basicTypes.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include "PrintHelper.h" - -/* ************************************* - * * Fundamental types and expressions * - * ************************************* - * - * Tasks: - * ------ - * - Compile the program and analyse the output of the different expressions - * - Discuss with other students or your tutor in case the result of an expression is a surprise - * - Fix the marked expressions by changing types such that they produce meaningful results - * - Answer the questions in the code - */ - -int main() { - std::cout << "Using literals of different number types:\n"; - print(5); - print(5/2); //FIXME - print(100/2ull); - print(2 + 4ull); - print(2.f + 4ull); - print(0u - 1u); // FIXME - print(1.0000000001f); // FIXME Why is this number not represented correctly? - print(1. + 1.E-18); // FIXME - - std::cout << "\nUsing increment and decrement operators:\n"; - int a = 1; - int b; - int c; - print(b = a++); // Q: What is the difference between a++ and ++a? - print(c = ++a); - print(a); - print(b); - print(c); - - std::cout << "\nCompound assignment operators:\n"; - int n = 1; - print(n *= 2); // Q: Is there a difference between this and the next line? - print(n *= 2.9); - print(n -= 1.1f); - print(n /= 4); // Q: Based on the results of these expressions, is there a better type to be used for n? - - std::cout << "\nLogic expressions:\n"; - const bool alwaysTrue = true; - bool condition1 = false; - bool condition2 = true; - print( alwaysTrue && condition1 && condition2 ); - print( alwaysTrue || condition1 && condition2 ); // Q: Are this and the following expressions useful? - print( alwaysTrue && condition1 || condition2 ); - print(condition1 != condition1); // Q: What is the difference between this and the following expression? - print(condition2 = !condition2); - print( alwaysTrue && condition1 && condition2 ); - print( alwaysTrue || condition1 && condition2 ); - print( alwaysTrue && condition1 || condition2 ); - - std::cout << '\n'; - print( false || 0b10 ); // Q: What is the difference between || and | ? - print( false | 0b10 ); - printBinary( 0b1 & 0b10 ); - printBinary( 0b1 | 0b10 ); - printBinary( 0b1 && 0b10 ); // Q: Are the operators && and || appropriate for integer types? - printBinary( 0b1 || 0b10 ); - - std::cout << "\nPlay with characters and strings:\n"; - print("a"); // Q: Why is this expression two bytes at run time, the next only one? - print('a'); - - char charArray[20]; - char* charPtr = charArray; - charArray[19] = 0; // Make sure that our string is terminated with the null byte - - print(charArray); - print(charArray[0] = 'a'); - print(charArray); - print(charArray[1] = 98); - print(charArray); - print(charPtr); - // FIXME: Ensure that no unexpected garbage is printed above -} diff --git a/exercises/basicTypes/solution/basicTypes.sol.cpp b/exercises/basicTypes/solution/basicTypes.sol.cpp deleted file mode 100644 index 047c5d89..00000000 --- a/exercises/basicTypes/solution/basicTypes.sol.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include "PrintHelper.h" - -/* ************************************* - * * Fundamental types and expressions * - * ************************************* - * - * Tasks: - * - Compile the program and analyse the output of the different expressions - * - Discuss with other students or your tutor in case the result of an expression is a surprise - * - Fix the marked expressions by changing types such that they produce meaningful results - * - Answer the questions in the code - */ - -int main() { - std::cout << "Using literals of different number types:\n"; - print(5); - print(5/2.); //FIXME - print(100/2ull); - print(2 + 4ull); - print(2.f + 4ull); - print(0 - 1 ); // FIXME - print(1.0000000001 ); // FIXME Why is this number not represented correctly? - print(1.l+ 1.E-18); // FIXME - - std::cout << "\nUsing increment and decrement operators:\n"; - int a = 1; - int b; - int c; - print(b = a++); // Q: What is the difference between a++ and ++a? - print(c = ++a); // A: Whether it returns the previous or new value - print(a); - print(b); - print(c); - - std::cout << "\nCompound assignment operators:\n"; - float n = 1; - print(n *= 2); // Q: Is there a difference between this and the next line? - print(n *= 2.9); // A: Yes, the computation runs in float and is converted back to int - print(n -= 1.1f); - print(n /= 4); // Q: Based on the results of these expressions, is there a better type to be used for n? - // A: Probably yes, for example float - - std::cout << "\nLogic expressions:\n"; - const bool alwaysTrue = true; - bool condition1 = false; - bool condition2 = true; - print( alwaysTrue && condition1 && condition2 ); - print( alwaysTrue || condition1 && condition2 ); // Q: Are this and the following expressions useful? - // A: Not really. Since we use "true ||", it is always true. - print( alwaysTrue && condition1 || condition2 ); // A: "true && condition1" is the same as "condition1" - print(condition1 != condition1); // Q: What is the difference between this and the following expression? - print(condition2 = !condition2); // A: The first is a comparison, the second a negation with subsequent assignment - print( alwaysTrue && condition1 && condition2 ); - print( alwaysTrue || condition1 && condition2 ); - print( alwaysTrue && condition1 || condition2 ); - - std::cout << '\n'; - print( false || 0b10 ); // Q: What is the difference between || and | ? - print( false | 0b10 ); // A: a boolean operation vs. a bit-wise boolean operation - printBinary( 0b1 & 0b10 ); - printBinary( 0b1 | 0b10 ); - printBinary( 0b1 && 0b10 ); // Q: Are the operators && and || appropriate for integer types? - printBinary( 0b1 || 0b10 ); // A: Most likely not, because the integers are first converted to boolean - - std::cout << "\nPlay with characters and strings:\n"; - print("a"); // Q: Why is this expression two bytes at run time, the next only one? - print('a'); // A: Because the first one is a string, which is 0-terminated - - char charArray[20]; - // There are many ways to solve this, for example to use std::string and not manually manage the memory. - // However, if one really desires to manage a char array, one should at least initialise it with the 0 byte: - std::fill(std::begin(charArray), std::end(charArray), '\0'); - char* charPtr = charArray; - - print(charArray); - print(charArray[0] = 'a'); - print(charArray); - print(charArray[1] = 98); - print(charArray); - print(charPtr); - // FIXME: Ensure that no unexpected garbage is printed above -} diff --git a/exercises/callgrind/.gitignore b/exercises/callgrind/.gitignore deleted file mode 100644 index 8f9f534d..00000000 --- a/exercises/callgrind/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -fibocrunch -fibocrunch.sol diff --git a/exercises/callgrind/CMakeLists.txt b/exercises/callgrind/CMakeLists.txt deleted file mode 100644 index c9393110..00000000 --- a/exercises/callgrind/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -# Set up the project. -cmake_minimum_required( VERSION 3.12 ) -project( callgrind LANGUAGES CXX ) - -# Set up the compilation environment. -include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) - -# Create the user's executable. -add_executable( fibocrunch "fibocrunch.cpp" ) - -# Create the "solution executable". -add_executable( fibocrunch.sol EXCLUDE_FROM_ALL "solution/fibocrunch.sol.cpp" ) -add_dependencies( solution fibocrunch.sol ) diff --git a/exercises/callgrind/Makefile b/exercises/callgrind/Makefile deleted file mode 100644 index 8871289e..00000000 --- a/exercises/callgrind/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -all: fibocrunch -solution : fibocrunch.sol - -clean: - rm -f *o fibocrunch *~ fibocrunch.sol fibocrunch.nostl core callgrind.out.* - -fibocrunch : fibocrunch.cpp - ${CXX} -std=c++17 -g -O0 -Wall -Wextra -L. -o $@ $< - -fibocrunch.sol : solution/fibocrunch.sol.cpp - ${CXX} -std=c++17 -Wall -Wextra -L. -o $@ $< diff --git a/exercises/callgrind/README.md b/exercises/callgrind/README.md deleted file mode 100644 index 58a28809..00000000 --- a/exercises/callgrind/README.md +++ /dev/null @@ -1,9 +0,0 @@ - -## Instructions - -* compile, run, it will be slow -* change nb iterations to 20 -* run with `valgrind --tool=callgrind` -* look at output with kcachegrind -* change fibo call to fibo2 -* observe the change in kcachegrind diff --git a/exercises/callgrind/fibocrunch.cpp b/exercises/callgrind/fibocrunch.cpp deleted file mode 100644 index 16eea368..00000000 --- a/exercises/callgrind/fibocrunch.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include - -constexpr auto NBITERATIONS = 20; -constexpr auto MAX = 40u; - -unsigned int add(unsigned int a, unsigned int b) { - return a + b; -} - -unsigned int mul(unsigned int a, unsigned int b) { - return a * b; -} - -unsigned int power(unsigned int a, unsigned int b) { - unsigned int res = 1; - for (unsigned int i = 0; i < b; i++) res *= a; - return res; -} - -unsigned int fibo(int a) { - if (a == 1 || a == 0) { - return 1; - } else { - return fibo(a-1)+fibo(a-2); - } -} - -unsigned int fibo2(int n) { - return static_cast((1/std::sqrt(5)) * (std::pow(((1 + std::sqrt(5)) / 2), n) - std::pow(((1 - std::sqrt(5)) / 2), n))); -} - -int main() { - std::default_random_engine e; - std::uniform_int_distribution d{0u, MAX}; - for (unsigned int i = 0; i < NBITERATIONS; i++) { - unsigned int a = d(e); - unsigned int b = d(e); - add(a, b); - mul(a, b); - power(a, b); - fibo(a); - } -} diff --git a/exercises/callgrind/solution/fibocrunch.sol.cpp b/exercises/callgrind/solution/fibocrunch.sol.cpp deleted file mode 100644 index 05335dea..00000000 --- a/exercises/callgrind/solution/fibocrunch.sol.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include - -constexpr auto NBITERATIONS = 20; -constexpr auto MAX = 40u; - -unsigned int add(unsigned int a, unsigned int b) { - return a + b; -} - -unsigned int mul(unsigned int a, unsigned int b) { - return a * b; -} - -unsigned int power(unsigned int a, unsigned int b) { - unsigned int res = 1; - for (unsigned int i = 0; i < b; i++) res *= a; - return res; -} - -unsigned int fibo(int a) { - if (a == 1 || a == 0) { - return 1; - } else { - return fibo(a-1)+fibo(a-2); - } -} - -unsigned int fibo2(int n) { - return static_cast((1/std::sqrt(5)) * (std::pow(((1 + std::sqrt(5)) / 2), n) - std::pow(((1 - std::sqrt(5)) / 2), n))); -} - -int main() { - std::default_random_engine e; - std::uniform_int_distribution d{0u, MAX}; - for (unsigned int i = 0; i < NBITERATIONS; i++) { - unsigned int a = d(e); - unsigned int b = d(e); - add(a, b); - mul(a, b); - power(a, b); - fibo2(a); - } -} diff --git a/exercises/check_setup.sh b/exercises/check_setup.sh deleted file mode 100755 index 6ba1cf17..00000000 --- a/exercises/check_setup.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/bash - -RED='\033[0;31m' -YEL='\033[0;33m' -NORMAL='\033[0m' -COL=12 - -exit_status=0 - -# from: https://stackoverflow.com/a/4024263 -function version_less() { - [ "$1" = "`echo -e "$1\n$2" | sort -V | head -n1`" ] -} - -function check_tool() { - min_version=$2 || "0" - required=$3 || true - if [ -x "$(command -v $1)" ] - then - version=$($1 --version | grep -o -E "[0-9]+.[0-9]+(.[0-9]+)?" | head -1) - if version_less $version $min_version - then - printf "%-${COL}s found, ${RED}version: ${version}, need at least: ${min_version}${NORMAL}\n" $1 - else - printf "%-${COL}s found, version: ${version}\n" $1 - return 0 - fi - elif $required - then - printf "${RED}%-${COL}s not found, but required${NORMAL}\n" $1 - exit_status=1 - else - printf "${YEL}%-${COL}s not found, but optional${NORMAL}\n" $1 - fi - return 1 -} - -# compiler -check_tool g++ 10.0.0 false || check_tool clang++ 11.0.0 false || { echo -e "${RED}No supported compiler found${NORMAL}"; exit_status=1; } # clang does not work for header_units exercise - -# build tools -check_tool make -check_tool cmake 3.12.0 -check_tool ccmake 3.12.0 false - -# debugger -check_tool gdb 10.0.0 false || check_tool lldb 11.0.0 false || { echo -e "${RED}No supported debugger found${NORMAL}"; exit_status=1; } - -# utils -check_tool nm -check_tool ldd 0.0 false || check_tool otool 0.0 false || { echo -e "${RED}Missing ldd or otool${NORMAL}"; exit_status=1; } - -# tools -check_tool valgrind -check_tool kcachegrind -check_tool cppcheck -check_tool clang-format -check_tool clang-tidy -check_tool python3 - -exit $exit_status diff --git a/exercises/classes/.gitignore b/exercises/classes/.gitignore deleted file mode 100644 index a5a19752..00000000 --- a/exercises/classes/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -classes -classes_sol diff --git a/exercises/classes/CMakeLists.txt b/exercises/classes/CMakeLists.txt deleted file mode 100644 index cfc53a9c..00000000 --- a/exercises/classes/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -# Set up the project. -cmake_minimum_required( VERSION 3.12 ) -project( operators LANGUAGES CXX ) - -# Set up the compilation environment. -include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) - -# Create the user's executable. -add_executable( classes "classes.cpp" ) - -# Create the "solution executable". -add_executable( classes_sol EXCLUDE_FROM_ALL "solution/classes_sol.cpp" ) -add_dependencies( solution classes_sol ) diff --git a/exercises/classes/Makefile b/exercises/classes/Makefile deleted file mode 100644 index b0a6014b..00000000 --- a/exercises/classes/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -all: classes -solution: classes_sol - -clean: - rm -f *o classes *~ classes_sol - -classes : classes.cpp - ${CXX} -g -std=c++17 -O0 -Wall -Wextra -L. -o $@ $< - -classes_sol : solution/classes_sol.cpp - ${CXX} -g -std=c++17 -O0 -Wall -Wextra -L. -o $@ $< diff --git a/exercises/classes/README.md b/exercises/classes/README.md deleted file mode 100644 index 26aba0a8..00000000 --- a/exercises/classes/README.md +++ /dev/null @@ -1,32 +0,0 @@ - -## Instructions - -STEP 1 -- Complete the class Fraction so that a Fraction can be construct from one or two integer. - Check the first two lines of main() are working (comment out the rest) -- Add the function equal(). - Check the second section of main() works. -- Add the function multiply(). - Check the whole main() works. - -STEP 2 -- Replace the function printTestResult() by a class TestResultPrinter - with a method process() that take the same arguments as before. - Upgrade CHECK() and main(). -- Transform the WIDTH constant into a variable member of TestResultPrinter, - which is initialized in its constructor. - Upgrade main(). - -OPTIONAL STEP 3 -- Move multiply() and compare() as friend functions within the class Fraction. - Check main() works. -- Remove the accessors numerator() and denominator(). - Check main() works. - -OPTIONAL STEP 4 -- Remove the systematic call to normalize(). -- Add a equivalent() method to Fraction. -- Upgrade the tests accordingly. -- Transform the private normalize() into a public const normalized() method - which return the normalized fraction. -- Add some tests to check normalized(). diff --git a/exercises/classes/classes.cpp b/exercises/classes/classes.cpp deleted file mode 100644 index 05bd5dc4..00000000 --- a/exercises/classes/classes.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include -#include -#include -#include - -class Fraction { - -public: - - // ADD YOUR CODE HERE - - std::string str() const { - std::ostringstream oss; - oss << m_num << '/' << m_denom; - return oss.str(); - } - - int numerator() const { - return m_num; - } - int denominator() const { - return m_denom; - } - -private: - - void normalize() { - const int gcd = std::gcd(m_num, m_denom); - m_num /= gcd; - m_denom /= gcd; - } - - int m_num, m_denom; -}; - -// ADD YOUR CODE HERE - -// This is using the cpp, the C preprocessor to expand a bit of code -// (the what argument) to a pair containing a string representation -// of it and the code itself. That way, print is given a string and a -// value where the string is the code that lead to the value -#define CHECK(print,what) print(#what, what) - -unsigned int WIDTH {20}; - -void printTestResult(std::string const & what, bool passed) { - std::cout << std::setw(WIDTH) << what << ": " << (passed ? "PASS" : "** FAIL **") << '\n'; -} - -int main() { - - // create a fraction with values 3 (which is 3/1) and 1/3 - std::cout< -#include -#include -#include - -class Fraction { - -public: - - Fraction(int a_num, int a_denom = 1) : m_num(a_num), m_denom(a_denom) {} - - std::string str() const { - std::ostringstream oss; - oss << m_num << '/' << m_denom; - return oss.str(); - } - - friend bool equal( Fraction const & lhs, Fraction const & rhs ) { - return (lhs.m_num==rhs.m_num) && (lhs.m_denom==rhs.m_denom); - } - - friend bool equivalent( Fraction const & lhs, Fraction const & rhs ) { - return (lhs.m_num*rhs.m_denom==rhs.m_num*lhs.m_denom); - } - - friend Fraction multiply( Fraction const & lhs, Fraction const & rhs ) { - return {lhs.m_num*rhs.m_num, lhs.m_denom*rhs.m_denom}; - } - - Fraction normalized() const { - const int gcd = std::gcd(m_num, m_denom); - return {m_num/gcd, m_denom/gcd}; - } - -private: - - int m_num, m_denom; -}; - -class TestResultPrinter { - -public: - - TestResultPrinter( unsigned int a_width ) : m_width(a_width) {} - - void process(std::string const & what, bool passed) { - std::cout << std::left << std::setw(m_width) << what << ": " << (passed ? "PASS" : "** FAIL **") << '\n'; - } - -private: - - unsigned int m_width; - -}; - -// This is using the cpp, the C preprocessor to expand a bit of code -// (the what argument) to a pair containing a string representation -// of it and the code itself. That way, print is given a string and a -// value where the string is the code that lead to the value -#define CHECK(printer,what) printer.process(#what, what) - -int main() { - - // create a fraction with values 3 (which is 3/1) and 1/3 - std::cout< -#include -#include - -/* - -In the code below, we provide two implementations of the function increment(). -The commented one is optimized for iterators which fulfill the requirements of -the concept RandomAccessIterator. - -1. Uncomment and complete the concept RandomAccessIterator: check that the - class IterT has operator +=. -2. Find an existing concept in the standard library, which can replace the - previous user-defined concept. - -*/ - -/* - -template -concept RandomAccessIterator = requires(... TO BE COMPLETED...) { - ... TO BE COMPLETED... -}; - -template -void increment(IterT &iter, unsigned d) { - iter += d; - std::cout << "(random)\n"; -} - -*/ - -template -void increment(IterT &iter, unsigned d) { - while (d--) - ++iter; - std::cout << "(other)\n"; -} - -int main() { - std::list l_data = {1, 2, 3, 4, 5}; - auto l_itr = l_data.begin(); - increment(l_itr, 2); - - std::vector v_data = {1, 2, 3, 4, 5}; - auto v_itr = v_data.begin(); - increment(v_itr, 2); -} diff --git a/exercises/concepts/solution/concepts.sol1.cpp b/exercises/concepts/solution/concepts.sol1.cpp deleted file mode 100644 index 49a6193b..00000000 --- a/exercises/concepts/solution/concepts.sol1.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include -#include - -template -concept RandomAccessIterator = requires(IterT itr, unsigned d) { - itr += d; -}; - -template -void increment(IterT &iter, unsigned d) { - iter += d; - std::cout << "(random)" << std::endl; -} - -template -void increment(IterT &iter, unsigned d) { - while (d--) - ++iter; - std::cout << "(other)" << std::endl; -} - -int main() { - - std::list l_data = {1, 2, 3, 4, 5}; - auto l_itr = begin(l_data); - increment(l_itr, 2); - - std::vector v_data = {1, 2, 3, 4, 5}; - auto v_itr = begin(v_data); - increment(v_itr, 2); - -} diff --git a/exercises/concepts/solution/concepts.sol2.cpp b/exercises/concepts/solution/concepts.sol2.cpp deleted file mode 100644 index a1151b1b..00000000 --- a/exercises/concepts/solution/concepts.sol2.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include -#include -#include - -template -void increment(IterT &iter, unsigned d) { - iter += d; - std::cout << "(random)" << std::endl; -} - -template -void increment(IterT &iter, unsigned d) { - while (d--) - ++iter; - std::cout << "(other)" << std::endl; -} - -// Main - -int main() { - - std::list l_data = {1, 2, 3, 4, 5}; - auto l_itr = begin(l_data); - increment(l_itr, 2); - - std::vector v_data = {1, 2, 3, 4, 5}; - auto v_itr = begin(v_data); - increment(v_itr, 2); - -} diff --git a/exercises/condition_variable/.gitignore b/exercises/condition_variable/.gitignore deleted file mode 100644 index 753f759f..00000000 --- a/exercises/condition_variable/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -condition_variable -condition_variable.sol diff --git a/exercises/condition_variable/CMakeLists.txt b/exercises/condition_variable/CMakeLists.txt deleted file mode 100644 index 0a9097d4..00000000 --- a/exercises/condition_variable/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -# Set up the project. -cmake_minimum_required( VERSION 3.12 ) -project( condition_variable LANGUAGES CXX ) - -# Set up the compilation environment. -include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) - -# Figure out how to use the platform's thread capabilities. -find_package( Threads REQUIRED ) - -# Create the user's executable. -add_executable( condition_variable "condition_variable.cpp" ) -target_link_libraries( condition_variable PRIVATE Threads::Threads ) - -# Create the "solution executable". -add_executable( condition_variable.sol EXCLUDE_FROM_ALL "solution/condition_variable.sol.cpp" ) -target_link_libraries( condition_variable.sol PRIVATE Threads::Threads ) -add_dependencies( solution condition_variable.sol ) diff --git a/exercises/condition_variable/Makefile b/exercises/condition_variable/Makefile deleted file mode 100644 index 19c7ecad..00000000 --- a/exercises/condition_variable/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -all: condition_variable -solution: condition_variable.sol - -clean: - rm -f *o condition_variable *~ core condition_variable.sol - -% : %.cpp - ${CXX} -g -std=c++17 -O0 -pthread -Wall -Wextra -L. -o $@ $< - -condition_variable.sol : solution/condition_variable.sol.cpp - ${CXX} -g -std=c++17 -O0 -pthread -Wall -Wextra -L. -o $@ $< diff --git a/exercises/condition_variable/condition_variable.cpp b/exercises/condition_variable/condition_variable.cpp deleted file mode 100644 index 6076c764..00000000 --- a/exercises/condition_variable/condition_variable.cpp +++ /dev/null @@ -1,140 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -/* - * ------------------------------------------------------------ - * Setup and helpers. You don't need to change any code here. - * ------------------------------------------------------------ - */ -using namespace std::chrono_literals; // We can write 1s - -// Print contents of the stream to cout in a thread-safe manner. -// This class consumes stream inputs, buffers them, and writes them -// out when destructed respecting the cout_mutex. -class SafeCout { - std::stringstream stream; - inline static std::mutex cout_mutex; // We need this to synchronise printing - -public: - ~SafeCout() { - std::scoped_lock coutLock{cout_mutex}; - std::cout << stream.str(); - } - - template - SafeCout & operator<<(T&& arg) { - stream << std::forward(arg); - return *this; - } -}; - -// A mock data object -struct Data { - bool isReady() const { - return _isReady; - } - - bool _isReady = false; - bool _isConsistent = false; -}; - - -// The function that processes the data. You don't need to touch it. -// It will check whether the data are in a consistent state, and -// idle a bit to simulate longer data processing. -// Note: It should run in parallel. -bool process(unsigned int threadIdx, Data const & data) { - bool processingOK = true; - - SafeCout{} << '[' << threadIdx << "] I'm starting to process the data now\n"; - if (!data._isConsistent) { - processingOK = false; - SafeCout{} << '[' << threadIdx << "] ERROR data isn't fully ready! Race condition!\n"; - } - - // Burn some CPU cycles to simulate intensive data processing. - const auto startTime = std::chrono::high_resolution_clock::now(); - unsigned dummyCounter = 0; - while (std::chrono::high_resolution_clock::now() - startTime < 5s) { - ++dummyCounter; - } - return processingOK; -} - -/* - * ------------------------------------------------------------ - * Exercise code you need to work on. - * ------------------------------------------------------------ - * This program tries to implement a producer/multi-consumer dependency between threads. - * One producer provides some data, and multiple consumers wait for the data to become ready. - * - * The threads communicate via std::condition_variable, but the implementation is incomplete. - * - * Tasks: - * 1. Run the program and understand why the consumer threads start running too early (on some - * platforms, at least ...). - * Run it multiple times if necessary. - * Why do they wake up although they should remain sleeping? - * 2. Fix the race condition by protecting the data production phase with a lock. - * 3. When you run the program now, the consumers should start running only after the data are ready. - * Why do they run one by one, though? - * Check the CPU consumption with a tool like top in a second shell. - * Ideally, we want 400% utilisation. - * 4. Fix the consumer waiting phase like in the lecture to make the consumers run in parallel. - * Check the CPU consumption again. - */ - - -int main() { - std::mutex mutex; - std::condition_variable cond; - Data data; - - // DATA-PROCESSING THREADS - // Here we start the processing threads. They have to wait for the data to be ready, - // and then they should process it in parallel. - auto processData = [&](unsigned int threadIdx){ - SafeCout{} << '[' << threadIdx << "] I'm starting to wait\n"; - - std::unique_lock lock{mutex}; - cond.wait(lock, [&](){ return data.isReady(); }); - - auto result = process(threadIdx, data); - - SafeCout{} << '[' << threadIdx << "] Data processing completed " << (result ? "OK" : "with failure!") << '\n'; - }; - - std::vector consumers; - for (unsigned int i=0; i < 4; ++i) { - consumers.emplace_back(processData, i); - } - - // DATA-PRODUCER THREAD - // This thread produces the data. We simulate a complicated way of producing the data - // by making the thread wait for a few seconds during the data production. - std::thread producer([&](){ - SafeCout{} << "[p] Starting to produce data\n"; - data._isReady = true; - // Sleep a bit to simulate a complicated set up phase - std::this_thread::sleep_for(6s); - data._isConsistent = true; - - SafeCout{} << "[p] Data ready now\n"; - - // Wake up all threads - cond.notify_all(); - }); - - // Join all threads, so we don't terminate prematurely - producer.join(); - for (auto & t : consumers) { - t.join(); - } - - return 0; -} diff --git a/exercises/condition_variable/solution/condition_variable.sol.cpp b/exercises/condition_variable/solution/condition_variable.sol.cpp deleted file mode 100644 index 87217a97..00000000 --- a/exercises/condition_variable/solution/condition_variable.sol.cpp +++ /dev/null @@ -1,142 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -/* - * ------------------------------------------------------------ - * Setup and helpers. You don't need to change any code here. - * ------------------------------------------------------------ - */ -using namespace std::chrono_literals; // We can write 1s - -// Print contents of the stream to cout in a thread-safe manner. -// This class consumes stream inputs, buffers them, and writes them -// out when destructed respecting the cout_mutex. -class SafeCout { - std::stringstream stream; - inline static std::mutex cout_mutex; // We need this to synchronise printing - -public: - ~SafeCout() { - std::scoped_lock coutLock{cout_mutex}; - std::cout << stream.str(); - } - - template - SafeCout & operator<<(T&& arg) { - stream << std::forward(arg); - return *this; - } -}; - -// A mock data object -struct Data { - bool isReady() const { - return _isReady; - } - - bool _isReady = false; - bool _isConsistent = false; -}; - - -// The function that processes the data. You don't need to touch it. -// It will check whether the data are in a consistent state, and -// idle a bit to simulate longer data processing. -// Note: It should run in parallel. -bool process(unsigned int threadIdx, Data const & data) { - bool processingOK = true; - - SafeCout{} << '[' << threadIdx << "] I'm starting to process the data now\n"; - if (!data._isConsistent) { - processingOK = false; - SafeCout{} << '[' << threadIdx << "] ERROR data isn't fully ready! Race condition!\n"; - } - - // Burn some CPU cycles to simulate intensive data processing. - const auto startTime = std::chrono::high_resolution_clock::now(); - unsigned dummyCounter = 0; - while (std::chrono::high_resolution_clock::now() - startTime < 5s) { - ++dummyCounter; - } - return processingOK; -} - -/* - * ------------------------------------------------------------ - * Exercise code you need to work on. - * ------------------------------------------------------------ - * This program tries to implement a producer/multi-consumer dependency between threads. - * One producer provides some data, and multiple consumers wait for the data to become ready. - * - * The threads communicate via std::condition_variable, but the implementation is incomplete. - * - * Tasks: - * 1. Run the program and understand why the consumer threads start running too early (on some - * platforms, at least ...). - * Run it multiple times if necessary. - * Why do they wake up although they should remain sleeping? - * 2. Fix the race condition by protecting the data production phase with a lock. - * 3. When you run the program now, the consumers should start running only after the data are ready. - * Why do they run one by one, though? - * Check the CPU consumption with a tool like top in a second shell. - * Ideally, we want 400% utilisation. - * 4. Fix the consumer waiting phase like in the lecture to make the consumers run in parallel. - * Check the CPU consumption again. - */ - - -int main() { - std::mutex mutex; - std::condition_variable cond; - Data data; - - // DATA-PROCESSING THREADS - // Here we start the processing threads. They have to wait for the data to be ready, - // and then they should process it in parallel. - auto processData = [&](unsigned int threadIdx){ - SafeCout{} << '[' << threadIdx << "] I'm starting to wait\n"; - { - std::unique_lock lock{mutex}; - cond.wait(lock, [&](){ return data.isReady(); }); - } - auto result = process(threadIdx, data); - - SafeCout{} << '[' << threadIdx << "] Data processing completed " << (result ? "OK" : "with failure!") << '\n'; - }; - - std::vector consumers; - for (unsigned int i=0; i < 4; ++i) { - consumers.emplace_back(processData, i); - } - - // DATA-PRODUCER THREAD - // This thread produces the data. We simulate a complicated way of producing the data - // by making the thread wait for a few seconds during the data production. - std::thread producer([&](){ - SafeCout{} << "[p] Starting to produce data\n"; - { - std::scoped_lock lock(mutex); - data._isReady = true; - // Sleep a bit to simulate a complicated set up phase - std::this_thread::sleep_for(6s); - data._isConsistent = true; - } - SafeCout{} << "[p] Data ready now\n"; - - // Wake up all threads - cond.notify_all(); - }); - - // Join all threads, so we don't terminate prematurely - producer.join(); - for (auto & t : consumers) { - t.join(); - } - - return 0; -} diff --git a/exercises/constness/.gitignore b/exercises/constness/.gitignore deleted file mode 100644 index 57abd716..00000000 --- a/exercises/constness/.gitignore +++ /dev/null @@ -1 +0,0 @@ -constplay diff --git a/exercises/constness/CMakeLists.txt b/exercises/constness/CMakeLists.txt deleted file mode 100644 index 98a87237..00000000 --- a/exercises/constness/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -# Set up the project. -cmake_minimum_required( VERSION 3.12 ) -project( constness LANGUAGES CXX ) - -# Set up the compilation environment. -include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) - -# Create the user's executable. -add_executable( constplay "constplay.cpp" ) diff --git a/exercises/constness/Makefile b/exercises/constness/Makefile deleted file mode 100644 index 2e3eb578..00000000 --- a/exercises/constness/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -all: constplay - -clean: - rm -f *o constplay *~ constplay.sol - -constplay : constplay.cpp - ${CXX} -std=c++17 -Wall -Wextra -L. -o $@ $< diff --git a/exercises/constness/README.md b/exercises/constness/README.md deleted file mode 100644 index 74ac1d68..00000000 --- a/exercises/constness/README.md +++ /dev/null @@ -1,6 +0,0 @@ - -## Instructions - -* open `constplay.cpp` -* try to find out which lines inside `main` will be problematic and comment them out -* try to compile and check your findings diff --git a/exercises/constness/constplay.cpp b/exercises/constness/constplay.cpp deleted file mode 100644 index d8811d8a..00000000 --- a/exercises/constness/constplay.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include -#include - -/* This is a dummy function to demonstrate pass by value. - * Since it doesn't do anything with the argument, we suppress - * possible compiler warnings using `maybe_unused`. - */ -void copy(int a) { - [[maybe_unused]] int val = a; -} - -void copyConst(const int a) { - [[maybe_unused]] int val = a; -} - -void write(int* a) { - *a = 42; -} -void write(int& a) { - a = 42; -} - -void read(const int* a) { - [[maybe_unused]] int val = *a; -} -void read(int const & a) { - [[maybe_unused]] int val = a = 2; -} - -struct Test { - void hello(std::string &s) { - std::cout << "Hello " << s << '\n'; - } - void helloConst(std::string &s) const { - std::cout << "Hello " << s << '\n'; - } -}; - -int main() { - // try pointer to constant - int a = 1, b = 2; - int const *i = &a; - *i = 5; - i = &b; - - // try constant pointer - int * const j = &a; - *j = 5; - j = &b; - - // try constant pointer to constant - int const * const k = &a; - *k = 5; - k = &b; - - // try constant arguments of functions - int l = 0; - const int m = 0; - copy(l); - copy(m); - copyConst(l); - copyConst(m); - - // try constant arguments of functions with pointers - { - int *p = &a; - const int *r = &b; - write(p); - write(r); - read(p); - read(r); - } - - // try constant arguments of functions with references - { - int p = 0; - const int r = 0; - write(2); - write(r); - read(2); - read(r); - } - - // try constant method in a class - Test t; - const Test tc; - std::string s("World"); - t.hello(s); - tc.hello(s); - t.helloConst(s); - tc.helloConst(s); - - return 0; -} diff --git a/exercises/control/.gitignore b/exercises/control/.gitignore deleted file mode 100644 index 3c3b9fe9..00000000 --- a/exercises/control/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -control -control.sol diff --git a/exercises/control/CMakeLists.txt b/exercises/control/CMakeLists.txt deleted file mode 100644 index a116cd8f..00000000 --- a/exercises/control/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -# Set up the project. -cmake_minimum_required( VERSION 3.12 ) -project( control LANGUAGES CXX ) - -# Set up the compilation environment. -include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) - -# Create the user's executable. -add_executable( control "control.cpp" ) - -# Create the "solution executable". -add_executable( control.sol EXCLUDE_FROM_ALL "solution/control.sol.cpp" ) -add_dependencies( solution control.sol ) diff --git a/exercises/control/Makefile b/exercises/control/Makefile deleted file mode 100644 index 356338ab..00000000 --- a/exercises/control/Makefile +++ /dev/null @@ -1,12 +0,0 @@ - -all: control -solution: control.sol - -clean: - rm -f *o *~ control control.sol - -control : control.cpp - $(CXX) --std=c++17 -g -Wall -Wextra -o $@ $^ - -control.sol: solution/control.sol.cpp - $(CXX) --std=c++17 -g -Wall -Wextra -o $@ $^ diff --git a/exercises/control/README.md b/exercises/control/README.md deleted file mode 100644 index cf327123..00000000 --- a/exercises/control/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# Instructions - -## Part 1 - -* Replace the C++98-style for loop with a range-based loop -* Replace the if / else statement with a conditional operator - -## Part 2 - -* Replace the for loop with a while loop -* Try it with a do / while loop - -## Part 3 - -* Replace the if / else statement with a switch statement diff --git a/exercises/control/control.cpp b/exercises/control/control.cpp deleted file mode 100644 index 574b9ed7..00000000 --- a/exercises/control/control.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include - -const unsigned int numbers[]{1000001, 1000002, 1000003, 1000004, 1000005, 1000006, 1000007, 1000008, 1000009}; - -bool isodd(unsigned int i) { return i % 2 == 1; } - -void part1() { - unsigned int sum_odd = 0; - unsigned int sum_eve = 0; - for (int i = 0; i < 9; ++i) { - unsigned int num = numbers[i]; - if (isodd(num)) { - sum_odd += num; - } else { - sum_eve += num; - } - } - std::cout << "Sums: odd = " << sum_odd << ", even = " << sum_eve << "\n"; -} - -void part2() { - // print smallest n for which 1 + 2 + ... + n > 10000 - int sum = 0; - for (int i = 1; ; i++) { - sum += i; - if (sum > 10000) { - std::cout << i << "\n"; - break; - } - } -} - -enum class Language { English, French, German, Italian, Other }; - -void part3(Language l) { - if (l == Language::English) { - std::cout << "Hello\n"; - } else if (l == Language::French) { - std::cout << "Salut\n"; - } else if (l == Language::German) { - std::cout << "Hallo\n"; - } else if (l == Language::Italian) { - std::cout << "Ciao\n"; - } else { - std::cout << "I don't speak your language\n"; - } -} - -int main() { - part1(); - part2(); - part3(Language::English); - return 0; -} diff --git a/exercises/control/solution/control.sol.cpp b/exercises/control/solution/control.sol.cpp deleted file mode 100644 index 2026389a..00000000 --- a/exercises/control/solution/control.sol.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include - -const unsigned int numbers[]{1000001, 1000002, 1000003, 1000004, 1000005, 1000006, 1000007, 1000008, 1000009}; - -bool isodd(unsigned int i) { return i % 2 == 1; } - -void part1() { - unsigned int sum_odd = 0; - unsigned int sum_eve = 0; - for (unsigned int num : numbers) { - // Note the usage of ternary expression to select the sum to which we add - // the ternary expression returns a reference to the right sum - (isodd(num) ? sum_odd : sum_eve) += num; - } - std::cout << "Sums: odd = " << sum_odd << ", even = " << sum_eve << "\n"; -} - -void part2() { - // print smallest n for which 1 + 2 + ... + n > 10000 - int sum = 0; - int i = 0; - while (sum <= 10000) { - ++i; - sum += i; - } - std::cout << i << "\n"; -} - -void part2bis() { - // print smallest n for which 1 + 2 + ... + n > 10000 - int sum = 0; - int i = 0; - do { - ++i; - sum += i; - } while (sum <= 10000); - std::cout << i << "\n"; -} - -enum class Language { English, French, German, Italian, Other }; - -void part3(Language l) { - switch (l) { - case Language::English: - std::cout << "Hello\n"; - break; - case Language::French: - std::cout << "Salut\n"; - break; - case Language::German: - std::cout << "Hallo\n"; - break; - case Language::Italian: - std::cout << "Ciao\n"; - break; - default: - std::cout << "Don't speak your language\n"; - } -} - -int main() { - part1(); - part2(); - part2bis(); - part3(Language::English); - return 0; -} diff --git a/exercises/cppcheck/.gitignore b/exercises/cppcheck/.gitignore deleted file mode 100644 index 634133d7..00000000 --- a/exercises/cppcheck/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -randomize -randomize.sol diff --git a/exercises/cppcheck/CMakeLists.txt b/exercises/cppcheck/CMakeLists.txt deleted file mode 100644 index f2419b3d..00000000 --- a/exercises/cppcheck/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -# Set up the project. -cmake_minimum_required( VERSION 3.12 ) -project( cppcheck LANGUAGES CXX ) - -# Set up the compilation environment. -include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) - -# Create the user's executable. -add_executable( cppcheck_randomize "randomize.cpp" ) - -# Create the "solution executable". -add_executable( cppcheck_randomize.sol EXCLUDE_FROM_ALL "solution/randomize.sol.cpp" ) -add_dependencies( solution cppcheck_randomize.sol ) diff --git a/exercises/cppcheck/Makefile b/exercises/cppcheck/Makefile deleted file mode 100644 index 152f7a68..00000000 --- a/exercises/cppcheck/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -all: randomize -solution: randomize.sol - -clean: - rm -f *o randomize *~ randomize.sol - -randomize : randomize.cpp - ${CXX} -std=c++17 -g -O0 -Wall -Wextra -L. -o $@ $< - -randomize.sol : solution/randomize.sol.cpp - ${CXX} -std=c++17 -g -O0 -Wall -Wextra -L. -o $@ $< diff --git a/exercises/cppcheck/README.md b/exercises/cppcheck/README.md deleted file mode 100644 index 98fe0d93..00000000 --- a/exercises/cppcheck/README.md +++ /dev/null @@ -1,8 +0,0 @@ - -## Instructions - -* compile, run, see that it works -* use valgrind : no issue -* use cppcheck, see the problem -* analyze the issue, and fix it -* bonus : understand why valgrind did not complain and how the standard deviation could be biased ( hint : use gdb and check addresses of v and diffs). diff --git a/exercises/cppcheck/randomize.cpp b/exercises/cppcheck/randomize.cpp deleted file mode 100644 index 3877c2fa..00000000 --- a/exercises/cppcheck/randomize.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include -#include -#include - -constexpr auto LEN = 1000; -constexpr auto STEP = 10; - -void swap(int *a, int*b) { - int c = *a; - *a = *b; - *b = c; -} - -void randomize(int* v, unsigned int len) { - std::default_random_engine e; - std::uniform_int_distribution d{0u, len}; - // we randomize via len random inversions - for (unsigned int i = 0; i < len; i++) { - int a = d(e); - int b = d(e); - swap(v+a, v+b); - } -} - -void fillVector(int* v, unsigned int len) { - for (unsigned int i = 0; i < len; i++) v[i] = i*STEP; -} - -int main() { - int v[LEN-1]; - // create and randomize vector - fillVector(v, LEN+1); - randomize(v, LEN+1); - - // compute diffs - int diffs[LEN]; - for (unsigned int i = 0; i < LEN; i++) - diffs[i] = v[i+1] - v[i]; - - // compute standard deviation of it - float sum = 0; - float sumsq = 0; - for (unsigned int i = 0; i < LEN; i ++) { - sum += diffs[i]; - sumsq += diffs[i]*diffs[i]; - } - float mean = sum/LEN; - float stddev = std::sqrt(sumsq/LEN - mean*mean) ; - std::cout << "Range = [0, " << STEP*LEN << "]\n" - << "Mean = " << mean - << "\nStdDev = " << stddev << '\n'; -} diff --git a/exercises/cppcheck/solution/randomize.sol.cpp b/exercises/cppcheck/solution/randomize.sol.cpp deleted file mode 100644 index 2b525dff..00000000 --- a/exercises/cppcheck/solution/randomize.sol.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include -#include -#include - -constexpr auto LEN = 1000; -constexpr auto STEP = 10; - -void swap(int *a, int*b) { - int c = *a; - *a = *b; - *b = c; -} - -void randomize(int* v, unsigned int len) { - std::default_random_engine e; - std::uniform_int_distribution d{0u, len}; - // we randomize via len random inversions - for (unsigned int i = 0; i < len; i++) { - int a = d(e); - int b = d(e); - swap(v+a, v+b); - } -} - -void fillVector(int* v, unsigned int len) { - for (unsigned int i = 0; i < len; i++) v[i] = i*STEP; -} - -int main() { - int v[LEN+1]; - // create and randomize vector - fillVector(v, LEN+1); - randomize(v, LEN+1); - - // compute diffs - int diffs[LEN]; - for (unsigned int i = 0; i < LEN; i++) - diffs[i] = v[i+1] - v[i]; - - // compute standard deviation of it - float sum = 0; - float sumsq = 0; - for (unsigned int i = 0; i < LEN; i ++) { - sum += diffs[i]; - sumsq += diffs[i]*diffs[i]; - } - float mean = sum/LEN; - float stddev = std::sqrt(sumsq/LEN - mean*mean) ; - std::cout << "Range = [0, " << STEP*LEN << "]\n" - << "Mean = " << mean - << "\nStdDev = " << stddev << '\n'; -} diff --git a/exercises/debug/.gitignore b/exercises/debug/.gitignore deleted file mode 100644 index 18ed3421..00000000 --- a/exercises/debug/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -debug -debug.sol diff --git a/exercises/debug/CMakeLists.txt b/exercises/debug/CMakeLists.txt deleted file mode 100644 index 2f7f0ac1..00000000 --- a/exercises/debug/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -# Set up the project. -cmake_minimum_required( VERSION 3.12 ) -project( debug LANGUAGES CXX ) - -# Set up the compilation environment. -include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) - -# Create the user's executable. -add_executable( debug "debug.cpp" ) - -# Create the "solution executable". -add_executable( debug.sol EXCLUDE_FROM_ALL "solution/debug.sol.cpp" ) -add_dependencies( solution debug.sol ) diff --git a/exercises/debug/Makefile b/exercises/debug/Makefile deleted file mode 100644 index d41fde73..00000000 --- a/exercises/debug/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -all: debug -solution: debug.sol - -clean: - rm -f *o debug *~ debug.sol core - -debug : debug.cpp - ${CXX} -std=c++17 -g -O0 -Wall -Wextra -L. -o $@ $< - -debug.sol : solution/debug.sol.cpp - ${CXX} -std=c++17 -g -O0 -Wall -Wextra -L. -o $@ $< diff --git a/exercises/debug/README.md b/exercises/debug/README.md deleted file mode 100644 index 4fec057a..00000000 --- a/exercises/debug/README.md +++ /dev/null @@ -1,28 +0,0 @@ -## Instructions for the "debug" exercise - -* compile, run, see the crash -* run it in gdb -* inspect backtrace, variables to understand the problem -* try stepping through the code using 'step' and 'next', use breakpoints and continue to get familiar with gdb -* fix the bug - -### Some useful gdb commands - -| Command | Effect | -|---------------------------|---------------------------------------------------------------| -| `gdb ./randomize` | launch the debugger with the given executable | -| `gdb --tui ./randomize` | same as above, but with terminal user interface enabled | -| `tui enable` | enabled the terminal user interface | -| `run` | runs the program | -| `bt, backtrace` | show a backtrace (list of stack frames) of the current thread | -| `up` | navigate one stack frame up | -| `down` | navigate one stack frame down | -| `s, step` | execute current line, stop at earliest next occasion | -| `n, next` | continue until next line or function exits | -| `c, continue` | continue execution | -| `print ` | show current value of variable | -| `info locals` | show the values of all local variables | -| `info args` | show the values of all function arguments | -| `br ` | put a breakpoint at line | -| `info br`: | list active breakpoints | -| `enable/disable/delete #` | enable/disable/delete breakpoints | diff --git a/exercises/debug/debug.cpp b/exercises/debug/debug.cpp deleted file mode 100644 index a09da9de..00000000 --- a/exercises/debug/debug.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include - -void swap(int* a, int* b) -{ - int c = *a; - *a = *b; - *b = c; -} - -void reverse(int* v, unsigned int len) -{ - for (unsigned int i = 0; i < (len + 1) / 2; i++) { - const int a = i; - const int b = len - 1 - i; - - swap(v + a, v + b); - } -} - -int* createAndFillVector(unsigned int len) -{ - auto v = new int[len]; - for (unsigned int i = 0; i < len; i++) { - v[i] = i; - } - return v; -} - -int main() -{ - constexpr auto arraySize = 100; - int* v = nullptr; - // create and reverse the vector of LEN numbers - reverse(v, 1000); - v = createAndFillVector(arraySize); - - // check if the revert worked: - const bool isReversed = std::is_sorted(v, v + arraySize, std::greater {}); - std::cout << "Vector reversed successfully: " << std::boolalpha - << isReversed << "\n"; - - return isReversed ? 0 : 1; -} diff --git a/exercises/debug/solution/debug.sol.cpp b/exercises/debug/solution/debug.sol.cpp deleted file mode 100644 index 5676e620..00000000 --- a/exercises/debug/solution/debug.sol.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include - -void swap(int* a, int* b) -{ - int c = *a; - *a = *b; - *b = c; -} - -void reverse(int* v, unsigned int len) -{ - for (unsigned int i = 0; i < (len + 1) / 2; i++) { - const int a = i; - const int b = len - 1 - i; - - swap(v + a, v + b); - } -} - -int* createAndFillVector(unsigned int len) -{ - auto v = new int[len]; - for (unsigned int i = 0; i < len; i++) { - v[i] = i; - } - return v; -} - -int main() -{ - constexpr auto arraySize = 100; - int* v = nullptr; - // create and reverse the vector of LEN numbers - v = createAndFillVector(arraySize); - reverse(v, arraySize); - - // check if the revert worked: - const bool isReversed = std::is_sorted(v, v + arraySize, std::greater {}); - std::cout << "Vector reversed successfully: " << std::boolalpha - << isReversed << "\n"; - - delete[] v; - - return isReversed ? 0 : 1; -} diff --git a/exercises/functions/.gitignore b/exercises/functions/.gitignore deleted file mode 100644 index ab406cf6..00000000 --- a/exercises/functions/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -functions -functions.sol diff --git a/exercises/functions/CMakeLists.txt b/exercises/functions/CMakeLists.txt deleted file mode 100644 index 2aa7260e..00000000 --- a/exercises/functions/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -# Set up the project. -cmake_minimum_required( VERSION 3.12 ) -project( functions LANGUAGES CXX ) - -# Set up the compilation environment. -include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) - -# Create the user's executable. -add_executable( functions "Structs.h" "Structs.cpp" "functions.cpp" ) - -# Create the "solution executable". -add_executable( functions.sol EXCLUDE_FROM_ALL "Structs.h" "Structs.cpp" "solution/functions.sol.cpp" ) -target_include_directories(functions.sol PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") -add_dependencies( solution functions.sol ) - -if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC" ) - target_compile_definitions( functions PRIVATE _CRT_SECURE_NO_WARNINGS ) - target_compile_definitions( functions.sol PRIVATE _CRT_SECURE_NO_WARNINGS ) -endif() diff --git a/exercises/functions/Makefile b/exercises/functions/Makefile deleted file mode 100644 index 6bc249ed..00000000 --- a/exercises/functions/Makefile +++ /dev/null @@ -1,15 +0,0 @@ - -all: functions -solution: functions.sol - -clean: - rm -f *o *~ functions functions.sol - -%.o: %.cpp %.h - ${CXX} -std=c++17 -Wall -Wextra -c -o $@ $< - -functions : functions.cpp Structs.o - ${CXX} -std=c++17 -Wall -Wextra -o $@ $^ - -functions.sol : solution/functions.sol.cpp Structs.o - ${CXX} -I. -std=c++17 -Wall -Wextra -o $@ $^ diff --git a/exercises/functions/README.md b/exercises/functions/README.md deleted file mode 100644 index 17fd9784..00000000 --- a/exercises/functions/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# Functions and how arguments are passed in C++ - -Here, we will look a bit into how arguments are passed into functions. -You will find an example where everything is passed by value (by copy), but there is a struct that is slow to copy. -We will try to work with it without copying it. - -# Instructions - -## Step 1 - -Check out `functions.cpp`, compile it (`make`) and run the program. -Check out `Structs.h`. It defines two structs that we will work with : `FastToCopy` and `SlowToCopy`. -They are exactly what their name says, so let's try to avoid copying the latter. - -## Step 2 - -Using `printName()` as an example, write a function that prints the name of `SlowToCopy`. Call it in `main()`. - -## Step 3 - -Try passing by copy and passing by reference, see the difference. - -## Step 4 - -When passing by reference, ensure that your `printName` cannot inadvertently modify the original object. -To test its const correctness, try adding something like `argument.name = "a";` to your print function. -Try both with and without const attributes in your print function's signature. diff --git a/exercises/functions/Structs.cpp b/exercises/functions/Structs.cpp deleted file mode 100644 index 4f24a9d3..00000000 --- a/exercises/functions/Structs.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "Structs.h" - -#include -#include -#include -#include - -/// Construct a new instance of SlowToCopy. -SlowToCopy::SlowToCopy() : name("SlowToCopy") {} - -/// Construct a new instance of SlowToCopy. -SlowToCopy::SlowToCopy(const std::string& name) : name(name) {} - -/// Construct a new instance of SlowToCopy, copying the data from 'other'. -SlowToCopy::SlowToCopy(const SlowToCopy& other) { - std::cout << __func__ << ": Please don't copy me. This is slow.\n"; - std::this_thread::sleep_for(std::chrono::seconds(3)); - name = other.name; -} diff --git a/exercises/functions/Structs.h b/exercises/functions/Structs.h deleted file mode 100644 index 2497855d..00000000 --- a/exercises/functions/Structs.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include - -struct FastToCopy { - std::string name; -}; - -struct SlowToCopy { - std::string name; - - // Functions to create and copy this struct. - // We go into details on the next days. - SlowToCopy(); - SlowToCopy(const std::string& name); - SlowToCopy(const SlowToCopy& other); -}; diff --git a/exercises/functions/functions.cpp b/exercises/functions/functions.cpp deleted file mode 100644 index c532bcb6..00000000 --- a/exercises/functions/functions.cpp +++ /dev/null @@ -1,33 +0,0 @@ - -/* Tasks: - * 1. Check out Structs.h. It defines two structs that we will work with. - * FastToCopy - * SlowToCopy - * They are exactly what their name says, so let's try to avoid copying the latter. - * 2. Using "printName()" as an example, write a function that prints the name of "SlowToCopy". - * Call it in main(). - * 3. Try passing by copy and passing by reference, see the difference. - * 4. When passing by reference, ensure that your "printName" cannot inadvertently modify the original object. - * To test its const correctness, try adding something like - * argument.name = "other name"; - * to your print function. - * Try both with and without const attributes in your print function's signature. - */ - -#include "Structs.h" // The data structs we will work with - -#include // For printing - -void printName(FastToCopy argument) { - std::cout << argument.name << '\n'; -} - -int main() { - FastToCopy fast = {"Fast"}; - printName(fast); - - SlowToCopy slow = {"Slow"}; - // print it here - - return 0; -} diff --git a/exercises/functions/solution/functions.sol.cpp b/exercises/functions/solution/functions.sol.cpp deleted file mode 100644 index 543e8c0c..00000000 --- a/exercises/functions/solution/functions.sol.cpp +++ /dev/null @@ -1,50 +0,0 @@ - -/* Tasks: - * 1. Check out Structs.h. It defines two structs that we will work with. - * FastToCopy - * SlowToCopy - * They are exactly what their name says, so let's try to avoid copying the latter. - * 2. Using "printName()" as an example, write a function that prints the name of "SlowToCopy". - * Call it in main(). - * 3. Try passing by copy and passing by reference, see the difference. - * 4. When passing by reference, ensure that your "printName" cannot inadvertently modify the original object. - * To test its const correctness, try adding something like - * argument.name = "other name"; - * to your print function. - * Try both with and without const attributes in your print function's signature. - */ - -#include "Structs.h" // The data structs we will work with - -#include // For printing - -void printName(FastToCopy argument) { - std::cout << argument.name << '\n'; -} - -void inefficientPrintName(SlowToCopy argument) { - std::cout << argument.name << '\n'; - - // We can change the argument's name because it's a copy: - argument.name = "New name"; -} - -void printName(const SlowToCopy & argument) { - std::cout << argument.name << '\n'; - - // We are unable to change name, as we should: - //argument.name = '\n'; -} - -int main() { - FastToCopy fast = {"Fast"}; - printName(fast); - - SlowToCopy slow = {"Slow"}; - printName(slow); - - std::cout << "Now printing with copy:\n"; - inefficientPrintName(slow); - - return 0; -} diff --git a/exercises/header_units/.gitignore b/exercises/header_units/.gitignore deleted file mode 100644 index 10be76d2..00000000 --- a/exercises/header_units/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -header_units -header_units.sol -gcm.cache diff --git a/exercises/header_units/Complex.hpp b/exercises/header_units/Complex.hpp deleted file mode 100644 index 07443d64..00000000 --- a/exercises/header_units/Complex.hpp +++ /dev/null @@ -1,110 +0,0 @@ -#include -#include - -template -class Complex_t { -public: - Complex_t() = default; - Complex_t(T r, T i) : m_r(r), m_i(i) {} - - T real() const { return m_r; } - T imaginary() const { return m_i; } - - T norm_sqr() const { - return m_r * m_r + m_i * m_i; - } - - T norm() const { - return std::sqrt(norm_sqr()); - } - - Complex_t& operator+=(const Complex_t& other) { - m_r += other.m_r; - m_i += other.m_i; - return *this; - } - - Complex_t& operator-=(const Complex_t& other) { - m_r -= other.m_r; - m_i -= other.m_i; - return *this; - } - - Complex_t& operator*=(const Complex_t& other) { - const auto r = m_r * other.m_r - m_i * other.m_i; - const auto i = m_r * other.m_i + m_i * other.m_r; - m_r = r; - m_i = i; - return *this; - } - - Complex_t& operator*=(T factor) { - m_r *= factor; - m_i *= factor; - return *this; - } - - Complex_t& operator/=(const Complex_t& other) { - const T ns = other.norm_sqr(); - const auto r = (m_r * other.m_r + m_i * other.m_i) / ns; - const auto i = (m_i * other.m_r - m_r * other.m_i) / ns; - m_r = r; - m_i = i; - return *this; - } - - Complex_t& operator/=(T divisor) { - m_r /= divisor; - m_i /= divisor; - return *this; - } - - friend Complex_t operator+(Complex_t a, const Complex_t& b) { - return a += b; - } - - friend Complex_t operator-(Complex_t a, const Complex_t& b) { - return a -= b; - } - - friend Complex_t operator*(Complex_t a, const Complex_t& b) { - return a *= b; - } - - friend Complex_t operator*(Complex_t c, T factor) { - return c *= factor; - } - - friend Complex_t operator*(T factor, Complex_t c) { - return c *= factor; - } - - friend Complex_t operator/(Complex_t a, Complex_t b) { - return a /= b; - } - - friend Complex_t operator/(Complex_t c, T divisor) { - return c /= divisor; - } - - friend Complex_t operator/(T dividend, const Complex_t& c) { - return Complex_t(dividend, 0) / c; - } - - friend bool operator==(const Complex_t& a, const Complex_t& b) { - return a.m_r == b.m_r && a.m_i == b.m_i; - } - - friend bool operator<(const Complex_t& a, const Complex_t& b) { - return a.norm_sqr() < b.norm_sqr(); - } - - friend std::ostream& operator<<(std::ostream& os, const Complex_t& c) { - return os << "(" << c.real() << ", " << c.imaginary() << ")"; - } - -private: - T m_r{}, m_i{}; -}; - -using Complex = Complex_t<>; diff --git a/exercises/header_units/Makefile b/exercises/header_units/Makefile deleted file mode 100644 index 772ae6a7..00000000 --- a/exercises/header_units/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -all: header_units -solution: header_units.sol - -clean: - rm -rf *.o header_units gcm.cache solution/header_units solution/*.o solution/gcm.cache - -main.o: main.cpp Complex.hpp - ${CXX} -std=c++20 -fmodules-ts -g -O0 -Wall -Wextra -o $@ -c $< - -header_units : main.o - ${CXX} -std=c++20 -fmodules-ts -g -O0 -Wall -Wextra -o $@ $^ - -header_units.sol: - $(MAKE) -C solution header_units diff --git a/exercises/header_units/README.md b/exercises/header_units/README.md deleted file mode 100644 index 6701f3cb..00000000 --- a/exercises/header_units/README.md +++ /dev/null @@ -1,9 +0,0 @@ - -## Instructions - -* convert the `#include "Complex.hpp"` to a header unit import - * you will need to edit the Makefile and add a new target to precompile `Complex.hpp` -* convert the standard library includes in `randomize.cpp` to header unit imports - * you will need to precompile the standard library headers in your Makefile - * with g++-11 and g++-12 you cannot yet precompile `` and ``, so keep those as a regular includes -* below g++-12 you will get a linker error when building incrementally, so run `make clean` before each build diff --git a/exercises/header_units/main.cpp b/exercises/header_units/main.cpp deleted file mode 100644 index b0beddda..00000000 --- a/exercises/header_units/main.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include -#include -#include -#include -#include "Complex.hpp" - -// The code below here should not need to change !! - -template -void compute(int len, T initial, T step) { - // allocate vectors - std::vector v(len+1), diffs(len+1); - - // fill and randomize v - std::generate(v.begin(), v.end(), [value = initial, step]() mutable { - const T cur = value; - value += step; - return cur; - }); - std::shuffle(v.begin(), v.end(), std::default_random_engine{}); - - // compute differences - std::adjacent_difference(v.begin(), v.end(), diffs.begin()); - - // compute standard deviation of it - const T sum = std::reduce(diffs.begin()+1, diffs.end()); - const T sumsq = std::accumulate(diffs.begin()+1, diffs.end(), T(), - [](const T& s, const T& a) { return s + a * a; }); - const T mean = sum/len; - const T variance = sumsq/len - mean*mean; - - std::cout << "Range = [" << initial << ", " << step*len << "]\n" - << "Mean = " << mean << '\n' - << "Variance = " << variance << '\n'; -} - -int main() { - compute(1000, 0.0, 7.0); - compute(1000, Complex(0,0), Complex(1,2)); -} diff --git a/exercises/header_units/solution/Makefile b/exercises/header_units/solution/Makefile deleted file mode 100644 index 2450908a..00000000 --- a/exercises/header_units/solution/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -all: header_units - -clean: - rm -rf *.o header_units gcm.cache - -algorithm numeric random vector: - ${CXX} -std=c++20 -fmodules-ts -x c++-system-header $@ - -Complex_header_unit: ../Complex.hpp - ${CXX} -std=c++20 -g -O0 -Wall -Wextra -fmodules-ts -x c++-header $< - -main.o: main.cpp Complex_header_unit algorithm numeric random vector - ${CXX} -std=c++20 -fmodules-ts -g -O0 -Wall -Wextra -o $@ -c $< - -header_units: main.o - ${CXX} -std=c++20 -fmodules-ts -g -O0 -Wall -Wextra -o $@ $^ diff --git a/exercises/header_units/solution/main.cpp b/exercises/header_units/solution/main.cpp deleted file mode 100644 index 55110c9f..00000000 --- a/exercises/header_units/solution/main.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include -import ; -import ; -import ; -import ; -import "../Complex.hpp"; - -template -void compute(int len, T initial, T step) { - // allocate vectors - std::vector v(len+1), diffs(len+1); - - // fill and randomize v - std::generate(v.begin(), v.end(), [value = initial, step]() mutable { - const T cur = value; - value += step; - return cur; - }); - std::shuffle(v.begin(), v.end(), std::default_random_engine{}); - - // compute differences - std::adjacent_difference(v.begin(), v.end(), diffs.begin()); - - // compute standard deviation of it - const T sum = std::reduce(diffs.begin()+1, diffs.end()); - const T sumsq = std::accumulate(diffs.begin()+1, diffs.end(), T(), - [](const T& s, const T& a) { return s + a * a; }); - const T mean = sum/len; - const T variance = sumsq/len - mean*mean; - - std::cout << "Range = [" << initial << ", " << step*len << "]\n" - << "Mean = " << mean << '\n' - << "Variance = " << variance << '\n'; -} - -int main() { - compute(1000, 0.0, 7.0); - compute(1000, Complex(0,0), Complex(1,2)); -} diff --git a/exercises/helgrind/.gitignore b/exercises/helgrind/.gitignore deleted file mode 100644 index c0308138..00000000 --- a/exercises/helgrind/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -fiboMT -fiboMT.sol diff --git a/exercises/helgrind/CMakeLists.txt b/exercises/helgrind/CMakeLists.txt deleted file mode 100644 index 461d8724..00000000 --- a/exercises/helgrind/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -# Set up the project. -cmake_minimum_required( VERSION 3.12 ) -project( helgrind LANGUAGES CXX ) - -# Set up the compilation environment. -include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) - -# Figure out how to use the platform's thread capabilities. -find_package( Threads REQUIRED ) - -# Create the user's executable. -add_executable( fiboMT "fiboMT.cpp" ) -target_link_libraries( fiboMT PRIVATE Threads::Threads ) - -# Create the "solution executable". -add_executable( fiboMT.sol EXCLUDE_FROM_ALL "solution/fiboMT.sol.cpp" ) -target_link_libraries( fiboMT.sol PRIVATE Threads::Threads ) -add_dependencies( solution fiboMT.sol ) diff --git a/exercises/helgrind/Makefile b/exercises/helgrind/Makefile deleted file mode 100644 index 46b67a51..00000000 --- a/exercises/helgrind/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -all: fiboMT -solution: fiboMT.sol - -clean: - rm -f *o fiboMT *~ fiboMT.sol core - -fiboMT : fiboMT.cpp - ${CXX} -std=c++17 -g -O0 -Wall -Wextra -o $@ $< - -fiboMT.sol : solution/fiboMT.sol.cpp - ${CXX} -std=c++17 -g -O0 -Wall -Wextra -o $@ $< diff --git a/exercises/helgrind/README.md b/exercises/helgrind/README.md deleted file mode 100644 index 408ae6ba..00000000 --- a/exercises/helgrind/README.md +++ /dev/null @@ -1,7 +0,0 @@ - -## Instructions - -* compile, run -* check it with valgrind. You may see strange behavior but it may be perfectly fine. -* check it with valgrind --tool=helgrind -* understand issue and fix diff --git a/exercises/helgrind/fiboMT.cpp b/exercises/helgrind/fiboMT.cpp deleted file mode 100644 index 965c80ed..00000000 --- a/exercises/helgrind/fiboMT.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include -#include -#include -#include -#include -#include - -constexpr auto NBITERATIONS = 5; -constexpr auto MIN = 22; -constexpr auto MAX = 25; - -struct WorkToDo { - char* title; - int a; -}; - -unsigned int fibo(unsigned a) { - if (a == 1 || a == 0) { - return 1; - } else { - return fibo(a-1)+fibo(a-2); - } -} - -void computation(WorkToDo* work, unsigned long* result) { - *result = fibo(work->a); - std::free(work->title); - work->title = nullptr; -} - -void launchFibo(const char* title, int a) { - WorkToDo w; - w.title = strdup(title); - w.a = a; - unsigned long result; - std::thread t{computation, &w, &result}; - std::this_thread::sleep_for(std::chrono::microseconds{1}); - std::cout << "Computing " << w.title << '\n'; - t.join(); - std::cout << title << " = " << (unsigned long)result << '\n'; -} - -int main() { - std::default_random_engine e; - std::uniform_int_distribution d{MIN, MAX}; - for (unsigned int i = 0; i < NBITERATIONS; i++) { - unsigned int a = d(e); - std::stringstream ss; - ss << "Fibo(" << a << ")"; - launchFibo(ss.str().c_str(), a); - } -} diff --git a/exercises/helgrind/solution/fiboMT.sol.cpp b/exercises/helgrind/solution/fiboMT.sol.cpp deleted file mode 100644 index 3ea9299b..00000000 --- a/exercises/helgrind/solution/fiboMT.sol.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include -#include -#include -#include -#include -#include - -constexpr auto NBITERATIONS = 5; -constexpr auto MIN = 22; -constexpr auto MAX = 25; - -struct WorkToDo { - char* title; - int a; -}; - -unsigned int fibo(unsigned a) { - if (a == 1 || a == 0) { - return 1; - } else { - return fibo(a-1)+fibo(a-2); - } -} - -void computation(WorkToDo* work, unsigned long* result) { - *result = fibo(work->a); -} - -void launchFibo(const char* title, int a) { - WorkToDo w; - w.title = strdup(title); - w.a = a; - unsigned long result; - std::thread t{computation, &w, &result}; - std::this_thread::sleep_for(std::chrono::microseconds{1}); - std::cout << "Computing " << w.title << '\n'; - std::free(w.title); - w.title = nullptr; - t.join(); - std::cout << title << " = " << (unsigned long)result << '\n'; -} - -int main() { - std::default_random_engine e; - std::uniform_int_distribution d{MIN, MAX}; - for (unsigned int i = 0; i < NBITERATIONS; i++) { - unsigned int a = d(e); - std::stringstream ss; - ss << "Fibo(" << a << ")"; - launchFibo(ss.str().c_str(), a); - } -} diff --git a/exercises/hello/.gitignore b/exercises/hello/.gitignore deleted file mode 100644 index ce013625..00000000 --- a/exercises/hello/.gitignore +++ /dev/null @@ -1 +0,0 @@ -hello diff --git a/exercises/hello/CMakeLists.txt b/exercises/hello/CMakeLists.txt deleted file mode 100644 index b98a07c7..00000000 --- a/exercises/hello/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -# Set up the project. -cmake_minimum_required( VERSION 3.12 ) -project( hello LANGUAGES CXX ) - -# Set up the compilation environment. -include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) -set(CMAKE_CXX_STANDARD 20) - -# Set up the library. -add_library( helloLib "hello.hpp" "hello.cpp" ) -set_target_properties( helloLib PROPERTIES OUTPUT_NAME "hello" ) - -# Set up the executable. -add_executable( hello "main.cpp" ) -target_link_libraries( hello PRIVATE helloLib ) diff --git a/exercises/hello/Makefile b/exercises/hello/Makefile deleted file mode 100644 index 22777399..00000000 --- a/exercises/hello/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -all: libhello.a hello - -solution: all - -clean: - rm -f *.o *.a *.so hello *~ callgrind.out.* - -hello.o: hello.cpp hello.hpp - $(CXX) --std=c++20 -c -g -Wall -Wextra -o $@ $< - -libhello.a: hello.o - ar rcs $@ $< - -hello : main.cpp libhello.a - $(CXX) --std=c++20 -g -Wall -Wextra -o $@ $^ diff --git a/exercises/hello/README.md b/exercises/hello/README.md deleted file mode 100644 index 7388913b..00000000 --- a/exercises/hello/README.md +++ /dev/null @@ -1,36 +0,0 @@ - -# Hello World ! - -This example should help to check that your machine is well installed. - -## make vs cmake - -On any linux like system, provided you have a "recent enough" g++, this should work out of the box: -``` -make -./hello -``` - -On native Windows, build with `cmake`: -``` -mkdir build -cd build -cmake .. -cmake --build . -Debug/hello.exe -``` - -## valgrind & callgrind & graphical tools - -Try: -``` -valgrind --tool=callgrind ./hello -kcachegrind -``` - -## cppcheck - -Try: -``` -cppcheck *.hpp *.cpp -``` diff --git a/exercises/hello/hello.cpp b/exercises/hello/hello.cpp deleted file mode 100644 index 3eaade18..00000000 --- a/exercises/hello/hello.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "hello.hpp" - -#include -#include -#include - -void printHello(int i) { - std::cout << "Hello, world " << i << '\n'; -} - -void checkCpp20() { - std::array worldHellos{"Bonjour", "Ciao", "Guten Tag", "Hello"}; - for (int i=0; auto const& hello : worldHellos) { - i++; - std::cout << "(" << i << ") " << hello << "\n"; - } -} diff --git a/exercises/hello/hello.hpp b/exercises/hello/hello.hpp deleted file mode 100644 index 5ca9274a..00000000 --- a/exercises/hello/hello.hpp +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -void printHello(int i); -void checkCpp20(); diff --git a/exercises/hello/main.cpp b/exercises/hello/main.cpp deleted file mode 100644 index b17f2bbc..00000000 --- a/exercises/hello/main.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "hello.hpp" - -int main() { - int n = 3; - for (int i = 0; i < n; i++) { - printHello(i); - } - checkCpp20(); - return 0; -} diff --git a/exercises/loopsRefsAuto/.gitignore b/exercises/loopsRefsAuto/.gitignore deleted file mode 100644 index e757cd3a..00000000 --- a/exercises/loopsRefsAuto/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -loopsRefsAuto -loopsRefsAuto.sol diff --git a/exercises/loopsRefsAuto/CMakeLists.txt b/exercises/loopsRefsAuto/CMakeLists.txt deleted file mode 100644 index 4eb6ad93..00000000 --- a/exercises/loopsRefsAuto/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -# Set up the project. -cmake_minimum_required( VERSION 3.12 ) -project( loopsRefsAuto LANGUAGES CXX ) - -# Set up the compilation environment. -include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) - -# Create the user's executable. -add_executable( loopsRefsAuto "loopsRefsAuto.cpp" ) - -# Create the "solution executable". -add_executable( loopsRefsAuto.sol EXCLUDE_FROM_ALL "solution/loopsRefsAuto.sol.cpp" ) -add_dependencies( solution loopsRefsAuto.sol ) diff --git a/exercises/loopsRefsAuto/Makefile b/exercises/loopsRefsAuto/Makefile deleted file mode 100644 index 322609f1..00000000 --- a/exercises/loopsRefsAuto/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -all: loopsRefsAuto -solution: loopsRefsAuto.sol - -clean: - rm -f *o *~ loopsRefsAuto loopsRefsAuto.sol - -%.o: %.cpp %.h - ${CXX} -std=c++17 -Wall -Wextra -c -o $@ $< - -loopsRefsAuto : loopsRefsAuto.cpp - ${CXX} -std=c++17 -Wall -Wextra -o $@ $^ - -loopsRefsAuto.sol : solution/loopsRefsAuto.sol.cpp - ${CXX} -std=c++17 -Wall -Wextra -o $@ $^ diff --git a/exercises/loopsRefsAuto/README.md b/exercises/loopsRefsAuto/README.md deleted file mode 100644 index 2587f7f7..00000000 --- a/exercises/loopsRefsAuto/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Exercise about for loops, references and the `auto` keyword. - -Here, we are playing with a struct that doesn't like to be copied. Imagine that this is some large data -that is expensive to copy. We will learn how to work with an array of such data without copying it. - -## Instructions: -- Open `loopsRefsAuto.cpp`, and familiarise yourself with what happens in `main()`. -- Compile (`make`) and run the program. -- In the source file, you will find further tasks. diff --git a/exercises/loopsRefsAuto/loopsRefsAuto.cpp b/exercises/loopsRefsAuto/loopsRefsAuto.cpp deleted file mode 100644 index 0cb63fa4..00000000 --- a/exercises/loopsRefsAuto/loopsRefsAuto.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include - -struct DontCopyMe { - int resultA; - int resultB; - - // This is material for the second day: - DontCopyMe() = default; - DontCopyMe(const DontCopyMe& other) : - resultA(other.resultA), - resultB(other.resultB) - { std::cout << "Please don't copy me\n"; } -}; - -int main() { - // We create an array of DontCopyMe structs: - DontCopyMe collection[10]; - - // Task 1: - // Write a for loop that initialises resultA and resultB for each element in the above array - // with sensible numbers. - // Verify the output of the program before and after you do this. - - - // Task 2: - // We use a range-based for loop to analyse the array of structs. - // The problem is: we are copying every DontCopyMe ... - // Fix this loop using references. - // Hint: Fix the type declaration "auto" in the loop head. - int resultA = 0; - int resultB = 0; - for (auto item : collection) { - resultA += item.resultA; - resultB += item.resultB; - } - std::cout << "resultA = " << resultA << "\tresultB = " << resultB << "\n"; - - return 0; -} - -// Task 3: -// Think about which loop needs write access to the DontCopyMe. -// Make sure that all references that don't need write access are const. -// Hint: C++ understands "auto const". diff --git a/exercises/loopsRefsAuto/solution/loopsRefsAuto.sol.cpp b/exercises/loopsRefsAuto/solution/loopsRefsAuto.sol.cpp deleted file mode 100644 index b248f843..00000000 --- a/exercises/loopsRefsAuto/solution/loopsRefsAuto.sol.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include - -struct DontCopyMe { - int resultA; - int resultB; - - // This is material for the second day: - DontCopyMe() = default; - DontCopyMe(const DontCopyMe& other) : - resultA(other.resultA), - resultB(other.resultB) - { std::cout << "Please don't copy me\n"; } -}; - -int main() { - // We create an array of DontCopyMe structs: - DontCopyMe collection[10]; - - // Task 1: - // Write a for loop that initialises resultA and resultB for each element in the above array - // with sensible numbers. - // Verify the output of the program before and after you do this. - - for ( int i = 0 ; i<10 ; ++i ) { - collection[i].resultA = i; - collection[i].resultB = 2*i; - } - - // Task 2: - // We use a range-based for loop to analyse the array of structs. - // The problem is: we are copying every DontCopyMe ... - // Fix this loop using references. - // Hint: Fix the type declaration "auto" in the loop head. - int resultA = 0; - int resultB = 0; - for (auto const & item : collection) { - resultA += item.resultA; - resultB += item.resultB; - } - std::cout << "resultA = " << resultA << "\tresultB = " << resultB << "\n"; - - return 0; -} - -// Task 3: -// Think about which loop needs write access to the DontCopyMe. -// Make sure that all references that don't need write access are const. -// Hint: C++ understands "auto const". diff --git a/exercises/memcheck/.gitignore b/exercises/memcheck/.gitignore deleted file mode 100644 index b543e843..00000000 --- a/exercises/memcheck/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -memleak -memleak.sol diff --git a/exercises/memcheck/CMakeLists.txt b/exercises/memcheck/CMakeLists.txt deleted file mode 100644 index 0be30f7d..00000000 --- a/exercises/memcheck/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -# Set up the project. -cmake_minimum_required( VERSION 3.12 ) -project( memcheck LANGUAGES CXX ) - -# Set up the compilation environment. -include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) - -# Create the user's library. -add_library( memcheckPoly "Polygons.hpp" "Polygons.cpp" ) -set_target_properties( memcheckPoly PROPERTIES OUTPUT_NAME "poly" ) -if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC" ) - target_compile_definitions( memcheckPoly PRIVATE _USE_MATH_DEFINES ) -endif() - -# Create the user's executable. -add_executable( memleak "memleak.cpp" ) -target_link_libraries( memleak PRIVATE memcheckPoly ) - -# Create the "solution library". -add_library( memcheckPolySol EXCLUDE_FROM_ALL "solution/Polygons.sol.hpp" "solution/Polygons.sol.cpp" ) -set_target_properties( memcheckPolySol PROPERTIES OUTPUT_NAME "polysol" ) -if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC" ) - target_compile_definitions( memcheckPolySol PRIVATE _USE_MATH_DEFINES ) -endif() - -# Create the "solution executable". -add_executable( memleak.sol EXCLUDE_FROM_ALL "solution/memleak.sol.cpp" ) -target_link_libraries( memleak.sol PRIVATE memcheckPolySol ) -add_dependencies( solution memleak.sol ) diff --git a/exercises/memcheck/Makefile b/exercises/memcheck/Makefile deleted file mode 100644 index 3a5ebccc..00000000 --- a/exercises/memcheck/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -all: libpoly.so memleak -solution: libpolysol.so memleak.sol - -clean: - rm -f *o *so memleak *~ memleak.sol vgcore* - -libpoly.so: Polygons.cpp Polygons.hpp - $(CXX) -g -Wall -Wextra -shared -fPIC -o $@ $< - -memleak : memleak.cpp libpoly.so - $(CXX) -g -Wall -Wextra -o $@ $^ - -libpolysol.so: solution/Polygons.sol.cpp solution/Polygons.sol.hpp - $(CXX) -g -Wall -Wextra -shared -fPIC -o $@ $< - -memleak.sol : solution/memleak.sol.cpp libpolysol.so - $(CXX) -g -Wall -Wextra -o $@ $^ diff --git a/exercises/memcheck/Polygons.cpp b/exercises/memcheck/Polygons.cpp deleted file mode 100644 index 039e4866..00000000 --- a/exercises/memcheck/Polygons.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "Polygons.hpp" -#include -#include -#include -#include - -Polygon::Polygon(int n, float radius) : m_nbSides(n), m_radius(radius) {}; - -float Polygon::computePerimeter() { - std::cout << "Generic computePerimeter for polygons\n"; - return 2*m_nbSides*std::sin(static_cast(M_PI)/m_nbSides)*m_radius; -} - -Hexagon::Hexagon(char* name, float radius) : Polygon(6, radius) { - m_name = strdup(name); -} - -Hexagon::~Hexagon() { - free(m_name); - m_name = 0; -} diff --git a/exercises/memcheck/Polygons.hpp b/exercises/memcheck/Polygons.hpp deleted file mode 100644 index c36985b8..00000000 --- a/exercises/memcheck/Polygons.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -class Polygon { -public: - Polygon(int n, float radius); - ~Polygon(){}; - float computePerimeter(); -protected: - int m_nbSides; - float m_radius; -}; - -class Hexagon : public Polygon { -public: - Hexagon(char* name, float radius); - Hexagon(const Hexagon&) = delete; - Hexagon& operator=(const Hexagon&) = delete; - ~Hexagon(); - char* name() const {return m_name;}; -private: - char* m_name; -}; diff --git a/exercises/memcheck/README.md b/exercises/memcheck/README.md deleted file mode 100644 index e69de29b..00000000 diff --git a/exercises/memcheck/memleak.cpp b/exercises/memcheck/memleak.cpp deleted file mode 100644 index 87f08932..00000000 --- a/exercises/memcheck/memleak.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "Polygons.hpp" -#include - -Polygon* getHexa(char* name, float radius) { - return new Hexagon(name, radius); -} - -int main() { - // create an Hexagon, call its perimeter method - Polygon *hexa = getHexa((char*)"hexa", 1.0); - std::cout << "Hexa : perimeter = " << hexa->computePerimeter() << "\n\n"; - - // memory deallocation - delete hexa; -} diff --git a/exercises/memcheck/solution/Polygons.sol.cpp b/exercises/memcheck/solution/Polygons.sol.cpp deleted file mode 100644 index f216ba8b..00000000 --- a/exercises/memcheck/solution/Polygons.sol.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "Polygons.sol.hpp" -#include -#include -#include -#include - -Polygon::Polygon(int n, float radius) : m_nbSides(n), m_radius(radius) {}; - -float Polygon::computePerimeter() { - std::cout << "Generic computePerimeter for polygons\n"; - return 2*m_nbSides*std::sin(static_cast(M_PI)/m_nbSides)*m_radius; -} - -Hexagon::Hexagon(char* name, float radius) : Polygon(6, radius) { - m_name = strdup(name); -} - -Hexagon::~Hexagon() { - free(m_name); - m_name = 0; -} diff --git a/exercises/memcheck/solution/Polygons.sol.hpp b/exercises/memcheck/solution/Polygons.sol.hpp deleted file mode 100644 index 5cf0668f..00000000 --- a/exercises/memcheck/solution/Polygons.sol.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -class Polygon { -public: - Polygon(int n, float radius); - virtual ~Polygon(){}; - float computePerimeter(); -protected: - int m_nbSides; - float m_radius; -}; - -class Hexagon : public Polygon { -public: - Hexagon(char* name, float radius); - Hexagon(const Hexagon&) = delete; - Hexagon& operator=(const Hexagon&) = delete; - ~Hexagon(); - char* name() const {return m_name;}; -private: - char* m_name; -}; diff --git a/exercises/memcheck/solution/memleak.sol.cpp b/exercises/memcheck/solution/memleak.sol.cpp deleted file mode 100644 index e229f5fd..00000000 --- a/exercises/memcheck/solution/memleak.sol.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "Polygons.sol.hpp" -#include - -Polygon* getHexa(char* name, float radius) { - return new Hexagon(name, radius); -} - -int main() { - // create an Hexagon, call its perimeter method - Polygon *hexa = getHexa((char*)"hexa", 1.0); - std::cout << "Hexa : perimeter = " << hexa->computePerimeter() << "\n\n"; - - // memory deallocation - delete hexa; -} diff --git a/exercises/modern_oo/.gitignore b/exercises/modern_oo/.gitignore deleted file mode 100644 index 51fcd463..00000000 --- a/exercises/modern_oo/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -particles -particles.sol diff --git a/exercises/modern_oo/CMakeLists.txt b/exercises/modern_oo/CMakeLists.txt deleted file mode 100644 index a0d02681..00000000 --- a/exercises/modern_oo/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -# Set up the project. -cmake_minimum_required( VERSION 3.12 ) -project( modern_oo LANGUAGES CXX ) - -# Set up the compilation environment. -include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) - -# Create the user's executable. -add_executable( particles "particles.cpp" ) - -# Create the "solution executable". -add_executable( particles.sol EXCLUDE_FROM_ALL "solution/particles.sol.cpp" ) -add_dependencies( solution particles.sol ) diff --git a/exercises/modern_oo/Makefile b/exercises/modern_oo/Makefile deleted file mode 100644 index 34c72d54..00000000 --- a/exercises/modern_oo/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -all: particles -solution: particles.sol - -clean: - rm -f *o particles particles.sol *~ callgrind.out.* - -particles: particles.cpp - ${CXX} -g -std=c++17 -Wall -Wextra -o $@ $< - -particles.sol : solution/particles.sol.cpp - ${CXX} -g -std=c++17 -Wall -Wextra -o $@ $< diff --git a/exercises/modern_oo/README.md b/exercises/modern_oo/README.md deleted file mode 100644 index 23bf956d..00000000 --- a/exercises/modern_oo/README.md +++ /dev/null @@ -1,8 +0,0 @@ - -## Prerequisites - -* know about classes in ancient C++ - -## Instructions - -* insert one `= delete`, one `= default` and one `override`. diff --git a/exercises/modern_oo/particles.cpp b/exercises/modern_oo/particles.cpp deleted file mode 100644 index 534be765..00000000 --- a/exercises/modern_oo/particles.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include -#include -#include - -class Particle - { - public : - Particle( double mass ) : mass_(mass) {} - double mass() const { return mass_ ; } - virtual std::string name() const { return "Particle" ; } - virtual ~Particle() {} - private : - Particle( const Particle & ) ; // non copiable - double mass_ ; - } ; - -class ChargedParticle : public Particle - { - public : - ChargedParticle( double mass, double charge ) - : Particle(mass), charge_(charge) {} - double charge() const { return charge_ ; } - virtual std::string name() const { return "ChargedParticle" ; } - private : - double charge_ ; - } ; - -void print( Particle & p ) - { - std::cout << p.name() << '\n' ; - std::cout << " mass = " << p.mass() << '\n' ; - } - -int main() - { - std::default_random_engine e; - std::uniform_real_distribution d; - for ( int i = 0 ; i < 5 ; ++i ) - { - if ( d(e) < 0.5 ) - { - Particle p(2) ; - print(p) ; - } - else - { - ChargedParticle p(1,1) ; - print(p) ; - std::cout << " charge = " << p.charge() << '\n' ; - } - } - } diff --git a/exercises/modern_oo/solution/particles.sol.cpp b/exercises/modern_oo/solution/particles.sol.cpp deleted file mode 100644 index 807d1fa5..00000000 --- a/exercises/modern_oo/solution/particles.sol.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include -#include -#include - -class Particle - { - public : - Particle( double mass ) : mass_(mass) {} - Particle( const Particle & ) = delete ; - virtual ~Particle() = default ; - double mass() const { return mass_ ; } - virtual std::string name() const { return "Particle" ; } - private : - double mass_ ; - } ; - -class ChargedParticle : public Particle - { - public : - ChargedParticle( double mass, double charge ) - : Particle(mass), charge_(charge) {} - double charge() const { return charge_ ; } - std::string name() const override { return "ChargedParticle" ; } - private : - double charge_ = 0.0 ; - } ; - -void print( Particle & p ) - { - std::cout << p.name() << '\n' ; - std::cout << " mass = " << p.mass() << '\n' ; - } - -int main() - { - std::default_random_engine e; - std::uniform_real_distribution d; - for ( int i = 0 ; i < 5 ; ++i ) - { - if ( d(e) < 0.5 ) - { - Particle p(2) ; - print(p) ; - } - else - { - ChargedParticle p(1,1) ; - print(p) ; - std::cout << " charge = " << p.charge() << '\n' ; - } - } - } diff --git a/exercises/modules/.gitignore b/exercises/modules/.gitignore deleted file mode 100644 index 00d0a6d1..00000000 --- a/exercises/modules/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -modules -solution/modules -solution/gcm.cache diff --git a/exercises/modules/Complex.hpp b/exercises/modules/Complex.hpp deleted file mode 100644 index 07443d64..00000000 --- a/exercises/modules/Complex.hpp +++ /dev/null @@ -1,110 +0,0 @@ -#include -#include - -template -class Complex_t { -public: - Complex_t() = default; - Complex_t(T r, T i) : m_r(r), m_i(i) {} - - T real() const { return m_r; } - T imaginary() const { return m_i; } - - T norm_sqr() const { - return m_r * m_r + m_i * m_i; - } - - T norm() const { - return std::sqrt(norm_sqr()); - } - - Complex_t& operator+=(const Complex_t& other) { - m_r += other.m_r; - m_i += other.m_i; - return *this; - } - - Complex_t& operator-=(const Complex_t& other) { - m_r -= other.m_r; - m_i -= other.m_i; - return *this; - } - - Complex_t& operator*=(const Complex_t& other) { - const auto r = m_r * other.m_r - m_i * other.m_i; - const auto i = m_r * other.m_i + m_i * other.m_r; - m_r = r; - m_i = i; - return *this; - } - - Complex_t& operator*=(T factor) { - m_r *= factor; - m_i *= factor; - return *this; - } - - Complex_t& operator/=(const Complex_t& other) { - const T ns = other.norm_sqr(); - const auto r = (m_r * other.m_r + m_i * other.m_i) / ns; - const auto i = (m_i * other.m_r - m_r * other.m_i) / ns; - m_r = r; - m_i = i; - return *this; - } - - Complex_t& operator/=(T divisor) { - m_r /= divisor; - m_i /= divisor; - return *this; - } - - friend Complex_t operator+(Complex_t a, const Complex_t& b) { - return a += b; - } - - friend Complex_t operator-(Complex_t a, const Complex_t& b) { - return a -= b; - } - - friend Complex_t operator*(Complex_t a, const Complex_t& b) { - return a *= b; - } - - friend Complex_t operator*(Complex_t c, T factor) { - return c *= factor; - } - - friend Complex_t operator*(T factor, Complex_t c) { - return c *= factor; - } - - friend Complex_t operator/(Complex_t a, Complex_t b) { - return a /= b; - } - - friend Complex_t operator/(Complex_t c, T divisor) { - return c /= divisor; - } - - friend Complex_t operator/(T dividend, const Complex_t& c) { - return Complex_t(dividend, 0) / c; - } - - friend bool operator==(const Complex_t& a, const Complex_t& b) { - return a.m_r == b.m_r && a.m_i == b.m_i; - } - - friend bool operator<(const Complex_t& a, const Complex_t& b) { - return a.norm_sqr() < b.norm_sqr(); - } - - friend std::ostream& operator<<(std::ostream& os, const Complex_t& c) { - return os << "(" << c.real() << ", " << c.imaginary() << ")"; - } - -private: - T m_r{}, m_i{}; -}; - -using Complex = Complex_t<>; diff --git a/exercises/modules/Makefile b/exercises/modules/Makefile deleted file mode 100644 index ab9ff5b5..00000000 --- a/exercises/modules/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -all: modules -solution: modules.sol - -clean: - rm -rf *.o modules gcm.cache - -main.o: main.cpp Complex.hpp - ${CXX} -std=c++20 -fmodules-ts -g -O0 -Wall -Wextra -o $@ -c $< - -modules: main.o - ${CXX} -std=c++20 -fmodules-ts -g -O0 -Wall -Wextra -o $@ $^ - -modules.sol: - $(MAKE) -C solution modules diff --git a/exercises/modules/README.md b/exercises/modules/README.md deleted file mode 100644 index ce7b44c1..00000000 --- a/exercises/modules/README.md +++ /dev/null @@ -1,7 +0,0 @@ - -## Instructions - -* convert the `Complex.hpp` header into a module named 'math' - * you will need to rename `Complex.hpp` into `Complex.cpp`, since it is a translation unit now - * you will need to edit the Makefile and add a new target to compile `Complex.cpp` -* import the module `math` from `main.cpp` diff --git a/exercises/modules/main.cpp b/exercises/modules/main.cpp deleted file mode 100644 index b0beddda..00000000 --- a/exercises/modules/main.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include -#include -#include -#include -#include "Complex.hpp" - -// The code below here should not need to change !! - -template -void compute(int len, T initial, T step) { - // allocate vectors - std::vector v(len+1), diffs(len+1); - - // fill and randomize v - std::generate(v.begin(), v.end(), [value = initial, step]() mutable { - const T cur = value; - value += step; - return cur; - }); - std::shuffle(v.begin(), v.end(), std::default_random_engine{}); - - // compute differences - std::adjacent_difference(v.begin(), v.end(), diffs.begin()); - - // compute standard deviation of it - const T sum = std::reduce(diffs.begin()+1, diffs.end()); - const T sumsq = std::accumulate(diffs.begin()+1, diffs.end(), T(), - [](const T& s, const T& a) { return s + a * a; }); - const T mean = sum/len; - const T variance = sumsq/len - mean*mean; - - std::cout << "Range = [" << initial << ", " << step*len << "]\n" - << "Mean = " << mean << '\n' - << "Variance = " << variance << '\n'; -} - -int main() { - compute(1000, 0.0, 7.0); - compute(1000, Complex(0,0), Complex(1,2)); -} diff --git a/exercises/modules/solution/Complex.cpp b/exercises/modules/solution/Complex.cpp deleted file mode 100644 index db104546..00000000 --- a/exercises/modules/solution/Complex.cpp +++ /dev/null @@ -1,115 +0,0 @@ -module; // start the module global partition - -#include -#include - -export module math; // declare that we intend to export a new module named 'math' - -// You may export Complex_t as well, but for the exercise only the alias Complex at the bottom is neccessary -template -class Complex_t { -public: - Complex_t() = default; - Complex_t(T r, T i) : m_r(r), m_i(i) {} - - T real() const { return m_r; } - T imaginary() const { return m_i; } - - T norm_sqr() const { - return m_r * m_r + m_i * m_i; - } - - T norm() const { - return std::sqrt(norm_sqr()); - } - - Complex_t& operator+=(const Complex_t& other) { - m_r += other.m_r; - m_i += other.m_i; - return *this; - } - - Complex_t& operator-=(const Complex_t& other) { - m_r -= other.m_r; - m_i -= other.m_i; - return *this; - } - - Complex_t& operator*=(const Complex_t& other) { - const auto r = m_r * other.m_r - m_i * other.m_i; - const auto i = m_r * other.m_i + m_i * other.m_r; - m_r = r; - m_i = i; - return *this; - } - - Complex_t& operator*=(T factor) { - m_r *= factor; - m_i *= factor; - return *this; - } - - Complex_t& operator/=(const Complex_t& other) { - const T ns = other.norm_sqr(); - const auto r = (m_r * other.m_r + m_i * other.m_i) / ns; - const auto i = (m_i * other.m_r - m_r * other.m_i) / ns; - m_r = r; - m_i = i; - return *this; - } - - Complex_t& operator/=(T divisor) { - m_r /= divisor; - m_i /= divisor; - return *this; - } - - friend Complex_t operator+(Complex_t a, const Complex_t& b) { - return a += b; - } - - friend Complex_t operator-(Complex_t a, const Complex_t& b) { - return a -= b; - } - - friend Complex_t operator*(Complex_t a, const Complex_t& b) { - return a *= b; - } - - friend Complex_t operator*(Complex_t c, T factor) { - return c *= factor; - } - - friend Complex_t operator*(T factor, Complex_t c) { - return c *= factor; - } - - friend Complex_t operator/(Complex_t a, Complex_t b) { - return a /= b; - } - - friend Complex_t operator/(Complex_t c, T divisor) { - return c /= divisor; - } - - friend Complex_t operator/(T dividend, const Complex_t& c) { - return Complex_t(dividend, 0) / c; - } - - friend bool operator==(const Complex_t& a, const Complex_t& b) { - return a.m_r == b.m_r && a.m_i == b.m_i; - } - - friend bool operator<(const Complex_t& a, const Complex_t& b) { - return a.norm_sqr() < b.norm_sqr(); - } - - friend std::ostream& operator<<(std::ostream& os, const Complex_t& c) { - return os << "(" << c.real() << ", " << c.imaginary() << ")"; - } - -private: - T m_r{}, m_i{}; -}; - -export using Complex = Complex_t<>; // export the alias Complex diff --git a/exercises/modules/solution/Makefile b/exercises/modules/solution/Makefile deleted file mode 100644 index 25fdd68a..00000000 --- a/exercises/modules/solution/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -all: modules - -clean: - rm -rf *.o modules gcm.cache - -Complex.o: Complex.cpp - ${CXX} -std=c++20 -fmodules-ts -g -O0 -Wall -Wextra -o $@ -c $< - -main.o: main.cpp Complex.o - ${CXX} -std=c++20 -fmodules-ts -g -O0 -Wall -Wextra -o $@ -c $< - -modules: main.o Complex.o - ${CXX} -std=c++20 -fmodules-ts -g -O0 -Wall -Wextra -o $@ $^ diff --git a/exercises/modules/solution/main.cpp b/exercises/modules/solution/main.cpp deleted file mode 100644 index 23bcc795..00000000 --- a/exercises/modules/solution/main.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include -#include -#include -#include -#include - -import math; - -// The code below here should not need to change !! - -template -void compute(int len, T initial, T step) { - // allocate vectors - std::vector v(len+1), diffs(len+1); - - // fill and randomize v - std::generate(v.begin(), v.end(), [value = initial, step]() mutable { - const T cur = value; - value += step; - return cur; - }); - std::shuffle(v.begin(), v.end(), std::default_random_engine{}); - - // compute differences - std::adjacent_difference(v.begin(), v.end(), diffs.begin()); - - // compute standard deviation of it - const T sum = std::reduce(diffs.begin()+1, diffs.end()); - const T sumsq = std::accumulate(diffs.begin()+1, diffs.end(), T(), - [](const T& s, const T& a) { return s + a * a; }); - const T mean = sum/len; - const T variance = sumsq/len - mean*mean; - - std::cout << "Range = [" << initial << ", " << step*len << "]\n" - << "Mean = " << mean << '\n' - << "Variance = " << variance << '\n'; -} - -int main() { - compute(1000, 0.0, 7.0); - compute(1000, Complex(0,0), Complex(1,2)); -} diff --git a/exercises/move/.gitignore b/exercises/move/.gitignore deleted file mode 100644 index a1c69d40..00000000 --- a/exercises/move/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -trymove -trymove.sol diff --git a/exercises/move/CMakeLists.txt b/exercises/move/CMakeLists.txt deleted file mode 100644 index 21fec822..00000000 --- a/exercises/move/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -# Set up the project. -cmake_minimum_required( VERSION 3.12 ) -project( move LANGUAGES CXX ) - -# Set up the compilation environment. -include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) - -# Create the user's executable. -add_executable( trymove "trymove.cpp" ) - -# Create the "solution executable". -add_executable( trymove.sol EXCLUDE_FROM_ALL "solution/trymove.sol.cpp" ) -add_dependencies( solution trymove.sol ) diff --git a/exercises/move/Makefile b/exercises/move/Makefile deleted file mode 100644 index 271c7fe3..00000000 --- a/exercises/move/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -all: trymove -solution: trymove.sol - -clean: - rm -f *o trymove trymove.sol *~ callgrind.out.* - -trymove : trymove.cpp - ${CXX} -g -std=c++17 -O2 -Wall -Wextra -L. -o $@ $< - -trymove.sol : solution/trymove.sol.cpp - ${CXX} -g -std=c++17 -O2 -Wall -Wextra -L. -o $@ $< diff --git a/exercises/move/README.md b/exercises/move/README.md deleted file mode 100644 index 99b2b659..00000000 --- a/exercises/move/README.md +++ /dev/null @@ -1,10 +0,0 @@ -## Prerequisites -- Copy and move constructors -- Copy and move assignment operators - -## Instructions - -* look at the code and run it with callgrind or time it e.g. using `/usr/bin/time ./trymove` -* understand how inefficient it is -* understand why and fix trymove.cpp -* see efficiency improvements diff --git a/exercises/move/solution/trymove.sol.cpp b/exercises/move/solution/trymove.sol.cpp deleted file mode 100644 index b6528c6f..00000000 --- a/exercises/move/solution/trymove.sol.cpp +++ /dev/null @@ -1,105 +0,0 @@ -#include -#include -#include - -/** - * An attempt to make a movable class. It allocates memory on construction, and has - * array semantics. (Prefer std::array or std::vector instead of hand-crafted solutions, though.) - * We made it copyable by providing copy constructor and assignment operator, but note that we - * are violating the rule of 5, so it's not moveable yet. -*/ -class CustomArray { - static constexpr std::size_t size = 10000; - -public: - CustomArray() = default; - CustomArray(CustomArray const & other) - { - // Delegate copying to the assignment operator - *this = other; - } - CustomArray & operator=(const CustomArray & other) - { - // We don't do anything when asked to self assign - if (this == &other) return *this; - - std::copy(other.m_storage.get(), other.m_storage.get() + size, m_storage.get()); - return *this; - } - - // ******* - // Task 1: Provide move constructor and move assignment operator. - // Remember from the lectures that you can use the copy and swap - // idiom. - // ******* - - // Step 1: declare a swap function as hidden friend - friend void swap(CustomArray & a, CustomArray & b) noexcept - { - auto tempStorage{ std::move(a.m_storage) }; - a.m_storage = std::move(b.m_storage); - b.m_storage = std::move(tempStorage); - } - - // Step 2: implement move constructor and move assignment using swap - CustomArray(CustomArray && other) noexcept : - m_storage{ nullptr } // This avoids the initial allocation - { - swap(*this, other); - } - CustomArray & operator=(CustomArray && other) noexcept - { - // Protect against self assignment - if (this == &other) return *this; - - swap(*this, other); - return *this; - } - - int & operator[](std::size_t index) { return m_storage[index]; } - -private: - std::unique_ptr m_storage { std::make_unique(size) }; -}; - -/** - * A function to randomly swap entries. - * Unfortunately, it needs three copies to execute each swap. -*/ -void randomiseOrder(std::vector & v) { - // we randomise by applying 10*len random swaps - const auto len = v.size(); - std::default_random_engine e; - std::uniform_int_distribution randomIntDistr{0, len-1}; - - auto swapEntries = [&v](std::size_t i, std::size_t j) - { - // ******* - // Task 2: Use move instead of copy to speed up the swap. - // Test that you are moving by measuring the speed of the program. - // ******* - - // Option 1: - // We use the move constructor for temp, and move assign into v[i], v[j]: - // CustomArray temp{ std::move(v[i]) }; - // v[i] = std::move(v[j]); - // v[j] = std::move(temp); - - // Option 2: swap! - swap(v[i], v[j]); - }; - - for (std::size_t i = 0; i < 10*len; i++) { - const std::size_t m = randomIntDistr(e); - const std::size_t n = randomIntDistr(e); - swapEntries(m, n); - } -} - -int main() { - // Create a lot of movables - std::vector vec(10000); - randomiseOrder(vec); - - return 0; -} diff --git a/exercises/move/trymove.cpp b/exercises/move/trymove.cpp deleted file mode 100644 index 3201fb62..00000000 --- a/exercises/move/trymove.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include -#include -#include - -/** - * An attempt to make a movable class. It allocates memory on construction, and has - * array semantics. (Prefer std::array or std::vector instead of hand-crafted solutions, though.) - * We made it copyable by providing copy constructor and assignment operator, but note that we - * are violating the rule of 5, so it's not moveable yet. -*/ -class CustomArray { - static constexpr std::size_t size = 10000; - -public: - CustomArray() = default; - CustomArray(CustomArray const & other) - { - // Delegate copying to the assignment operator - *this = other; - } - CustomArray & operator=(const CustomArray & other) - { - // We don't do anything when asked to self assign - if (this == &other) return *this; - - std::copy(other.m_storage.get(), other.m_storage.get() + size, m_storage.get()); - return *this; - } - - // ******* - // Task 1: Provide move constructor and move assignment operator. - // Remember from the lectures that you can use the copy and swap - // idiom. - // ******* - - - int & operator[](std::size_t index) { return m_storage[index]; } - -private: - std::unique_ptr m_storage { std::make_unique(size) }; -}; - -/** - * A function to randomly swap entries. - * Unfortunately, it needs three copies to execute each swap. -*/ -void randomiseOrder(std::vector & v) { - // we randomise by applying 10*len random swaps - const auto len = v.size(); - std::default_random_engine e; - std::uniform_int_distribution randomIntDistr{0, len-1}; - - auto swapEntries = [&v](std::size_t i, std::size_t j) - { - // ******* - // Task 2: Use move instead of copy to speed up the swap. - // Test that you are moving by measuring the speed of the program. - // ******* - const CustomArray temp = v[i]; - v[i] = v[j]; - v[j] = temp; - }; - - for (std::size_t i = 0; i < 10*len; i++) { - const std::size_t m = randomIntDistr(e); - const std::size_t n = randomIntDistr(e); - swapEntries(m, n); - } -} - -int main() { - // Create a lot of movables - std::vector vec(10000); - randomiseOrder(vec); - - return 0; -} diff --git a/exercises/operators/.gitignore b/exercises/operators/.gitignore deleted file mode 100644 index 30d8add5..00000000 --- a/exercises/operators/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -operators -operators_sol diff --git a/exercises/operators/CMakeLists.txt b/exercises/operators/CMakeLists.txt deleted file mode 100644 index 2c9f31da..00000000 --- a/exercises/operators/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -# Set up the project. -cmake_minimum_required( VERSION 3.12 ) -project( operators LANGUAGES CXX ) - -# Set up the compilation environment. -include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) -set( CMAKE_CXX_STANDARD 20 ) - -# Create the user's executable. -add_executable( operators "operators.cpp" ) - -# Create the "solution executable". -add_executable( operators_sol EXCLUDE_FROM_ALL "solution/operators_sol.cpp" ) -add_dependencies( solution operators_sol ) diff --git a/exercises/operators/Makefile b/exercises/operators/Makefile deleted file mode 100644 index fd5f735f..00000000 --- a/exercises/operators/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -all: operators -solution: operators_sol - -clean: - rm -f *o operators *~ operators_sol - -operators : operators.cpp - ${CXX} -g -std=c++20 -O0 -Wall -Wextra -L. -o $@ $< - -operators_sol : solution/operators_sol.cpp - ${CXX} -g -std=c++20 -O0 -Wall -Wextra -L. -o $@ $< diff --git a/exercises/operators/README.md b/exercises/operators/README.md deleted file mode 100644 index a1a644bd..00000000 --- a/exercises/operators/README.md +++ /dev/null @@ -1,26 +0,0 @@ - -## Instructions - -STEP 1 -- Add a free operator<<, reusing str(), and simplify main() first lines. -- Replace equal() with operator==(), and upgrade tests. -- Add operator!=(), reusing operator==(), and upgrade tests. -- Replace compare() with operator<=>(), reusing <=> between doubles, - and upgrade tests. -- Replace multiply() with operator*(), and upgrade tests. - -STEP 2 -- Replace TestResultPrinter::process() with operator()(), and upgrade CHECK(). - -OPTIONAL STEP 3 -- Add an inplace multiplication operator*=(), and add tests. -- Review operator*() so to reuse operator*=(). -- Ensure calls to operator*=() can be chained, the same as operator<<(). - -## Take away - -- Do not confuse equality and equivalence. -- We can very often implement an arithmetic operator@ in terms of operator@=. -- When implementing <=>, you get <, >, <=, >= for free. -- Object-functions are very used with standard algorithms, - yet tend to be often replaced by lambdas in modern C++. diff --git a/exercises/operators/operators.cpp b/exercises/operators/operators.cpp deleted file mode 100644 index 625c9c25..00000000 --- a/exercises/operators/operators.cpp +++ /dev/null @@ -1,107 +0,0 @@ -#include -#include -#include -#include - -class Fraction { - -public: - - Fraction(int a_num, int a_denom = 1) : m_num(a_num), m_denom(a_denom) {} - - std::string str() const { - std::ostringstream oss; - oss << m_num << '/' << m_denom; - return oss.str(); - } - - friend bool equal( Fraction const & lhs, Fraction const & rhs ) { - return (lhs.m_num==rhs.m_num) && (lhs.m_denom==rhs.m_denom); - } - - friend int compare( Fraction const & lhs, Fraction const & rhs ) { - int v1 = lhs.m_num * rhs.m_denom; - int v2 = rhs.m_num * lhs.m_denom; - if (v1 < v2) return -1; - else if (v1 > v2) return 1; - else return 0; - } - - friend Fraction multiply( Fraction const & lhs, Fraction const & rhs ) { - return {lhs.m_num * rhs.m_num, lhs.m_denom * rhs.m_denom}; - } - - Fraction normalized() const { - const int gcd = std::gcd(m_num, m_denom); - return {m_num/gcd, m_denom/gcd}; - } - -private: - - int m_num, m_denom; - -}; - -class TestResultPrinter { - -public: - - TestResultPrinter( unsigned int a_width ) : m_width(a_width) {} - - void process(std::string const & what, bool passed) { - std::cout << std::left << std::setw(m_width) << what << ": " << (passed ? "PASS" : "** FAIL **") << '\n'; - } - -private: - - unsigned int m_width; - -}; - -// This is using the cpp, the C preprocessor to expand a bit of code -// (the what argument) to a pair containing a string representation -// of it and the code itself. That way, print is given a string and a -// value where the string is the code that lead to the value -#define CHECK(printer,what) printer.process(#what, what) - -int main() { - - // create a fraction with values 3 (which is 3/1) and 1/3 - std::cout<0); - CHECK(p2,compare(third,Fraction{2,4})<0); - - // multiply - std::cout< -#include -#include -#include -#include - -class Fraction { - -public: - - Fraction(int a_num, int a_denom = 1) : m_num(a_num), m_denom(a_denom) {} - - std::string str() const { - std::ostringstream oss; - oss << m_num << '/' << m_denom; - return oss.str(); - } - - friend bool operator==(Fraction const & lhs, Fraction const & rhs) { - return lhs.m_num == rhs.m_num && lhs.m_denom == rhs.m_denom; - } - - friend bool operator!=(Fraction const & lhs, Fraction const & rhs) { - return !(lhs==rhs); - } - - friend auto operator<=>( Fraction const & lhs, Fraction const & rhs ) { - return ((lhs.m_num*rhs.m_denom)<=>(rhs.m_num*lhs.m_denom)); - } - - Fraction & operator*=(Fraction const & other) { - m_num *= other.m_num; - m_denom *= other.m_denom; - return *this; - } - - friend Fraction operator*( Fraction lhs, Fraction const & rhs ) { - return lhs*=rhs; - } - - Fraction normalized() const { - const int gcd = std::gcd(m_num, m_denom); - return {m_num/gcd, m_denom/gcd}; - } - -private: - - int m_num, m_denom; - -}; - -std::ostream & operator<<(std::ostream & os, Fraction const & f) { - return (os<Fraction{2,6})); - CHECK(p2,std::is_gt(third<=>Fraction{1,4})); - CHECK(p2,std::is_lt(third<=>Fraction{2,4})); - CHECK(p2,(third>Fraction{1,4})); - CHECK(p2,(third=Fraction{2,4})); - CHECK(p2,(third>=Fraction{1,4})); - CHECK(p2,(third<=Fraction{2,4})); - CHECK(p2,(third>=Fraction{1,3})); - CHECK(p2,(third<=Fraction{2,3})); - CHECK(p2,!(thirdFraction{2,4})); - CHECK(p2,!(thirdFraction{2,3})); - - // multiply - std::cout<Fraction{1,1})); - CHECK(p3,std::is_eq((3*third)<=>Fraction{1,1})); - CHECK(p3,((3*third).normalized()==1)); - - // multiply in place - std::cout<1)); - CHECK(p4,one.normalized()==1); - CHECK(p4,one!=1); - - // end - std::cout<` rather than a double, and the program prints `nothing` rather than `nan` for the call with `-10`. It will also require to modify `square`. diff --git a/exercises/optional/optional.cpp b/exercises/optional/optional.cpp deleted file mode 100644 index 6ed57d1d..00000000 --- a/exercises/optional/optional.cpp +++ /dev/null @@ -1,37 +0,0 @@ - -/* - -In the code below, modify the function `mysqrt` below so that it returns -an `std::optional` rather than a double, and the program prints -`nothing` rather than `nan` for the call with `-10`. It will also require -to update `square`. - -*/ - -#include -#include -#include - -double mysqrt(double d) // TO BE MODIFIED -{ - return std::sqrt(d); // TO BE MODIFIED -} - -double square(double d) // TO BE MODIFIED -{ - return d * d; // TO BE MODIFIED -} - -template -std::ostream &operator<<(std::ostream &os, std::optional const &opt) { - if (opt) { - return os << opt.value(); - } else { - return os << "nothing"; - } -} - -int main() { - std::cout << square(mysqrt(10)) << std::endl; - std::cout << square(mysqrt(-10)) << std::endl; -} diff --git a/exercises/optional/solution/optional.sol.cpp b/exercises/optional/solution/optional.sol.cpp deleted file mode 100644 index 4788eacc..00000000 --- a/exercises/optional/solution/optional.sol.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include -#include - -std::optional mysqrt(double d) { - if (d < 0) { - return {}; - } else { - return std::sqrt(d); - } -} - -std::optional square(std::optional d) { - if (d) { - return d.value() * d.value(); - } else { - return {}; - } -} - -template -std::ostream &operator<<(std::ostream &os, std::optional const &opt) { - if (opt) { - return os << opt.value(); - } else { - return os << "nothing"; - } -} - -int main() { - std::cout << square(mysqrt(10)) << std::endl; - std::cout << square(mysqrt(-10)) << std::endl; -} diff --git a/exercises/polymorphism/.gitignore b/exercises/polymorphism/.gitignore deleted file mode 100644 index 6b2be516..00000000 --- a/exercises/polymorphism/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -trypoly -trypoly.sol diff --git a/exercises/polymorphism/CMakeLists.txt b/exercises/polymorphism/CMakeLists.txt deleted file mode 100644 index 2a6eec99..00000000 --- a/exercises/polymorphism/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -# Set up the project. -cmake_minimum_required( VERSION 3.12 ) -project( polymorhism LANGUAGES CXX ) - -# Set up the compilation environment. -include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) - -# Create the user's library. -add_library( polymorphismPoly "Polygons.hpp" "Polygons.cpp" ) -target_include_directories( polymorphismPoly PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}" ) -set_target_properties( polymorphismPoly PROPERTIES OUTPUT_NAME "poly" ) -if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC" ) - target_compile_definitions( polymorphismPoly PRIVATE _USE_MATH_DEFINES ) -endif() - -# Create the user's executable. -add_executable( trypoly "trypoly.cpp" ) -target_link_libraries( trypoly PRIVATE polymorphismPoly ) - -# Create the "solution executable". -add_executable( trypoly.sol EXCLUDE_FROM_ALL "solution/trypoly.sol.cpp" ) -target_link_libraries( trypoly.sol PRIVATE polymorphismPoly ) -add_dependencies( solution trypoly.sol ) diff --git a/exercises/polymorphism/Makefile b/exercises/polymorphism/Makefile deleted file mode 100644 index 41af0f2e..00000000 --- a/exercises/polymorphism/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -all: trypoly -solution: trypoly.sol - -clean: - rm -f *o *so trypoly *~ trypoly.sol - -libpoly.so: Polygons.cpp Polygons.hpp - $(CXX) -std=c++11 -Wsuggest-override -g -Wall -Wextra -shared -fPIC -o $@ $< - -trypoly : trypoly.cpp libpoly.so - $(CXX) -std=c++11 -Wsuggest-override -g -Wall -Wextra -o $@ $^ - -trypoly.sol : solution/trypoly.sol.cpp libpoly.so - $(CXX) -std=c++11 -g -Wall -Wextra -I. -o $@ $^ diff --git a/exercises/polymorphism/Polygons.cpp b/exercises/polymorphism/Polygons.cpp deleted file mode 100644 index a94383a0..00000000 --- a/exercises/polymorphism/Polygons.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "Polygons.hpp" -#include -#include - -RegularPolygon::RegularPolygon(int n, float radius) : m_nbSides(n), m_radius(radius) {}; - -float RegularPolygon::computePerimeter() const { - std::cout << "Polygon::computePerimeter is being called\n"; - return 2 * m_nbSides * std::sin(static_cast(M_PI) / m_nbSides) * m_radius; -} - -Pentagon::Pentagon(float radius) : RegularPolygon(5, radius) {} - -Hexagon::Hexagon(float radius) : RegularPolygon(6, radius) {} - -float Hexagon::computePerimeter() const { - std::cout << "Hexagon::computePerimeter is being called\n"; - return 6 * m_radius; -} diff --git a/exercises/polymorphism/Polygons.hpp b/exercises/polymorphism/Polygons.hpp deleted file mode 100644 index a7715f81..00000000 --- a/exercises/polymorphism/Polygons.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -class RegularPolygon { -public: - RegularPolygon(int n, float radius); - float computePerimeter() const; -protected: - int m_nbSides; - float m_radius; -}; - -class Pentagon : public RegularPolygon { -public: - Pentagon(float radius); -}; - -class Hexagon : public RegularPolygon { -public: - Hexagon(float radius); - // 6*radius is easier than generic case - float computePerimeter() const; -}; diff --git a/exercises/polymorphism/README.md b/exercises/polymorphism/README.md deleted file mode 100644 index 5c46555e..00000000 --- a/exercises/polymorphism/README.md +++ /dev/null @@ -1,33 +0,0 @@ -## Instructions for the "polymorphism" exercise - -Step 1 -* look at the code -* open `trypoly.cpp` -* create a Pentagon, call its `perimeter` method -* Compile via `make`, execute via `./trypoly` - * you may have to add current directory to your LD_LIBRARY_PATH : -```shell - export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:. -``` -* create an Hexagon, call its `perimeter` method -* recompile and check what happens - -Step 2 -* create an Hexagon, call its parent’s `perimeter` method -* recompile and check again -* retry with virtual methods - - -## Instructions for the "compiler chain" exercise - -* preprocess `Polygons.cpp` (`g++ -E -o output`) -* compile `Polygons.o` and `trypoly.o` (`g++ -c -o output`) -* use `nm` to check symbols in `.o` files -* look at the `Makefile` -* try `make clean; make` -* see linking stage using `g++ -v` - * just add a `-v` in the Makefile command for `trypoly` - * run `make clean; make` - * look at the collect 2 line, from the end up to `-o trypoly` -* see library dependencies of `trypoly` and `Polygons.so` with `ldd` - * On OS X, use `otool -L` for a similar effect diff --git a/exercises/polymorphism/solution/trypoly.sol.cpp b/exercises/polymorphism/solution/trypoly.sol.cpp deleted file mode 100644 index 50325d41..00000000 --- a/exercises/polymorphism/solution/trypoly.sol.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "Polygons.hpp" -#include - -int main() { - // create a Pentagon, call its perimeter method - Pentagon penta{1.0}; - std::cout << "Penta : perimeter = " << penta.computePerimeter() << "\n\n"; - - // create a Hexagon, call its perimeter method - Hexagon hexa{1.0}; - std::cout << "Hexa : perimeter = " << hexa.computePerimeter() << "\n\n"; - - // create a Hexagon, call the perimeter method through a reference to Polygon - Hexagon hexa2{1.0}; - RegularPolygon &poly = hexa2; - std::cout << "Hexa : perimeter = " << hexa2.computePerimeter() << '\n' - << "Hexa as Poly : perimeter = " << poly.computePerimeter() << '\n'; - - // retry virtual method -} diff --git a/exercises/polymorphism/trypoly.cpp b/exercises/polymorphism/trypoly.cpp deleted file mode 100644 index 97e200df..00000000 --- a/exercises/polymorphism/trypoly.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "Polygons.hpp" -#include - -int main() { - // create a Pentagon, call its perimeter method - - - // create a Hexagon, call its perimeter method - - - // create a Hexagon, call the perimeter method through a reference to Polygon - - - // retry virtual method - -} diff --git a/exercises/python/CMakeLists.txt b/exercises/python/CMakeLists.txt deleted file mode 100644 index 1e1bd348..00000000 --- a/exercises/python/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -# Set up the project. -cmake_minimum_required( VERSION 3.12 ) -project( python LANGUAGES CXX ) - -# Set up the compilation environment. -include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) - -# Find Python for the build. -find_package( Python3 COMPONENTS Development REQUIRED ) - -# Build the C++ shared library. -add_library( mandel SHARED Complex.hpp mandel.hpp mandel.cpp ) - -# Build a "C wrapper" around the C++ shared library. -add_library( mandelc SHARED mandel_cwrapper.hpp mandel_cwrapper.cpp ) -target_link_libraries( mandelc PUBLIC mandel ) - -# Build the Python module around the C++ shared library. -add_library( mandelm SHARED mandel_module.cpp ) -target_link_libraries( mandelm PRIVATE Python3::Python mandel ) -set_target_properties( mandelm PROPERTIES - PREFIX "" - OUTPUT_NAME "mandel" ) diff --git a/exercises/python/Complex.hpp b/exercises/python/Complex.hpp deleted file mode 100644 index 07443d64..00000000 --- a/exercises/python/Complex.hpp +++ /dev/null @@ -1,110 +0,0 @@ -#include -#include - -template -class Complex_t { -public: - Complex_t() = default; - Complex_t(T r, T i) : m_r(r), m_i(i) {} - - T real() const { return m_r; } - T imaginary() const { return m_i; } - - T norm_sqr() const { - return m_r * m_r + m_i * m_i; - } - - T norm() const { - return std::sqrt(norm_sqr()); - } - - Complex_t& operator+=(const Complex_t& other) { - m_r += other.m_r; - m_i += other.m_i; - return *this; - } - - Complex_t& operator-=(const Complex_t& other) { - m_r -= other.m_r; - m_i -= other.m_i; - return *this; - } - - Complex_t& operator*=(const Complex_t& other) { - const auto r = m_r * other.m_r - m_i * other.m_i; - const auto i = m_r * other.m_i + m_i * other.m_r; - m_r = r; - m_i = i; - return *this; - } - - Complex_t& operator*=(T factor) { - m_r *= factor; - m_i *= factor; - return *this; - } - - Complex_t& operator/=(const Complex_t& other) { - const T ns = other.norm_sqr(); - const auto r = (m_r * other.m_r + m_i * other.m_i) / ns; - const auto i = (m_i * other.m_r - m_r * other.m_i) / ns; - m_r = r; - m_i = i; - return *this; - } - - Complex_t& operator/=(T divisor) { - m_r /= divisor; - m_i /= divisor; - return *this; - } - - friend Complex_t operator+(Complex_t a, const Complex_t& b) { - return a += b; - } - - friend Complex_t operator-(Complex_t a, const Complex_t& b) { - return a -= b; - } - - friend Complex_t operator*(Complex_t a, const Complex_t& b) { - return a *= b; - } - - friend Complex_t operator*(Complex_t c, T factor) { - return c *= factor; - } - - friend Complex_t operator*(T factor, Complex_t c) { - return c *= factor; - } - - friend Complex_t operator/(Complex_t a, Complex_t b) { - return a /= b; - } - - friend Complex_t operator/(Complex_t c, T divisor) { - return c /= divisor; - } - - friend Complex_t operator/(T dividend, const Complex_t& c) { - return Complex_t(dividend, 0) / c; - } - - friend bool operator==(const Complex_t& a, const Complex_t& b) { - return a.m_r == b.m_r && a.m_i == b.m_i; - } - - friend bool operator<(const Complex_t& a, const Complex_t& b) { - return a.norm_sqr() < b.norm_sqr(); - } - - friend std::ostream& operator<<(std::ostream& os, const Complex_t& c) { - return os << "(" << c.real() << ", " << c.imaginary() << ")"; - } - -private: - T m_r{}, m_i{}; -}; - -using Complex = Complex_t<>; diff --git a/exercises/python/Makefile b/exercises/python/Makefile deleted file mode 100644 index 478cf27b..00000000 --- a/exercises/python/Makefile +++ /dev/null @@ -1,21 +0,0 @@ - -all: mandel.so libmandelc.so -solution: mandel.so libmandelc.so - -mandel.so:mandel_module.o libmandel.so - ${CXX} -shared -Wl,-undefined,dynamic_lookup $^ -o $@ `python3-config --ldflags` - -mandel_module.o:mandel_module.cpp - ${CXX} -pthread -O3 -Wall -std=c++14 -fPIC -I. `python3-config --cflags` -c $< -o $@ - -libmandelc.so:mandel_cwrapper.o libmandel.so - ${CXX} -shared $^ -o $@ - -mandel_cwrapper.o:mandel_cwrapper.cpp - ${CXX} -O3 -Wall -std=c++14 -fPIC -c $< -o $@ - -libmandel.so:mandel.cpp Complex.hpp - ${CXX} -shared -O3 -Wall -std=c++14 -fPIC $< -o $@ - -clean: - rm -rf *.o *.so *~ *pyc *pyo *svg diff --git a/exercises/python/README.md b/exercises/python/README.md deleted file mode 100644 index b921cebb..00000000 --- a/exercises/python/README.md +++ /dev/null @@ -1,11 +0,0 @@ - -## Instructions - -* look at the original python code `mandel.py` -* time it (`time python3 mandel.py`) -* look at the code in `mandel.hpp/cpp` -* look at the python module mandel `mandel_module.cpp` -* compile and modify `mandel.py` to use it -* see the gain in time -* look at the C wrapper in `mandel_cwrapper.cpp` -* modify `mandel.py` to use `libmandelc` directly with ctypes diff --git a/exercises/python/mandel.cpp b/exercises/python/mandel.cpp deleted file mode 100644 index 9993aa71..00000000 --- a/exercises/python/mandel.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "mandel.hpp" - -int mandel(const Complex &a) { - Complex z{0, 0}; - for (int n = 1; n < 100; n++) { - z = z*z + a; - if (Complex{2, 0} < z) { - return n; - } - } - return -1; -} diff --git a/exercises/python/mandel.hpp b/exercises/python/mandel.hpp deleted file mode 100644 index f7cf9962..00000000 --- a/exercises/python/mandel.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "Complex.hpp" - -/** - * computes number of iterations of the mandelbrot - * formula you need before reaching a norm > 2 - * returned value is -1 if 100 iterations are reached - * without reaching it - */ -int mandel(const Complex &a); diff --git a/exercises/python/mandel.py b/exercises/python/mandel.py deleted file mode 100644 index cf42edc2..00000000 --- a/exercises/python/mandel.py +++ /dev/null @@ -1,25 +0,0 @@ -from pylab import * -from numpy import NaN - -def m(a): - z = 0 - for n in range(1, 100): - z = z**2 + a - if abs(z) > 2: - return n - return NaN - -X = arange(-2, .5, .002) -Y = arange(-1, 1, .002) -Z = zeros((len(Y), len(X))) - -for iy, y in enumerate(Y): - print (iy, "of", len(Y)) - for ix, x in enumerate(X): - Z[iy,ix] = m(x + 1j * y) - -imshow(Z, cmap = plt.cm.prism, interpolation = 'none', extent = (X.min(), X.max(), Y.min(), Y.max())) -xlabel("Re(c)") -ylabel("Im(c)") -savefig("mandelbrot_python.svg") -show() diff --git a/exercises/python/mandel_cwrapper.cpp b/exercises/python/mandel_cwrapper.cpp deleted file mode 100644 index 6f481eb0..00000000 --- a/exercises/python/mandel_cwrapper.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "mandel_cwrapper.hpp" - -extern "C" { - - int mandel(float r, float i) { - return mandel(Complex(r, i)); - } - -} diff --git a/exercises/python/mandel_cwrapper.hpp b/exercises/python/mandel_cwrapper.hpp deleted file mode 100644 index 5e3bf388..00000000 --- a/exercises/python/mandel_cwrapper.hpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "mandel.hpp" - -extern "C" { - int mandel(float r, float i); -} diff --git a/exercises/python/mandel_module.cpp b/exercises/python/mandel_module.cpp deleted file mode 100644 index 9a87ffbf..00000000 --- a/exercises/python/mandel_module.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include "mandel.hpp" - -static PyObject * mandel_wrapper(PyObject * self, - PyObject * args) { - // Parse Input - float r, i; - if (!PyArg_ParseTuple(args, "ff", &r, &i)) return NULL; - // Call C function - int result = mandel(Complex(r, i)); - // Build returned objects - return PyLong_FromLong(result); -} - -static PyMethodDef mandelMethods[] = { - {"mandel", mandel_wrapper, METH_VARARGS, "computes nb of iterations for mandelbrot set for a given complex number"}, - {NULL, NULL, 0, NULL} -}; - -static struct PyModuleDef mandelModule = { - PyModuleDef_HEAD_INIT, - "mandel", /* name of module */ - NULL, /* module documentation */ - -1, /* size of per-interpreter state of the module, - or -1 if the module keeps state in global variables. */ - mandelMethods -}; - -PyMODINIT_FUNC PyInit_mandel(void) { - return PyModule_Create(&mandelModule); -} diff --git a/exercises/python/solution/mandel.sol.py b/exercises/python/solution/mandel.sol.py deleted file mode 100644 index bb442589..00000000 --- a/exercises/python/solution/mandel.sol.py +++ /dev/null @@ -1,22 +0,0 @@ -from pylab import * -from numpy import NaN -from mandel import mandel - -X = arange(-2, .5, .002) -Y = arange(-1, 1, .002) -Z = zeros((len(Y), len(X))) - -for iy, y in enumerate(Y): - print (iy, "of", len(Y)) - for ix, x in enumerate(X): - v = mandel(x, y) - if v >= 0 : - Z[iy,ix] = v - else: - Z[iy,ix] = NaN - -imshow(Z, cmap = plt.cm.prism, interpolation = 'none', extent = (X.min(), X.max(), Y.min(), Y.max())) -xlabel("Re(c)") -ylabel("Im(c)") -savefig("mandelbrot_python.svg") -show() diff --git a/exercises/python/solution/mandel.solctype.py b/exercises/python/solution/mandel.solctype.py deleted file mode 100644 index da6f9313..00000000 --- a/exercises/python/solution/mandel.solctype.py +++ /dev/null @@ -1,25 +0,0 @@ -from pylab import * -from numpy import NaN -from ctypes import * - -# interface with C library -libmandel = CDLL('libmandelc.so') - -X = arange(-2, .5, .002) -Y = arange(-1, 1, .002) -Z = zeros((len(Y), len(X))) - -for iy, y in enumerate(Y): - print (iy, "of", len(Y)) - for ix, x in enumerate(X): - v = libmandel.mandel(c_float(x), c_float(y)) - if v >= 0 : - Z[iy,ix] = v - else: - Z[iy,ix] = NaN - -imshow(Z, cmap = plt.cm.prism, interpolation = 'none', extent = (X.min(), X.max(), Y.min(), Y.max())) -xlabel("Re(c)") -ylabel("Im(c)") -savefig("mandelbrot_python.svg") -show() diff --git a/exercises/race/.gitignore b/exercises/race/.gitignore deleted file mode 100644 index 76613f70..00000000 --- a/exercises/race/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -racing -racing.sol1 -racing.sol2 diff --git a/exercises/race/CMakeLists.txt b/exercises/race/CMakeLists.txt deleted file mode 100644 index 07c789f8..00000000 --- a/exercises/race/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -# Set up the project. -cmake_minimum_required( VERSION 3.12 ) -project( race LANGUAGES CXX ) - -# Set up the compilation environment. -include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) - -# Figure out how to use the platform's thread capabilities. -find_package( Threads REQUIRED ) - -# Create the user's executable. -add_executable( racing "racing.cpp" ) -target_link_libraries( racing PRIVATE Threads::Threads ) - -# Create the "solution executable". -add_executable( racing.sol1 EXCLUDE_FROM_ALL "solution/racing.sol1.cpp" ) -target_link_libraries( racing.sol1 PRIVATE Threads::Threads ) -add_custom_target( solution1 ) -add_dependencies( solution1 racing.sol1 ) -add_executable( racing.sol2 EXCLUDE_FROM_ALL "solution/racing.sol2.cpp" ) -target_link_libraries( racing.sol2 PRIVATE Threads::Threads ) -add_custom_target( solution2 ) -add_dependencies( solution2 racing.sol2 ) -add_dependencies( solution solution1 solution2 ) diff --git a/exercises/race/Makefile b/exercises/race/Makefile deleted file mode 100644 index 129c7bd3..00000000 --- a/exercises/race/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -PROGRAM_NAME=racing - -all: $(PROGRAM_NAME) -solution: $(PROGRAM_NAME).sol1 $(PROGRAM_NAME).sol2 - - -clean: - rm -f *o $(PROGRAM_NAME) *~ core $(PROGRAM_NAME).sol? - -$(PROGRAM_NAME) : $(PROGRAM_NAME).cpp - ${CXX} ${CXXFLAGS} -g -std=c++17 -O2 -pthread -Wall -Wextra -L. -o $@ $< - -$(PROGRAM_NAME).sol1 : solution/$(PROGRAM_NAME).sol1.cpp - ${CXX} ${CXXFLAGS} -g -std=c++17 -O2 -pthread -Wall -Wextra -L. -o $@ $< - -$(PROGRAM_NAME).sol2 : solution/$(PROGRAM_NAME).sol2.cpp - ${CXX} ${CXXFLAGS} -g -std=c++17 -O2 -pthread -Wall -Wextra -L. -o $@ $< diff --git a/exercises/race/README.md b/exercises/race/README.md deleted file mode 100644 index 3dc089a0..00000000 --- a/exercises/race/README.md +++ /dev/null @@ -1,16 +0,0 @@ - -## Instructions - -The program `racing.cpp` is incrementing a shared integer many times, within several threads, which should lead to race conditions if no specific protection is used. The values of the global parameters `nThread`, `nInc` and `nRepeat` can be custommized for your own computer. - -Tasks -- Compile and run the executable, check it races. -- If you have a bash shell, try `./run ./racing`, which keeps invoking the executable until a race condition is detected. -- (Optional) You can use `valgrind --tool=helgrind ./racing` to prove your assumption -- (Optional) If your operating system supports it, recompile with thread sanitizer. - With Makefile, use e.g. `make CXXFLAGS="-fsanitize=thread"` -- Use a `std::mutex` to fix the issue. -- See the difference in execution time, for example with `time ./racing`. - You might have to increase `nRepeat` if it completes too fast, or lower it if it takes too long. -- (Optional) Check again with `valgrind` or thread sanitizer if the problem is fixed. -- Try to use `std::atomic` instead of the mutex, and compare the execution time. diff --git a/exercises/race/racing.cpp b/exercises/race/racing.cpp deleted file mode 100644 index 5d8017dc..00000000 --- a/exercises/race/racing.cpp +++ /dev/null @@ -1,44 +0,0 @@ - -#include -#include -#include - -/* - * This program tries to increment an integer `nInc` times in `nThread` threads. - * If the result comes out at `nInc*nThread`, it stays silent, but it will print - * an error if a race condition is detected. - * If you don't see it racing, try ./run ./racing, which keeps invoking the - * executable until a race condition is detected. - */ - -constexpr std::size_t nThread = 10; -constexpr std::size_t nInc = 1000; -constexpr std::size_t nRepeat = 1000; - -int main() { - int nError = 0; - - for (std::size_t j = 0; j < nRepeat; j++) { - int a = 0; - - // Increment the variable a 100 times: - auto increment = [&a](){ - for (std::size_t i = 0; i < nInc; ++i) { - a++; - } - }; - - // Start up all threads - std::vector threads; - for (std::size_t i = 0; i < nThread; ++i) threads.emplace_back(increment); - for (auto & thread : threads) thread.join(); - - // Check - if (a != nThread * nInc) { - std::cerr << "Race detected! Result: " << a << '\n'; - nError++; - } - } - - return nError; -} diff --git a/exercises/race/run b/exercises/race/run deleted file mode 100755 index f4db698d..00000000 --- a/exercises/race/run +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -PROGRAM="./racing" -if [ $# -ge 1 ]; then - PROGRAM=$1 -fi - -while true; do - $PROGRAM || break; -done diff --git a/exercises/race/solution/racing.sol1.cpp b/exercises/race/solution/racing.sol1.cpp deleted file mode 100644 index 1d883406..00000000 --- a/exercises/race/solution/racing.sol1.cpp +++ /dev/null @@ -1,39 +0,0 @@ - -#include -#include -#include -#include - -constexpr std::size_t nThread = 10; -constexpr std::size_t nInc = 1000; -constexpr std::size_t nRepeat = 1000; - -int main() { - int nError = 0; - - for (std::size_t j = 0; j < nRepeat; j++) { - int a = 0; - std::mutex aMutex; - - // Increment the variable a 100 times: - auto increment = [&a,&aMutex](){ - for (std::size_t i = 0; i < nInc; ++i) { - std::scoped_lock lock{aMutex}; - a++; - } - }; - - // Start up all threads: - std::vector threads; - for (std::size_t i = 0; i < nThread; ++i) threads.emplace_back(increment); - for (auto & thread : threads) thread.join(); - - // Check - if (a != nThread * nInc) { - std::cerr << "Race detected! Result: " << a << '\n'; - nError++; - } - } - - return nError; -} diff --git a/exercises/race/solution/racing.sol2.cpp b/exercises/race/solution/racing.sol2.cpp deleted file mode 100644 index 2e3f2a98..00000000 --- a/exercises/race/solution/racing.sol2.cpp +++ /dev/null @@ -1,37 +0,0 @@ - -#include -#include -#include -#include - -constexpr std::size_t nThread = 10; -constexpr std::size_t nInc = 1000; -constexpr std::size_t nRepeat = 1000; - -int main() { - int nError = 0; - - for (std::size_t j = 0; j < nRepeat; j++) { - std::atomic a{0}; - - // Increment the variable a 100 times: - auto increment = [&a](){ - for (std::size_t i = 0; i < nInc; ++i) { - a++; - } - }; - - // Start up all threads - std::vector threads; - for (std::size_t i = 0; i < nThread; ++i) threads.emplace_back(increment); - for (auto & thread : threads) thread.join(); - - // Check - if (a != nThread * nInc) { - std::cerr << "Race detected! Result: " << a << '\n'; - nError++; - } - } - - return nError; -} diff --git a/exercises/smartPointers/.gitignore b/exercises/smartPointers/.gitignore deleted file mode 100644 index f6bbf861..00000000 --- a/exercises/smartPointers/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -problem1 -problem2 -problem3 -problem4 -problem5 -problem1.sol -problem2.sol -problem3.sol -problem4.sol -problem5.sol diff --git a/exercises/smartPointers/CMakeLists.txt b/exercises/smartPointers/CMakeLists.txt deleted file mode 100644 index 1d13482c..00000000 --- a/exercises/smartPointers/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ -# Set up the project. -cmake_minimum_required( VERSION 3.12 ) -project( smartPointers LANGUAGES CXX ) - -# Set up the compilation environment. -include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) -set( CMAKE_CXX_STANDARD 20 ) - -# Create the user's executable. -add_executable( problem1 "problem1.cpp" ) -add_executable( problem2 "problem2.cpp" ) -add_executable( problem3 "problem3.cpp" ) -add_executable( problem4 "problem4.cpp" ) -add_executable( problem5 "problem5.cpp" ) - -# Create the "solution executables". -add_executable( problem1.sol EXCLUDE_FROM_ALL "solution/problem1.sol.cpp" ) -add_executable( problem2.sol EXCLUDE_FROM_ALL "solution/problem2.sol.cpp" ) -add_executable( problem3.sol EXCLUDE_FROM_ALL "solution/problem3.sol.cpp" ) -add_executable( problem4.sol EXCLUDE_FROM_ALL "solution/problem4.sol.cpp" ) -add_executable( problem5.sol EXCLUDE_FROM_ALL "solution/problem5.sol.cpp" ) -add_dependencies( solution problem1.sol problem2.sol problem3.sol problem4.sol problem5.sol ) diff --git a/exercises/smartPointers/Makefile b/exercises/smartPointers/Makefile deleted file mode 100644 index 59041117..00000000 --- a/exercises/smartPointers/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -all: problem1 problem2 problem3 problem4 problem5 -solution: problem1.sol problem2.sol problem3.sol problem4.sol problem5.sol - -clean: - rm -f *o *so *~ problem? problem?.sol - -% : %.cpp - $(CXX) -g -std=c++20 -Wall -Wextra -o $@ $< - -%.sol : solution/%.sol.cpp - $(CXX) -g -std=c++20 -Wall -Wextra -o $@ $< diff --git a/exercises/smartPointers/README.md b/exercises/smartPointers/README.md deleted file mode 100644 index 5c710bb9..00000000 --- a/exercises/smartPointers/README.md +++ /dev/null @@ -1,24 +0,0 @@ - -# Writing leak-free and fault-free C++ - -Here we have five code snippets that will benefit from using smart pointers. By replacing every explicit `new` with `make_unique` or `make_shared`, (alternatively by explicitly instantiating smart pointers) we will fix memory leaks, segmentation faults, and make most cleanup code unnecessary. - -## Prerequisites - -* Do you know which kind of pointer is used for what? - * Raw pointer - * [`std::unique_ptr`](https://en.cppreference.com/w/cpp/memory/unique_ptr) - * [`std::shared_ptr`](https://en.cppreference.com/w/cpp/memory/shared_ptr) -* C++-14 for `std::make_unique` / `std::make_shared`. Understand what these functions do. -* Helpful: Move semantics for `problem2()`, but one can do without. - -## Instructions - -* In the **essentials course**, work on `problem1` and `problem2`, and fix the leaks using smart pointers. -* In the **advanced course**, work on `problem1` to `problem5`. Skip `problem4` and `problem5` if you don't have enough time. -* Dedicated instructions are given in each cpp file. -* Each one is written so that you easily check if the problem is solved or not. -* If seen in course before, you are also advised to try external tools such as valgrind: -``` -valgrind --leak-check=full --track-origins=yes ./problem1 -``` diff --git a/exercises/smartPointers/problem1.cpp b/exercises/smartPointers/problem1.cpp deleted file mode 100644 index 1741aca7..00000000 --- a/exercises/smartPointers/problem1.cpp +++ /dev/null @@ -1,72 +0,0 @@ - - -#include -#include - - -/* -------------------------------------------------------------------------------------------- - * Unique ownership. - * - * Always use smart pointers instead of `new`. A frequent source of memory leaks is a function - * that terminates in an unexpected way. - * - * Tasks - * 1) Compile and run the code below. Notice that the final count is `1`, - * showing that the instance of LargeObject has not been deallocated. - * 2) Modify `doStuff()` (only) so to use a `std::unique_ptr` instead of a raw pointer. - * The final count should be `0`, and the memory leak solved. - * -------------------------------------------------------------------------------------------- - */ - - -// The class LargeObject emulates a large object. -// One should avoid to copy it, and rather use -// a pointer to pass it around. - -struct LargeObject { - - std::array data ; - - // So to check for some potential memory leak, - // we count the constructions and destructions - inline static std::size_t count = 0; - LargeObject() { count++ ; } - ~LargeObject() { count-- ; } - -} ; - -// A function to do something with a large object. -// Here we simulate that an error happens. - -void changeLargeObject( LargeObject & object ) { - - object.data[0] = 1. ; - throw std::invalid_argument("Error when changing object data.") ; - -} - -// Often, data are owned by one entity, and merely used by others. -// In this case, we hand the data to changeLargeObject(), -// and unfortunately, something goes wrong... - -void doStuff() { - - // MAKE YOUR CHANGES IN THIS FUNCTION - - auto obj = new LargeObject ; - changeLargeObject(*obj) ; - delete obj ; - -} - -int main() { - - try { - doStuff() ; - } catch ( const std::exception & e ) { - std::cerr<< "Terminated with exception: " << e.what() << "\n" ; - } - - std::cout<<"Leaked large objects: "< -#include -#include - - -/* -------------------------------------------------------------------------------------------- - * Collections of smart pointers. - * - * Often, one has to store pointers to objects in collections. - * Fix the memory leaks below by using `std::unique_ptr`. - * - * Tasks - * 1) Compile and run the code below. Notice that the final count is `10`, - * which is expected because the new objects are never deallocated. - * 2) Factory functions should better return smart pointers, - * because it clarifies who owns an object. - * Change the return type of the function `newLargeObject()` for a `std::unique_ptr()`. - * The vector should own the objects, so try to store them using smart pointers. - * Since the change function doesn't accept smart pointers, find a solution to pass the objects. - * Try to use `std::unique_ptr`, not `std::shared_ptr` ! - * -------------------------------------------------------------------------------------------- - */ - - -// The class LargeObject emulates a large object. -// One should avoid to copy it, and rather use -// a pointer to pass it around. - -struct LargeObject { - - std::array data ; - - // So to check for some potential memory leak, - // we count the constructions and destructions - inline static std::size_t count = 0; - LargeObject() { count++ ; } - ~LargeObject() { count-- ; } - -} ; - -// A factory function to create large objects. - -LargeObject * newLargeObject() { - - // MAKE YOUR CHANGES IN THIS FUNCTION - - auto object = new LargeObject() ; - // Imagine there is more setup steps of "object" here - // ... - return object ; - -} - -// A function to do something with the objects. -// Note that since we don't own the object, -// we don't need a smart pointer as argument. - -void changeLargeObject( LargeObject & object ) { - - object.data[0] = 1. ; - -} - -void doStuff() { - - // MAKE YOUR CHANGES IN THIS FUNCTION - - std::vector largeObjects ; - - for ( unsigned int i = 0 ; i < 10 ; ++i ) { - auto newObj = newLargeObject() ; - // ... additional newObj setup ... - largeObjects.push_back(newObj) ; - } - - for ( const auto & obj : largeObjects ) { - changeLargeObject(*obj) ; - } -} - -int main() { - - doStuff() ; - std::cout<<"Leaked large objects: "< -#include -#include -#include -#include - - -/* -------------------------------------------------------------------------------------------- - * Shared ownership. - * - * Most of the time, ownership can be solved by having one owner (with `std::unique_ptr`) and - * one or more observers (raw pointers or references). Sometimes, we need to truly share data, - * though. Here is an example of a completely messed up ownership model, which could be - * fixed using shared_ptr. - * - * Tasks - * 1) Verify the mess by repeatedly running it using such a command like: - * `while true; do ./problem3 ; done` - * You should notice that the program regularly leaks. - * 2) Fix the ownership model using `std::shared_ptr` ! - * - Convert the vectors to holding `std::shared_ptr`. - * - Fix the arguments of the functions. - * 3) Speed optimisation: make sure that you don't create & destroy useless `std::shared_ptr`, - * which is slow, for example in the for loop of `doStuff()` and when - * calling `changeLargeObject()`. - * -------------------------------------------------------------------------------------------- - */ - - -// The class LargeObject emulates a large object. -// One should avoid to copy it, and rather use -// a pointer to pass it around. - -struct LargeObject { - - std::array data ; - - // So to check for some potential memory leak, - // we count the constructions and destructions - inline static std::size_t count = 0; - LargeObject() { count++ ; } - ~LargeObject() { count-- ; } - -} ; - -// This removes an element from a non-owning vector, -// in a random place. Such elements can by known in -// several vectors, so they must not be deleted. - -void removeRandom( std::vector & collection, std::default_random_engine & engine ) { - - // MAKE YOUR CHANGES IN THIS FUNCTION - - auto pos = collection.begin() + engine() % collection.size() ; - collection.erase(pos); - -} - -// A function to do something with a large object. -// Note that since we don't own the object, -// we don't need a smart pointer as argument. - -void changeLargeObject( LargeObject & object ) { - - object.data[0] = 1. ; - -} - -// Global stuff: we have pointers to objects duplicated in two different collections. -// We work a bit with the collections, and then we try to clean up without neither -// memory leak nor segmentation fault. Without a shared ownership model, this becomes a mess. - -void doStuff() { - - // MAKE YOUR CHANGES IN THIS FUNCTION - - // Prepare a non deterministic random engine - - std::random_device device ; - std::default_random_engine engine(device()) ; - - // Original collection - - std::vector objVector(10); - for ( auto & ptr : objVector ) { - ptr = new LargeObject(); - } - - // Let's copy the whole collection - - auto objVectorCopy(objVector); - - // Random work with the objects - - removeRandom(objVector,engine); - removeRandom(objVectorCopy,engine); - removeRandom(objVectorCopy,engine); - // ... - for (auto objPtr : objVector ) { - changeLargeObject(*objPtr) ; - } - - // ONCE YOU FIXED CODE ABOVE WITH SHARED POINTERS - // THE UGLY CODE BELOW SHOULD BECOME UNNECESSARY - - for ( auto objPtr : objVector ) { - delete objPtr ; - } - for ( auto objPtr : objVectorCopy ) { - // If the element is in the original collection, it was already deleted. - if (std::find(objVector.begin(), objVector.end(), objPtr) == objVector.end()) { - delete objPtr; - } - } - -} - -int main() { - - doStuff() ; - std::cout<<"Leaked large objects: "< -#include -#include - - -/* -------------------------------------------------------------------------------------------- - * Smart pointers as class members. - * - * Class members that are pointers can quickly become a problem. - * Firstly, if only raw pointers are used, the intended ownership is unclear. - * Secondly, it's easy to overlook that a member has to be deleted. - * Thirdly, pointer members usually require you to implement copy or move constructors - * and assignment operators (--> rule of 3, rule of 5). - * Since C++-11, one can solve a few of those problems using smart pointers. - * - * The class "Owner" owns some data, but it is broken. If you copy it like in - * doStuff(), you have two pointers pointing to the same data, but both instances - * think that they own the data. - * - * Tasks - * 1) It likely crashes. Verify this. You can also try running `valgrind ./problem4`, - * it should give you some hints as to what's happening. - * 2) Fix the Owner class by using a `std::shared_ptr` for its data, which we can - * copy as much as we want. Run the fixed program. - * Note: Once `std::shared_ptr` is in use, you can also use the default destructor. - * - * -------------------------------------------------------------------------------------------- - */ - -struct LargeObject { - - std::array data ; - -} ; - -class Owner { - - // MAKE YOUR CHANGES IN THIS CLASS - - public: - - Owner() : _largeObject( new LargeObject() ) {} - LargeObject * getLargeObject() { return _largeObject ; } - ~Owner() { delete _largeObject ; } - - private: - - LargeObject * _largeObject ; - -} ; - -void doStuff() { - - std::vector owners ; - - for ( int i = 0 ; i < 5 ; ++i ) { - Owner owner ; - // ... additional owner setup ... - owners.push_back(owner) ; - } - - /* Now we have a problem: - * We created Owner instances on the stack, and copied them into the vector. - * When the instances on the stack are destroyed, the memory is deallocated. - * All copies in the vector now point to the deallocated memory! - * We could fix this using copy constructors (but we don't want to copy the data), - * using move semantics or using shared_ptr. - * Here, we want to go for shared_ptr. - */ - -} - -int main() { - - doStuff() ; - -} diff --git a/exercises/smartPointers/problem5.cpp b/exercises/smartPointers/problem5.cpp deleted file mode 100644 index 8a6f9ea4..00000000 --- a/exercises/smartPointers/problem5.cpp +++ /dev/null @@ -1,113 +0,0 @@ - - -#include -#include -#include -#include - - -/* -------------------------------------------------------------------------------------------- - * Weak pointers. - * - * Let's construct some `std::weak_ptr` so to observe some `std::shared_ptr`. - * This weak pointers can be used to retreive the object pointed by the corresponding `std::shared_ptr`, - * but it does not increase the reference count of the objects, and does not prevent - * the deletion of the underlying objects if all shared pointers go out of scope. - * To *use* the observed data, one has to create a `std::shared_ptr` from the `std::weak_ptr`, - * so that it is guaranteed that the underlying object is alive. - * - * In our case, the `Observer` class wants to act on the data of the `Owner`, - * but it doesn't need to own it. To do this, we use a weak pointer. - * - * Tasks - * 1) Investigate the crash. Optionally use a debugger, run in valgrind, - * compile with -fsanitize=address ... - * 2) Rewrite the interface of Owner::getData() such that the observer can see the - * `std::shared_ptr` pointing to the large object. - * Review the class `Observer` such that it stores a `std::weak pointer`. - * In `setValue`and `getValue`, access the weak pointer, and use the data *only* if the memory is still alive. - * Note: What you need is weak_ptr::lock(). Check out the documentation and the example at the bottom: - * https://en.cppreference.com/w/cpp/memory/weak_ptr/lock - * - * -------------------------------------------------------------------------------------------- - */ - -struct LargeObject { - - std::array data ; - -} ; - -class Owner { - - // SOME CHANGES NEEDED IN THIS CLASS - - public: - - Owner() : _largeObject( new LargeObject() ) {} - LargeObject * getLargeObject() const { return _largeObject.get() ; } - - private: - - std::shared_ptr _largeObject ; - -} ; - -class Observer { - - // SOME CHANGES NEEDED IN THIS CLASS - - public: - - Observer( const Owner & owner ) : _largeObject(owner.getLargeObject()) {} - - void setValue( double v ) { - if (_largeObject) { _largeObject->data[0] = v ; } - else { _largeObject->data[0] = 0. ; } - } - - double getValue() const { - if (_largeObject) { return _largeObject->data[0] ; } - else { return -1. ; } - } - - private: - - LargeObject * _largeObject ; - -} ; - -void doStuff() { - - // Owners and observers - - std::vector owners(5) ; - std::vector observers ; - for ( auto & owner : owners ) { - observers.emplace_back(owner) ; - } - - // Write through observers - - for ( auto & observer : observers ) { - observer.setValue(1.) ; - } - - // Let's destroy the 2 last owners - - owners.resize(3) ; - - // Read through observers - - std::cout << "Values:"; - for ( auto const & observer : observers ) { - std::cout<<" "< -#include -#include - -struct LargeObject { - - std::array data ; - - // So to check for some potential memory leak, - // we count the constructions and destructions - inline static std::size_t count = 0 ; - LargeObject() { count++ ; } - ~LargeObject() { count-- ; } - -} ; - -void changeLargeObject( LargeObject & object ) { - - object.data[0] = 1. ; - throw std::invalid_argument("Error when changing object data.") ; - -} - -void doStuff() { - - auto obj = std::make_unique() ; - changeLargeObject(*obj) ; - -} - -int main() { - - try { - doStuff() ; - } catch ( const std::exception & e ) { - std::cerr<< "Terminated with exception: " << e.what() << "\n" ; - } - - std::cout<<"Leaked large objects: "< -#include -#include -#include - - -struct LargeObject { - - std::array data ; - - // So to check for some potential memory leak, - // we count the constructions and destructions - inline static std::size_t count = 0 ; - LargeObject() { count++ ; } - ~LargeObject() { count-- ; } - -} ; - -std::unique_ptr newLargeObject() { - - auto object = std::make_unique() ; - // Imagine there is more setup steps of "object" here - // ... - return object ; -} - -void changeLargeObject( LargeObject & object ) { - - object.data[0] = 1. ; - -} - -void doStuff() { - - std::vector> largeObjects ; - - for ( unsigned int i = 0 ; i < 10 ; ++i ) { - largeObjects.push_back(newLargeObject()); - // ... additional largeObjects.back() setup ... - - // Alternatively, when the object is ready, - // one can "give up" newObj - // by moving it into the vector. - // auto newObj = createLargeObject() ; - // ... additional newObj setup ... - // largeObjects.push_back(std::move(newObj)); - - } - - for (const auto& obj : largeObjects) { - changeLargeObject(*obj); - } -} - -int main() { - doStuff() ; - std::cout<<"Leaked large objects: "< -#include -#include -#include -#include -#include - -struct LargeObject { - - std::array data ; - - // So to check for some potential memory leak, - // we count the constructions and destructions - inline static std::size_t count = 0 ; - LargeObject() { count++ ; } - ~LargeObject() { count-- ; } - -} ; - -void removeRandom(std::vector>& collection, std::default_random_engine & engine) { - - auto pos = collection.begin() + engine() % collection.size(); - collection.erase(pos); - -} - -void changeLargeObject( LargeObject & object ) { - - object.data[0] = 1. ; - -} - -void doStuff() { - - // Prepare a non deterministic random engine - - std::random_device device ; - std::default_random_engine engine(device()) ; - - // Original collection - - std::vector> objVector(10); - for ( auto & ptr : objVector ) { - ptr = std::make_shared(); - } - - // Less copies : - // std::vector> objVector ; - // objVector.reserve(10); - // for ( unsigned int i = 0 ; i < 10 ; ++i ) { - // objVector.emplace_back(new LargeObject()) ; - // } - - // Let's copy the whole collection - - auto objVectorCopy(objVector); - - // Random work with the objects - - removeRandom(objVector,engine); - removeRandom(objVectorCopy,engine); - removeRandom(objVectorCopy,engine); - // ... - // ... - for ( auto const & objPtr : objVector ) { - changeLargeObject(*objPtr) ; - } - -} - -int main() { - - doStuff() ; - std::cout<<"Leaked large objects: "< -#include -#include -#include - - -struct LargeObject { - - std::array data ; - -} ; - -class Owner { - - public: - - Owner() : _largeObject( new LargeObject() ) {} - LargeObject * getLargeObject() const { return _largeObject.get() ; } - - private: - - std::shared_ptr _largeObject ; - -} ; - -void doStuff() { - - std::vector owners ; - - for ( int i = 0 ; i < 5 ; ++i ) { - Owner owner ; - // ... additional owner setup ... - owners.push_back(owner) ; - } -} - -int main() { - - doStuff() ; - -} diff --git a/exercises/smartPointers/solution/problem5.sol.cpp b/exercises/smartPointers/solution/problem5.sol.cpp deleted file mode 100644 index 154af2fc..00000000 --- a/exercises/smartPointers/solution/problem5.sol.cpp +++ /dev/null @@ -1,83 +0,0 @@ - -#include -#include -#include -#include - -struct LargeObject { - - std::array data ; - -} ; - -class Owner { - - public: - - Owner() : _largeObject( new LargeObject() ) {} - auto getLargeObject() const { return _largeObject ; } - - private: - - std::shared_ptr _largeObject ; - -} ; - -class Observer { - - public: - - Observer( const Owner & owner ) : _largeObject(owner.getLargeObject()) {} - - void setValue( double v ) { - std::shared_ptr wptr = _largeObject.lock(); - if (wptr) { wptr->data[0] = v ; } - else { wptr->data[0] = 0. ; } - } - - double getValue() const { - std::shared_ptr wptr = _largeObject.lock(); - if (wptr) { return wptr->data[0] ; } - else { return -1. ; } - } - - private: - - std::weak_ptr _largeObject ; - -} ; - -void doStuff() { - - // Owners and observers - - std::vector owners(5) ; - std::vector observers ; - for ( auto & owner : owners ) { - observers.emplace_back(owner) ; - } - - // Write through observers - - for ( auto & observer : observers ) { - observer.setValue(1.) ; - } - - // Let's destroy the 2 last owners - - owners.resize(3) ; - - // Read through observers - - std::cout << "Values:"; - for ( auto const & observer : observers ) { - std::cout<<" "< - -Here we explore: -- how <=> are == differing. -- when to use or not to use the compiler default implementations. - -## Prerequisites - -* Being able to overload an operator, especially `==` and `<=>`. - -## Instructions - -0. Compile and run the program. We are not fully happy with the default implementation of `<=>` for our `Complex` class, which considers 1|2 as smaller than 1.5|1.5. -1. Modify it so that the ordering is based on the norm of the complexes. -2. Because you do not use any more the default implementation of `<=>` you had to provide also an implementation for `==`. What happens if you deduce it from `<=>` (using `(((*this)<=>other)==0)`) ? -3. Try to restore the default implementation for `==` only. diff --git a/exercises/spaceship/solution/spaceship.sol.cpp b/exercises/spaceship/solution/spaceship.sol.cpp deleted file mode 100644 index 8e209c70..00000000 --- a/exercises/spaceship/solution/spaceship.sol.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include -#include - -struct Complex - { - double r, i ; - double norm() const { return std::sqrt(r*r+i*i) ; } - auto operator<=>( Complex const & other ) const - { return (norm()<=>other.norm()) ; } - bool operator==( Complex const & other ) const = default ; - } ; - -std::ostream & operator<<( std::ostream & os, std::partial_ordering cmp ) - { return (os<<'<'<<(cmp<0)<<'|'<<(cmp==0)<<'|'<<(cmp>0)<<'>') ; } - -std::ostream & operator<<( std::ostream & os, Complex const & c ) - { return (os< -void compare( T lhs, T rhs ) - { - std::cout< "<rhs)<({ 1., 2. },{ 1.5, 1.5 }) ; - compare({ 1., 0. },{ 0., 1. }) ; - std::cout< -#include -#include - -/* - -We are not fully happy with the default implementation of `<=>`for our `Complex` class below. -1. Modify it so that the ordering is based on the norm of the complexes. -2. Because you do not use any more the default implementation of `<=>` you had to provide also an implementation for `==`. What happens if you deduce it from `<=>` (using `(((*this)<=>other)==0)`) ? -3. Try to restore the default implementation for `==` only. - -*/ - -struct Complex - { - double r, i ; - double norm() const { return std::sqrt(r*r+i*i) ; } - auto operator<=>( Complex const & other ) const = default ; - } ; - -std::ostream & operator<<( std::ostream & os, std::partial_ordering cmp ) - { return (os<<'<'<<(cmp<0)<<'|'<<(cmp==0)<<'|'<<(cmp>0)<<'>') ; } - -std::ostream & operator<<( std::ostream & os, Complex const & c ) - { return (os< -void compare( T lhs, T rhs ) - { - std::cout< "<rhs)<({ 1., 2. },{ 1.5, 1.5 }) ; - compare({ 1., 0. },{ 0., 1. }) ; - std::cout< -#include - -template -class Complex_t { -public: - Complex_t() = default; - Complex_t(T r, T i) : m_r(r), m_i(i) {} - - T real() const { return m_r; } - T imaginary() const { return m_i; } - - T norm_sqr() const { - return m_r * m_r + m_i * m_i; - } - - T norm() const { - return std::sqrt(norm_sqr()); - } - - Complex_t& operator+=(const Complex_t& other) { - m_r += other.m_r; - m_i += other.m_i; - return *this; - } - - Complex_t& operator-=(const Complex_t& other) { - m_r -= other.m_r; - m_i -= other.m_i; - return *this; - } - - Complex_t& operator*=(const Complex_t& other) { - const auto r = m_r * other.m_r - m_i * other.m_i; - const auto i = m_r * other.m_i + m_i * other.m_r; - m_r = r; - m_i = i; - return *this; - } - - Complex_t& operator*=(T factor) { - m_r *= factor; - m_i *= factor; - return *this; - } - - Complex_t& operator/=(const Complex_t& other) { - const T ns = other.norm_sqr(); - const auto r = (m_r * other.m_r + m_i * other.m_i) / ns; - const auto i = (m_i * other.m_r - m_r * other.m_i) / ns; - m_r = r; - m_i = i; - return *this; - } - - Complex_t& operator/=(T divisor) { - m_r /= divisor; - m_i /= divisor; - return *this; - } - - friend Complex_t operator+(Complex_t a, const Complex_t& b) { - return a += b; - } - - friend Complex_t operator-(Complex_t a, const Complex_t& b) { - return a -= b; - } - - friend Complex_t operator*(Complex_t a, const Complex_t& b) { - return a *= b; - } - - friend Complex_t operator*(Complex_t c, T factor) { - return c *= factor; - } - - friend Complex_t operator*(T factor, Complex_t c) { - return c *= factor; - } - - friend Complex_t operator/(Complex_t a, Complex_t b) { - return a /= b; - } - - friend Complex_t operator/(Complex_t c, T divisor) { - return c /= divisor; - } - - friend Complex_t operator/(T dividend, const Complex_t& c) { - return Complex_t(dividend, 0) / c; - } - - friend bool operator==(const Complex_t& a, const Complex_t& b) { - return a.m_r == b.m_r && a.m_i == b.m_i; - } - - friend bool operator<(const Complex_t& a, const Complex_t& b) { - return a.norm_sqr() < b.norm_sqr(); - } - - friend std::ostream& operator<<(std::ostream& os, const Complex_t& c) { - return os << "(" << c.real() << ", " << c.imaginary() << ")"; - } - -private: - T m_r{}, m_i{}; -}; - -using Complex = Complex_t<>; diff --git a/exercises/stl/Makefile b/exercises/stl/Makefile deleted file mode 100644 index 28431845..00000000 --- a/exercises/stl/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -all: randomize.nostl randomize -solution: randomize.sol - -clean: - rm -f *o randomize *~ randomize.sol randomize.nostl - -randomize : randomize.cpp - ${CXX} -std=c++17 -g -O0 -Wall -Wextra -L. -o $@ $< - -randomize.nostl : randomize.nostl.cpp - ${CXX} -std=c++17 -g -O0 -Wall -Wextra -L. -o $@ $< - -randomize.sol : solution/randomize.sol.cpp - ${CXX} -std=c++17 -g -O0 -Wall -Wextra -I. -L. -o $@ $< diff --git a/exercises/stl/README.md b/exercises/stl/README.md deleted file mode 100644 index c77385c8..00000000 --- a/exercises/stl/README.md +++ /dev/null @@ -1,9 +0,0 @@ - -## Instructions - -* look at the non STL code in randomize.nostl.cpp - * it creates a vector of ints at regular intervals - * it randomizes them - * it computes differences between consecutive ints and the mean and variance of it -* open randomize.cpp and complete the “translation” to the STL -* see how easy it is to reuse the code with complex numbers, by calling `compute` with objects of type `Complex` diff --git a/exercises/stl/randomize.cpp b/exercises/stl/randomize.cpp deleted file mode 100644 index a43b287e..00000000 --- a/exercises/stl/randomize.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include -#include -#include -#include -#include -#include "Complex.hpp" - -template -void compute(int len, T initial, T step) { - // allocate vectors - std::vector v(len+1), diffs(len+1); - - // fill and randomize v - std::generate(, , [](...) { ...; }); - std::shuffle(..., std::default_random_engine{}); - - // compute differences - std::adjacent_difference(...); - - // compute standard deviation of all differences - const T sum = std::reduce(...); - const T sumsq = std::accumulate(..., [](...) { ...; }); - const T mean = sum/len; - const T variance = sumsq/len - mean*mean; - - std::cout << "Range = [" << initial << ", " << step*len << "]\n" - << "Mean = " << mean << '\n' - << "Variance = " << variance << '\n'; -} - -int main() { - compute(1000, 0.0, 7.0); - // call compute here with Complex -} diff --git a/exercises/stl/randomize.nostl.cpp b/exercises/stl/randomize.nostl.cpp deleted file mode 100644 index 49ab30ac..00000000 --- a/exercises/stl/randomize.nostl.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include -#include -#include - -constexpr auto LEN = 1000; -constexpr auto STEP = 7; - -void randomize(int* v, unsigned int len) { - // we randomize via len random inversions - for (unsigned int i = 0; i < len; i++) { - int a = rand()%len; - int b = rand()%len; - int mem = v[a]; - v[a] = v[b]; - v[b] = mem; - } -} - -int main() { - // create vector - int *v = new int[LEN+1]; - for (unsigned int i = 0; i <= LEN; i++) v[i] = i*STEP; - - // randomize it - randomize(v, LEN+1); - - // compute diffs - int *diffs = new int[LEN]; - for (unsigned int i = 0; i < LEN; i++) - diffs[i] = v[i+1] - v[i]; - - // compute standard deviation of it - float sum = 0; - float sumsq = 0; - for (unsigned int i = 0; i < LEN; i ++) { - sum += diffs[i]; - sumsq += diffs[i]*diffs[i]; - } - float mean = sum/LEN; - float stddev = std::sqrt(sumsq/LEN - mean*mean) ; - std::cout << "Range = [0, " << STEP*LEN << "]\n" - << "Mean = " << mean - << "\nStdDev = " << stddev << '\n'; - - delete[] v; - delete[] diffs; -} diff --git a/exercises/stl/solution/randomize.sol.cpp b/exercises/stl/solution/randomize.sol.cpp deleted file mode 100644 index 1713f128..00000000 --- a/exercises/stl/solution/randomize.sol.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include -#include -#include -#include -#include -#include "Complex.hpp" - -template -struct Generator { - T m_value, m_step; - Generator(T initial, T step):m_value(initial), m_step(step){}; - T operator()() { - T cur_value = m_value; - m_value += m_step; - return cur_value; - } -}; - -template -struct sumsquare { - T operator()(const T& s, const T& a) { return s + a * a; }; -}; - -template -void compute(int len, T initial, T step) { - // allocate vectors - std::vector v(len+1), diffs(len+1); - - // fill and randomize v - std::generate(v.begin(), v.end(), Generator(initial, step)); - // Alternatively: - // std::generate(v.begin(), v.end(), [value = initial, step]() mutable { - // const T cur = value; - // value += step; - // return cur; - // }); - - std::shuffle(v.begin(), v.end(), std::default_random_engine{}); - - // compute differences - std::adjacent_difference(v.begin(), v.end(), diffs.begin()); - - // compute standard deviation of all differences. - // Note that the first element is just the original element itself, so we need to skip it. - const T sum = std::reduce(diffs.begin()+1, diffs.end()); - const T sumsq = std::accumulate(diffs.begin()+1, diffs.end(), T(), sumsquare()); - // Alternatively: - // const T sumsq = std::accumulate(diffs.begin()+1, diffs.end(), T(), - // [](const T& s, const T& a) { return s + a * a; }); - const T mean = sum/len; - const T variance = sumsq/len - mean*mean; - - std::cout << "Range = [" << initial << ", " << step*len << "]\n" - << "Mean = " << mean << '\n' - << "Variance = " << variance << '\n'; -} - -int main() { - compute(1000, 0.0, 7.0); - compute(1000, Complex(0,0), Complex(1,2)); -} diff --git a/exercises/templates/.gitignore b/exercises/templates/.gitignore deleted file mode 100644 index f36832f3..00000000 --- a/exercises/templates/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -playwithsort -playwithsort.sol diff --git a/exercises/templates/CMakeLists.txt b/exercises/templates/CMakeLists.txt deleted file mode 100644 index 928ffe63..00000000 --- a/exercises/templates/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -# Set up the project. -cmake_minimum_required( VERSION 3.12 ) -project( templates LANGUAGES CXX ) - -# Set up the compilation environment. -include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) -set(CMAKE_CXX_STANDARD 20) - -# Create the user's executable. -add_executable( playwithsort "Complex.hpp" "OrderedVector.hpp" "playwithsort.cpp" ) - -# Create the "solution executable". -add_executable( playwithsort.sol EXCLUDE_FROM_ALL - "Complex.hpp" "solution/OrderedVector.sol.hpp" "solution/playwithsort.sol.cpp" ) -target_include_directories( playwithsort.sol PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}" ) -add_dependencies( solution playwithsort.sol ) diff --git a/exercises/templates/Complex.hpp b/exercises/templates/Complex.hpp deleted file mode 100644 index 891a9076..00000000 --- a/exercises/templates/Complex.hpp +++ /dev/null @@ -1,54 +0,0 @@ -#include - -template -class Complex_t { -public: - Complex_t() = default; - - Complex_t(T r, T i) - : m_r(r), m_i(i) {} - - T real() const { return m_r; } - - T imaginary() const { return m_i; } - - Complex_t operator+(const Complex_t& other) const { - return Complex_t(m_r + other.m_r, m_i + other.m_i); - } - - Complex_t operator-(const Complex_t& other) const { - return Complex_t(m_r - other.m_r, m_i - other.m_i); - } - - Complex_t operator*(const Complex_t& other) const { - return Complex_t(m_r * other.m_r - m_i * other.m_i, - m_r * other.m_i + m_i * other.m_r); - } - - Complex_t operator*(const T factor) const { - return Complex_t(m_r * factor, m_i * factor); - } - - Complex_t operator/(const T dividend) const { - return Complex_t(m_r / dividend, m_i / dividend); - } - - Complex_t& operator+=(const Complex_t& other) { - m_r += other.m_r; - m_i += other.m_i; - return *this; - } - - friend bool operator<(const Complex_t& a, const Complex_t& b) { - return (a.m_r * a.m_r + a.m_i * a.m_i) < (b.m_r * b.m_r + b.m_i * b.m_i); - } - - friend std::ostream& operator<<(std::ostream& os, const Complex_t& c) { - return os << "(" << c.real() << ", " << c.imaginary() << ")"; - } - -private: - T m_r{}, m_i{}; -}; - -using Complex = Complex_t<>; diff --git a/exercises/templates/Makefile b/exercises/templates/Makefile deleted file mode 100644 index 7971fdc6..00000000 --- a/exercises/templates/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -all: playwithsort -solution: playwithsort.sol - -clean: - rm -f *o *so playwithsort *~ playwithsort.sol - -playwithsort : playwithsort.cpp OrderedVector.hpp Complex.hpp - $(CXX) -std=c++20 -g -O0 -Wall -Wextra -o $@ $< - -playwithsort.sol : solution/playwithsort.sol.cpp solution/OrderedVector.sol.hpp Complex.hpp - $(CXX) -std=c++20 -g -O0 -Wall -Wextra -I. -o $@ $< diff --git a/exercises/templates/OrderedVector.hpp b/exercises/templates/OrderedVector.hpp deleted file mode 100644 index f9a8bfa8..00000000 --- a/exercises/templates/OrderedVector.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include - -template -class OrderedVector { -public: - OrderedVector(unsigned int maxLen) - : m_maxLen(maxLen), m_data(std::make_unique(m_maxLen)) { } - - OrderedVector(const OrderedVector&) = delete; - OrderedVector& operator=(const OrderedVector&) = delete; - - bool add(ElementType value); - - ElementType& at(unsigned int n) { - if (n >= m_len) { - throw std::out_of_range("too big"); - } - return m_data[n]; - } - - ElementType& operator[](unsigned int n) { - return at(n); - } - -private: - unsigned int m_len = 0; - unsigned int m_maxLen; - std::unique_ptr m_data; -}; - -template -bool OrderedVector::add(ElementType value) { - if (m_len >= m_maxLen) { - return false; - } - // find insertion point - unsigned int insertIndex = 0; - while (insertIndex < m_len && m_data[insertIndex] < value) - insertIndex++; - // move end of vector - unsigned int index = m_len; - while (index > insertIndex) { - m_data[index] = m_data[index-1]; - index--; - } - // actual insertion - m_data[index] = value; - m_len++; - return true; -} diff --git a/exercises/templates/README.md b/exercises/templates/README.md deleted file mode 100644 index 0b1289d0..00000000 --- a/exercises/templates/README.md +++ /dev/null @@ -1,22 +0,0 @@ - -## Instructions - -Beginners -* Look at the `OrderedVector` code -* Compile and run `playwithsort.cpp`. See the printed ordering -* Inspect the `Complex_t` class template and the alias `Complex`. - Then, in `playwithsort.cpp`, create a third `OrderedVector` with `Complex` as element type, - fill it with some complex values and print the vector. - No modifications to `Complex_t` and `OrderedVector` are required! - -Intermediary -* Extend `OrderedVector` to allow to customize the ordering via an additional template parameter. - This template parameter should be a comparison object that defaults to `std::less`. - Hint: - You have to customize the loop in OrderedVector::add where the insertion point is defined. -* Try ordering by reversed strings (from the last letter, don't change the strings!) -* Test order based on [Manhattan distance](https://en.wikipedia.org/wiki/Taxicab_geometry) with complex type - -Bonus -* Check the implementation of `Complex` -* Try ordering complex of complex diff --git a/exercises/templates/playwithsort.cpp b/exercises/templates/playwithsort.cpp deleted file mode 100644 index 3238a45d..00000000 --- a/exercises/templates/playwithsort.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "OrderedVector.hpp" -#include "Complex.hpp" -#include -#include -#include -#include - -struct ReverseStringLess { - bool operator() (const std::string &s, const std::string &t) const { - // TODO: compare reversed strings - // hint: you can use: - // - std::views::reverse - // - std::ranges::lexicographical_compare - // or, if your compiler does not support those yet, - // take copies of the strings and reverse them using std::reverse - return s < t; - } -}; - -int main() { - std::cout << "Integer\n"; - OrderedVector v(10); - for (int i = 10; i > 0; i--) - v.add(i); - for (int i = 0; i < 10; i++) - std::cout << v[i] << " "; - std::cout << "\n\n"; - - std::cout << "String\n"; - OrderedVector vs(5); - vs.add(std::string("one")); - vs.add(std::string("two")); - vs.add(std::string("three")); - vs.add(std::string("four")); - vs.add(std::string("five")); - for (int i = 0; i < 5; i++) - std::cout << vs[i] << " "; - std::cout << "\n\n"; - - // TODO: Demonstrate OrderedVector with Complex as element type similar to above - - - // TODO: Extend OrderedVector to allow to customize the ordering via an additional template paramter. - // Then, demonstrate the new functionality by ordering an OrderedVector, - // where the strings are compared starting at their last letters. - - - // TODO: Order an OrderedVector of Complex based on the Manhattan distance - - -} diff --git a/exercises/templates/solution/OrderedVector.sol.hpp b/exercises/templates/solution/OrderedVector.sol.hpp deleted file mode 100644 index a7b0f0ef..00000000 --- a/exercises/templates/solution/OrderedVector.sol.hpp +++ /dev/null @@ -1,53 +0,0 @@ -#include -#include -#include - -template> -class OrderedVector { -public: - OrderedVector(unsigned int maxLen) - : m_maxLen(maxLen), m_data(std::make_unique(m_maxLen)) { } - - OrderedVector(const OrderedVector&) = delete; - OrderedVector& operator=(const OrderedVector&) = delete; - - bool add(ElementType value); - - ElementType& at(unsigned int n) { - if (n >= m_len) { - throw std::out_of_range("too big"); - } - return m_data[n]; - } - - ElementType& operator[](unsigned int n) { - return at(n); - } - -private: - unsigned int m_len = 0; - unsigned int m_maxLen; - Compare m_compare; - std::unique_ptr m_data; -}; - -template -bool OrderedVector::add(ElementType value) { - if (m_len >= m_maxLen) { - return false; - } - // find insertion point - unsigned int insertIndex = 0; - while (insertIndex < m_len && m_compare(m_data[insertIndex], value)) - insertIndex++; - // move end of vector - unsigned int index = m_len; - while (index > insertIndex) { - m_data[index] = m_data[index-1]; - index--; - } - // actual insertion - m_data[index] = value; - m_len++; - return true; -} diff --git a/exercises/templates/solution/playwithsort.sol.cpp b/exercises/templates/solution/playwithsort.sol.cpp deleted file mode 100644 index b49d8f8e..00000000 --- a/exercises/templates/solution/playwithsort.sol.cpp +++ /dev/null @@ -1,108 +0,0 @@ -#include "OrderedVector.sol.hpp" -#include "Complex.hpp" -#include -#include -#include -#include -#include - -struct ReverseStringLess { - bool operator() (const std::string &s, const std::string &t) const { - // __cpp_lib_ranges is a feature test macro. - // We can use those to check what features a C++ compiler supports. -#ifdef __cpp_lib_ranges - return std::ranges::lexicographical_compare(std::views::reverse(s), std::views::reverse(t)); -#else - std::string rs = s; - std::string rt = t; - std::reverse(rs.begin(), rs.end()); - std::reverse(rt.begin(), rt.end()); - return rs < rt; -#endif - } -}; - -struct ManhattanLess { - bool operator() (const Complex &a, const Complex &b) const { - return std::abs(a.real()) + std::abs(a.imaginary()) < std::abs(b.real()) + std::abs(b.imaginary()); - } -}; - -int main() { - std::cout << "Integer\n"; - OrderedVector v(10); - for (int i = 10; i > 0; i--) - v.add(i); - for (int i = 0; i < 10; i++) - std::cout << v[i] << " "; - std::cout << "\n\n"; - - std::cout << "String\n"; - OrderedVector vs(5); - vs.add(std::string("one")); - vs.add(std::string("two")); - vs.add(std::string("three")); - vs.add(std::string("four")); - vs.add(std::string("five")); - for (int i = 0; i < 5; i++) - std::cout << vs[i] << " "; - std::cout << "\n\n"; - - std::cout << "Complex\n"; - OrderedVector vc(5); - vc.add(Complex(1.5,0.0)); - vc.add(Complex(1.0,1.0)); - vc.add(Complex(-1.0,0.0)); - vc.add(Complex(1.0,2.0)); - vc.add(Complex(0.0,0.0)); - for (int i = 0; i < 5; i++) - std::cout << vc[i] << " "; - std::cout << "\n\n"; - - std::cout << "String\n"; - OrderedVector vsr(5); - vsr.add(std::string("one")); - vsr.add(std::string("two")); - vsr.add(std::string("three")); - vsr.add(std::string("four")); - vsr.add(std::string("five")); - for (int i = 0; i < 5; i++) - std::cout << vsr[i] << " "; - std::cout << "\n\n"; - - std::cout << "Complex with manhatan order\n"; - OrderedVector vcm(5); - vcm.add(Complex(1.5,0.0)); - vcm.add(Complex(1.0,1.0)); - vcm.add(Complex(-1.0,0.0)); - vcm.add(Complex(1.0,2.0)); - vcm.add(Complex(0.0,0.0)); - for (int i = 0; i < 5; i++) - std::cout << vcm[i] << " "; - std::cout << "\n\n"; - - std::cout << "Int Complex\n"; - using IComplex = Complex_t; - OrderedVector vci(5); - vci.add(IComplex(2,0)); - vci.add(IComplex(1,1)); - vci.add(IComplex(-1,0)); - vci.add(IComplex(1,2)); - vci.add(IComplex(0,0)); - for (int i = 0; i < 5; i++) - std::cout << vci[i] << " "; - std::cout << "\n\n"; - - std::cout << "Very Complex\n"; - using VComplex = Complex_t; - OrderedVector vcv(5); - vcv.add(VComplex(Complex(2,0),Complex(1,0))); - vcv.add(VComplex(Complex(2,0),Complex(0,2))); - vcv.add(VComplex(Complex(1,0),Complex(0,0))); - vcv.add(VComplex(Complex(0,1),Complex(1,0))); - vcv.add(VComplex(Complex(2,0),Complex(0,0))); - for (int i = 0; i < 5; i++) - std::cout << vcv[i] << " "; - std::cout << "\n\n"; - -} diff --git a/exercises/ubsan/README.md b/exercises/ubsan/README.md deleted file mode 100644 index b901ef7a..00000000 --- a/exercises/ubsan/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# Undefined Behaviour Sanitizer - -This directory contains a program that's full of evil bugs. Many of those would cause compiler warnings, -but the problems can easily be obscured by making the code slightly more complicated, e.g. by passing -pointers or indices through functions or similar. - -UBSan is a run-time tool, so it can catch these bugs even if the compilers don't emit warnings. -This should illustrate why every larger project should have a UBSan and a ASan build as part of -it Continuous Integration. - -## Instructions - -- Compile and run this program using a compiler invocation like - ` -g -std=c++17 -o undefinedBehaviour undefinedBehaviour.cpp` - -- You might see warnings depending on the compiler, but on most platforms the program runs without observable issues. - -- Recompile with "-fsanitize=undefined", and observe that almost every second line contains a serious bug. - NOTE: If this fails, your compiler does not support UBSan (yet). In this case, you can try to read the - program and catch the bugs, or continue with the next exercise. - -- Try to understand what's wrong. The solution contains a few comments what kind of bugs are hidden in the program. diff --git a/exercises/ubsan/solution/undefinedBehaviour.cpp b/exercises/ubsan/solution/undefinedBehaviour.cpp deleted file mode 100644 index 1101161d..00000000 --- a/exercises/ubsan/solution/undefinedBehaviour.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include - -// You don't need to change any code in these structs: -struct Base { - virtual void print() = 0; - virtual ~Base() {} -}; -struct Derived1 : public Base { - void print() override { - std::cout << "Derived1::print()\n"; - } -}; -struct Derived2 : public Base { - void print() override { - std::cout << "Derived2::print()\n"; - } -}; - - -/** - * *************** - * Instructions: - * *************** - * - * Compile and run this program using a compiler invocation like - * -g -std=c++17 -o undefinedBehaviour undefinedBehaviour.cpp - * - * You might see warnings depending on the compiler, but on most platforms the program runs without observable issues. - * Smart compilers will warn with most of these bugs, but the compilers can easily be deceived by hiding a nullptr in - * a variable, or passing it as a function argument or similar. - * - * Since UBSan does runtime checks, it will catch these errors even if they are obscured. - * Recompile with "-fsanitize=undefined", and observe that almost every second line contains a serious bug. - * Try to understand what's wrong. - */ - -int runTests() { - int arr[] = {1, 2, 3, 4}; - std::cout << "arr[4]=" << arr[4] << "\n"; // Array overrun - - unsigned int s = 1; - std::cout << "s << 33=" << (s << 33) << "\n"; // We cannot shift a type with 32 bits by 33 bits. - - int i = std::numeric_limits::max(); - std::cout << "i + 1 =" << i + 1 << "\n"; // Adding 1 to max int overflows to min int - - Derived1 d1; - Base & base = d1; - auto & d2 = static_cast(base); // Casting an original d1 to d2 is wrong - d2.print(); // Calling a function on a wrongly-cast object is wrong - - Derived2 * d2ptr = nullptr; - Derived2 & nullref = static_cast(*d2ptr); // Cannot bind references to a wrong address -} // Forgot to return a value - -int main() { - const auto result = runTests(); - return result; -} diff --git a/exercises/ubsan/undefinedBehaviour.cpp b/exercises/ubsan/undefinedBehaviour.cpp deleted file mode 100644 index d5926385..00000000 --- a/exercises/ubsan/undefinedBehaviour.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include - -// You don't need to change any code in these structs: -struct Base { - virtual void print() = 0; - virtual ~Base() {} -}; -struct Derived1 : public Base { - void print() override { - std::cout << "Derived1::print()\n"; - } -}; -struct Derived2 : public Base { - void print() override { - std::cout << "Derived2::print()\n"; - } -}; - - -/** - * *************** - * Instructions: - * *************** - * - * Compile and run this program using a compiler invocation like - * -g -std=c++17 -o undefinedBehaviour undefinedBehaviour.cpp - * - * You might see warnings depending on the compiler, but on most platforms the program runs without observable issues. - * Smart compilers will warn with most of these bugs, but the compilers can easily be deceived by hiding a nullptr in - * a variable, or passing it as a function argument or similar. - * - * Since UBSan does runtime checks, it will catch these errors even if they are obscured. - * Recompile with "-fsanitize=undefined", and observe that almost every second line contains a serious bug. - * Try to understand what's wrong. - */ - -int runTests() { - int arr[] = {1, 2, 3, 4}; - std::cout << "arr[4]=" << arr[4] << "\n"; - - unsigned int s = 1; - std::cout << "s << 33=" << (s << 33) << "\n"; - - int i = std::numeric_limits::max(); - std::cout << "i + 1 =" << i + 1 << "\n"; - - Derived1 d1; - Base & base = d1; - auto & d2 = static_cast(base); - d2.print(); - - Derived2 * d2ptr = nullptr; - Derived2 & nullref = static_cast(*d2ptr); -} - -int main() { - const auto result = runTests(); - return result; -} diff --git a/exercises/valgrind/.gitignore b/exercises/valgrind/.gitignore deleted file mode 100644 index 18ed3421..00000000 --- a/exercises/valgrind/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -debug -debug.sol diff --git a/exercises/valgrind/CMakeLists.txt b/exercises/valgrind/CMakeLists.txt deleted file mode 100644 index 80df4f13..00000000 --- a/exercises/valgrind/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -# Set up the project. -cmake_minimum_required( VERSION 3.12 ) -project( valgrind LANGUAGES CXX ) - -# Set up the compilation environment. -include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) - -# Create the user's executable. -add_executable( valgrind "debug.cpp" ) - -# Create the "solution executable". -add_executable( valgrind.sol EXCLUDE_FROM_ALL "solution/debug.sol.cpp" ) -add_dependencies( solution valgrind.sol ) diff --git a/exercises/valgrind/Makefile b/exercises/valgrind/Makefile deleted file mode 100644 index 077aadfa..00000000 --- a/exercises/valgrind/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -all: debug -solution: debug.sol - -clean: - rm -f *o debug *~ debug.sol core - -debug : debug.cpp - ${CXX} -std=c++17 -g -O0 -L. -o $@ $< - -debug.sol : solution/debug.sol.cpp - ${CXX} -std=c++17 -g -O0 -Wall -Wextra -L. -o $@ $< diff --git a/exercises/valgrind/README.md b/exercises/valgrind/README.md deleted file mode 100644 index 85b79570..00000000 --- a/exercises/valgrind/README.md +++ /dev/null @@ -1,7 +0,0 @@ - -## Instructions - -* compile, run, it shouldn't crash -* run with valgrind (`valgrind ./debug`) -* fix an out-of-bounds access -* check for memory leaks diff --git a/exercises/valgrind/debug.cpp b/exercises/valgrind/debug.cpp deleted file mode 100644 index eb7a917a..00000000 --- a/exercises/valgrind/debug.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include - -void swap(int* a, int* b) -{ - int c = *a; - *a = *b; - *b = c; -} - -void reverse(int* v, unsigned int len) -{ - for (unsigned int i = 0; i < (len + 1) / 2; i++) { - const int a = i; - const int b = len - i; - - swap(v + a, v + b); - } -} - -int* createAndFillVector(unsigned int len) -{ - auto v = new int[len]; - for (unsigned int i = 0; i < len; i++) { - v[i] = i; - } - return v; -} - -int main() -{ - constexpr auto arraySize = 100; - int* v = nullptr; - // create and reverse the vector of LEN numbers - v = createAndFillVector(arraySize); - reverse(v, arraySize); - - // check if the revert worked: - const bool isReversed = std::is_sorted(v, v + arraySize, std::greater {}); - std::cout << "Vector reversed successfully: " << std::boolalpha - << isReversed << "\n"; - - return isReversed ? 0 : 1; -} diff --git a/exercises/valgrind/solution/debug.sol.cpp b/exercises/valgrind/solution/debug.sol.cpp deleted file mode 100644 index 5676e620..00000000 --- a/exercises/valgrind/solution/debug.sol.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include - -void swap(int* a, int* b) -{ - int c = *a; - *a = *b; - *b = c; -} - -void reverse(int* v, unsigned int len) -{ - for (unsigned int i = 0; i < (len + 1) / 2; i++) { - const int a = i; - const int b = len - 1 - i; - - swap(v + a, v + b); - } -} - -int* createAndFillVector(unsigned int len) -{ - auto v = new int[len]; - for (unsigned int i = 0; i < len; i++) { - v[i] = i; - } - return v; -} - -int main() -{ - constexpr auto arraySize = 100; - int* v = nullptr; - // create and reverse the vector of LEN numbers - v = createAndFillVector(arraySize); - reverse(v, arraySize); - - // check if the revert worked: - const bool isReversed = std::is_sorted(v, v + arraySize, std::greater {}); - std::cout << "Vector reversed successfully: " << std::boolalpha - << isReversed << "\n"; - - delete[] v; - - return isReversed ? 0 : 1; -} diff --git a/exercises/variadic/.gitignore b/exercises/variadic/.gitignore deleted file mode 100644 index 711c49af..00000000 --- a/exercises/variadic/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -variadic -variadic.sol diff --git a/exercises/variadic/CMakeLists.txt b/exercises/variadic/CMakeLists.txt deleted file mode 100644 index d64e014e..00000000 --- a/exercises/variadic/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -# Set up the project. -cmake_minimum_required( VERSION 3.12 ) -project( variadic LANGUAGES CXX ) - -# Set up the compilation environment. -include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) -set(CMAKE_CXX_STANDARD 20) - -# Create the user's executable. -add_executable( variadic "variadic.cpp" ) - -# Create the "solution executable". -add_executable( variadic.sol EXCLUDE_FROM_ALL - "solution/variadic.sol.cpp" ) -add_dependencies( solution variadic.sol ) diff --git a/exercises/variadic/Makefile b/exercises/variadic/Makefile deleted file mode 100644 index 31d7f0d7..00000000 --- a/exercises/variadic/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -all: variadic -solution: variadic.sol - -clean: - rm -f *o variadic *~ variadic.sol - -variadic : variadic.cpp - $(CXX) -std=c++20 -g -O0 -Wall -Wextra -o $@ $< - -variadic.sol : solution/variadic.sol.cpp - $(CXX) -std=c++20 -g -O0 -Wall -Wextra -o $@ $< diff --git a/exercises/variadic/README.md b/exercises/variadic/README.md deleted file mode 100644 index 31c4fc74..00000000 --- a/exercises/variadic/README.md +++ /dev/null @@ -1,22 +0,0 @@ - -## Instructions - -In this exercise, we will take the `tuple` implementation from the slides -and extend it step by step to make the example code in `main` compile. - -Feel free to comment out parts of main to test parts of your implementation sooner. -All instructions are given in more detail in the source code as well, especially inside `main`. - -This example neglects const correctness so there is less code to write. -Making it const correct would require adding several overloads with almost the same code as the non-const version. -You can try this is a bonus exercise at the end! - -1. make `tuple` default-constructible -2. avoid implicit construction from a single value -3. write `head(tuple)`, which returns the first element of a tuple -4. implement `get(tuple)` -5. specialize `std::tuple_size` -6. specialize `std::tuple_element` -7. implement a binary `tuple_cat(tuple, tuple)` -8. implement `sum(tuple)` -9. implement `operator<<`, producing comma separated output diff --git a/exercises/variadic/solution/variadic.sol.cpp b/exercises/variadic/solution/variadic.sol.cpp deleted file mode 100644 index e65f0971..00000000 --- a/exercises/variadic/solution/variadic.sol.cpp +++ /dev/null @@ -1,196 +0,0 @@ -#include -#include -#include -#include -#include - -// we start with the tuple from the slides on variadic templates - -template -struct tuple {}; - -template -struct tuple : tuple { - // exercise 1: activate the default constructor - tuple() = default; - - // exercise 2: make constructor explicit - explicit tuple(T head, Ts... tail) : tuple(tail...), m_head(head) {} - - T m_head; -}; - -// we need a deduction guide, because the compiler only searches the primary template for constructors -template -tuple(Ts...) -> tuple; - -// here is a helper to get the tail of a tuple -template -auto& tail(tuple& t) { - // we just cast the tuple to its base class, which holds 1 element less - return static_cast&>(t); -} - -// exercise 3: implement head(tuple) here -template -auto& head(tuple& t) { - return t.m_head; -} - -// exercise 4: implement get here -template -auto& get(tuple& t) { - if constexpr (I == 0) - return head(t); - else - return get(tail(t)); -} - -// exercise 5: specialize std::tuple_size -template -struct std::tuple_size> { - static constexpr std::size_t value = sizeof...(Ts); -}; - -// exercise 6: specialize std::tuple_element -template -struct std::tuple_element> { - using type = std::remove_reference_t(std::declval>()))>; -}; - -// exercise 6: alternative solution using Head/Tail: -#if 0 -template -struct std::tuple_element<0, tuple> { - using type = Head; -}; - -template -struct std::tuple_element> { - using type = typename std::tuple_element>::type; -}; -#endif - -// exercise 7: implement tuple_cat(tuple, tuple) -template -auto tupleCatHelper(tuple t1, tuple t2, std::index_sequence, std::index_sequence) { - return tuple{get(t1)..., get(t2)...}; -} - -template -auto tupleCat(tuple t1, tuple t2) { - return tupleCatHelper(t1, t2, std::make_index_sequence{}, - std::make_index_sequence{}); -} - -// exercise 8: implement sum(tuple) -template -auto sum(tuple& t) { - return [&](std::index_sequence){ - return (get(t) + ... + 0); - }(std::make_index_sequence{}); -} - -// exercise 9: implement operator<< for tuple producing comma separated output -template -void putOperatorHelper(std::ostream& os, tuple& t, std::index_sequence) { - // fold over operator, with handling element index - ((os << get(t) << (Is == sizeof...(Ts) - 1 ? "" : ", ")), ...); - // we cannot use a binary fold over operator<< because we need to output twice per pack index (element and ", ") - // (os << ... << get(t)); -} - -template -std::ostream& operator<<(std::ostream& os, tuple& t) { - os << "tuple{"; - putOperatorHelper(os, t, std::make_index_sequence{}); - os << '}'; - return os; -} - -template -std::string toString(tuple& t) { - std::stringstream ss; - ss << std::boolalpha << t; - return ss.str(); -} - -int main() { - // tuple construction - tuple t1{}; - tuple t2{42, 3.14f, false}; - - // exercise 1: make tuple default-constructible, so the following code compiles: - tuple t3{}; - - // exercise 2: avoid implicit construction from a single value. make the following line not compile: - // tuple t4 = 42; - - // exercise 3: write head(tuple), which returns the first element of a tuple - static_assert(std::is_same_v); - assert(head(t2) == 42); - head(t2) = 43; - assert(head(t2) == 43); - - // exercise 4: implement get(tuple), use head() and tail() to help you - // 'if constexpr' may help you there - static_assert(std::is_same_v(t2)), int&>); - static_assert(std::is_same_v(t2)), float&>); - static_assert(std::is_same_v(t2)), bool&>); - assert(get<0>(t2) == 43); - assert(get<1>(t2) == 3.14f); - assert(get<2>(t2) == false); - get<0>(t2) = 42; - assert(get<0>(t2) == 42); - - // exercise 5: specialize std::tuple_size (used by std::tuple_size_v) for tuple - static_assert(std::tuple_size_v == 0); - static_assert(std::tuple_size_v == 3); - static_assert(std::tuple_size_v == 2); - - // exercise 6: specialize std::tuple_element (used by std::tuple_element_t), - // you can reuse your get(tuple) to determine the I-th type - // and std::remove_reference_t to strip the reference - static_assert(std::is_same_v, int>); - static_assert(std::is_same_v, float>); - static_assert(std::is_same_v, bool>); - - // congratulations! structured bindings should now work for your tuple! - auto& [i, f, b] = t2; - assert(get<0>(t2) == 42); - assert(get<1>(t2) == 3.14f); - assert(get<2>(t2) == false); - i = 1337; - assert(get<0>(t2) == 1337); - - // exercise 7: implement a binary tuple_cat(tuple, tuple). - // you will likely need std::index_sequence again, but now one for each tuple. - auto t4 = tupleCat(t2, t3); - static_assert(std::is_same_v>); - assert(get<0>(t4) == 1337); - assert(get<1>(t4) == 3.14f); - assert(get<2>(t4) == false); - assert(get<3>(t4) == 0); - assert(get<4>(t4) == 0.0f); - - // exercise 8: implement a function sum(tuple) that will add up all elements of the tuple - // use a fold expression and the lambda/index_sequence pattern - std::cout << "sum t1: " << sum(t1) << '\n'; - std::cout << "sum t2: " << sum(t2) << '\n'; - std::cout << "sum t4: " << sum(t4) << '\n'; - assert(sum(t1) == 0); - assert(sum(t2) == 1340.14f); // false == 0 - assert(sum(t4) == 1340.14f); - - // exercise 9: make your operator<< produce exactly the following output. - // you may need a fold expression over the comma operator, since you need to output the ", " as well - // for each tuple element, except the last. - // use a helper function with index_sequence. - std::cout << std::boolalpha; - std::cout << t1 << '\n'; - std::cout << t2 << '\n'; - std::cout << t4 << '\n'; - assert(toString(t1) == "tuple{}"); - assert(toString(t2) == "tuple{1337, 3.14, false}"); - assert(toString(t4) == "tuple{1337, 3.14, false, 0, 0}"); -} diff --git a/exercises/variadic/variadic.cpp b/exercises/variadic/variadic.cpp deleted file mode 100644 index c51f931c..00000000 --- a/exercises/variadic/variadic.cpp +++ /dev/null @@ -1,144 +0,0 @@ -#include -#include -#include -#include -#include - -// we start with the tuple from the slides on variadic templates - -template -struct tuple {}; - -template -struct tuple : tuple { - // exercise 1: TODO - - // exercise 2: TODO - tuple(T head, Ts... tail) : tuple(tail...), m_head(head) {} - - T m_head; -}; - -// we need a deduction guide, because the compiler only searches the primary template for constructors -template -tuple(Ts...) -> tuple; - -// here is a helper to get the tail of a tuple -template -auto& tail(tuple& t) { - // we just cast the tuple to its base class, which holds 1 element less - return static_cast&>(t); -} - -// exercise 3: implement head(tuple) here - -// exercise 4: implement get here - -// exercise 5: specialize std::tuple_size - -// exercise 6: specialize std::tuple_element - -// exercise 7: implement tuple_cat(tuple, tuple) -template -auto tupleCat(tuple t1, tuple t2) { - // TODO -} - -// exercise 8: implement sum(tuple) -template -auto sum(tuple& t) { - // TODO -} -// exercise 9: implement operator<< for tuple producing comma separated output -template -std::ostream& operator<<(std::ostream& os, tuple& t) { - // TODO - return os; -} - -template -std::string toString(tuple& t) { - std::stringstream ss; - ss << std::boolalpha << t; - return ss.str(); -} - -int main() { - // tuple construction - tuple t1{}; - tuple t2{42, 3.14f, false}; - - // exercise 1: make tuple default-constructible, so the following code compiles: - tuple t3{}; - - // exercise 2: avoid implicit construction from a single value. make the following line not compile: - tuple t4 = 42; - - // exercise 3: write head(tuple), which returns the first element of a tuple - static_assert(std::is_same_v); - assert(head(t2) == 42); - head(t2) = 43; - assert(head(t2) == 43); - - // exercise 4: implement get(tuple), use head() and tail() to help you - // 'if constexpr' may help you there - static_assert(std::is_same_v(t2)), int&>); - static_assert(std::is_same_v(t2)), float&>); - static_assert(std::is_same_v(t2)), bool&>); - assert(get<0>(t2) == 43); - assert(get<1>(t2) == 3.14f); - assert(get<2>(t2) == false); - get<0>(t2) = 42; - assert(get<0>(t2) == 42); - - // exercise 5: specialize std::tuple_size (used by std::tuple_size_v) for tuple - static_assert(std::tuple_size_v == 0); - static_assert(std::tuple_size_v == 3); - static_assert(std::tuple_size_v == 2); - - // exercise 6: specialize std::tuple_element (used by std::tuple_element_t), - // you can reuse your get(tuple) to determine the I-th type - // and std::remove_reference_t to strip the reference - static_assert(std::is_same_v, int>); - static_assert(std::is_same_v, float>); - static_assert(std::is_same_v, bool>); - - // congratulations! structured bindings should now work for your tuple! - auto& [i, f, b] = t2; - assert(get<0>(t2) == 42); - assert(get<1>(t2) == 3.14f); - assert(get<2>(t2) == false); - i = 1337; - assert(get<0>(t2) == 1337); - - // exercise 7: implement a binary tuple_cat(tuple, tuple). - // you will likely need std::index_sequence again, but now one for each tuple. - auto t4 = tupleCat(t2, t3); - static_assert(std::is_same_v>); - assert(get<0>(t4) == 1337); - assert(get<1>(t4) == 3.14f); - assert(get<2>(t4) == false); - assert(get<3>(t4) == 0); - assert(get<4>(t4) == 0.0f); - - // exercise 8: implement a function sum(tuple) that will add up all elements of the tuple - // use a fold expression and the lambda/index_sequence pattern - std::cout << "sum t1: " << sum(t1) << '\n'; - std::cout << "sum t2: " << sum(t2) << '\n'; - std::cout << "sum t4: " << sum(t4) << '\n'; - assert(sum(t1) == 0); - assert(sum(t2) == 1340.14f); // false == 0 - assert(sum(t4) == 1340.14f); - - // exercise 9: make your operator<< produce exactly the following output. - // you may need a fold expression over the comma operator, since you need to output the ", " as well - // for each tuple element, except the last. - // use a helper function with index_sequence. - std::cout << std::boolalpha; - std::cout << t1 << '\n'; - std::cout << t2 << '\n'; - std::cout << t4 << '\n'; - assert(toString(t1) == "tuple{}"); - assert(toString(t2) == "tuple{1337, 3.14, false}"); - assert(toString(t4) == "tuple{1337, 3.14, false, 0, 0}"); -} diff --git a/exercises/variant/.gitignore b/exercises/variant/.gitignore deleted file mode 100644 index 2e6bf93e..00000000 --- a/exercises/variant/.gitignore +++ /dev/null @@ -1 +0,0 @@ -variant diff --git a/exercises/variant/CMakeLists.txt b/exercises/variant/CMakeLists.txt deleted file mode 100644 index d764d9ae..00000000 --- a/exercises/variant/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -# Set up the project. -cmake_minimum_required( VERSION 3.12 ) -project( variant LANGUAGES CXX ) - -# Set up the compilation environment. -include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) -set(CMAKE_CXX_STANDARD 20) - -# Create the user's executable. -add_executable( variant "variant.cpp" ) - -# Create the "solution executable". -add_executable( variant.sol1 EXCLUDE_FROM_ALL "solution/variant.sol1.cpp" ) -add_custom_target( solution1 ) -add_dependencies( solution1 variant.sol1 ) -add_executable( variant.sol2 EXCLUDE_FROM_ALL "solution/variant.sol2.cpp" ) -add_custom_target( solution2 ) -add_dependencies( solution2 variant.sol2 ) -add_dependencies( solution solution1 solution2 ) diff --git a/exercises/variant/Makefile b/exercises/variant/Makefile deleted file mode 100644 index 472a84b5..00000000 --- a/exercises/variant/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -all: variant -solution: solution1 solution2 -solution1: variant.sol1 -solution2: variant.sol2 - -clean: - rm -f *o *so variant *~ variant.sol1 variant.sol2 - -% : %.cpp - $(CXX) -g -std=c++20 -Wall -Wextra -o $@ $< - -%.sol1 : solution/%.sol1.cpp - $(CXX) -g -std=c++20 -Wall -Wextra -o $@ $< - -%.sol2 : solution/%.sol2.cpp - $(CXX) -g -std=c++20 -Wall -Wextra -o $@ $< diff --git a/exercises/variant/README.md b/exercises/variant/README.md deleted file mode 100644 index 58923f78..00000000 --- a/exercises/variant/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Variants - -Here we explore: -- how `std::variant` offers an alternative to inheritance. - -## Prerequisites - -- slides about `std::variant` -- slides about lambda functions (for solution2) - -## Instructions - -In the file `variant.cpp`, replace inheritance with the use of a `std::variant`. -Two solutions are provided : -1. with `std::get_if`, -2. with `std::visit`. diff --git a/exercises/variant/solution/variant.sol1.cpp b/exercises/variant/solution/variant.sol1.cpp deleted file mode 100644 index 8e3f11c1..00000000 --- a/exercises/variant/solution/variant.sol1.cpp +++ /dev/null @@ -1,36 +0,0 @@ - -#include -#include -#include - -struct Electron { - void print() const { std::cout << "E\n"; } -}; - -struct Proton { - void print() const { std::cout << "P\n"; } -}; - -struct Neutron { - void print() const { std::cout << "N\n"; } -}; - -using Particle = std::variant; - -template void print_if(Particle const &p) { - // if the real type of p is not T, - // get_if returns nullptr - T const *ptr = std::get_if(&p); - if (ptr) - ptr->print(); -} - -int main() { - std::vector ps = {Electron{}, Proton{}, Neutron{}}; - - for (auto p : ps) { - print_if(p); - print_if(p); - print_if(p); - } -} diff --git a/exercises/variant/solution/variant.sol2.cpp b/exercises/variant/solution/variant.sol2.cpp deleted file mode 100644 index 4c48b64d..00000000 --- a/exercises/variant/solution/variant.sol2.cpp +++ /dev/null @@ -1,29 +0,0 @@ - -#include -#include -#include - -struct Electron { - void print() const { std::cout << "E\n"; } -}; - -struct Proton { - void print() const { std::cout << "P\n"; } -}; - -struct Neutron { - void print() const { std::cout << "N\n"; } -}; - -using Particle = std::variant; - -int main() { - std::vector ps = {Electron{}, Proton{}, Neutron{}}; - - for (auto const &p : ps) { - // With "auto" as argument, we provide a generic lambda. The compiler - // will instantiate it for all the types that the variant can hold, and at run - // time, the correct overload will be chosen automatically: - std::visit([](const auto &p) { p.print(); }, p); - } -} diff --git a/exercises/variant/variant.cpp b/exercises/variant/variant.cpp deleted file mode 100644 index 15b8502b..00000000 --- a/exercises/variant/variant.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - -In the code below, replace inheritance with the use of a `std::variant`. -There is no more need for a base class, and no more need pointers. -Two solutions are provided : -1. with `std::get_if`, -2. with `std::visit`. - -*/ - -#include -#include -#include - -struct Particle { - virtual void print() const = 0; - virtual ~Particle() = default; -}; - -struct Electron : Particle { - void print() const override { std::cout << "E\n"; } -}; - -struct Proton : Particle { - void print() const override { std::cout << "P\n"; } -}; - -struct Neutron : Particle { - void print() const override { std::cout << "N\n"; } -}; - -int main() { - std::vector> ps; - ps.push_back(std::make_unique()); - ps.push_back(std::make_unique()); - ps.push_back(std::make_unique()); - - for (auto const &p : ps) { - p->print(); - } -} diff --git a/exercises/virtual_inheritance/.gitignore b/exercises/virtual_inheritance/.gitignore deleted file mode 100644 index a2d52d8f..00000000 --- a/exercises/virtual_inheritance/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -trymultiherit -trymultiherit.sol diff --git a/exercises/virtual_inheritance/CMakeLists.txt b/exercises/virtual_inheritance/CMakeLists.txt deleted file mode 100644 index 62741350..00000000 --- a/exercises/virtual_inheritance/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -# Set up the project. -cmake_minimum_required( VERSION 3.12 ) -project( virtual_inheritance LANGUAGES CXX ) - -# Set up the compilation environment. -include( "${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake" ) - -# Create the user's library. -add_library( textbox "TextBox.hpp" "TextBox.cpp" ) -target_include_directories( textbox PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}" ) - -# Create the user's executable. -add_executable( trymultiherit "trymultiherit.cpp" ) -target_link_libraries( trymultiherit PRIVATE textbox ) - -# Create the solution's library. -add_library( textboxsol EXCLUDE_FROM_ALL "solution/TextBox.hpp" "solution/TextBox.cpp" ) -target_include_directories( textboxsol PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/solution" ) -add_dependencies( solution textboxsol ) - -# Create the "solution executable". -add_executable( trymultiherit.sol EXCLUDE_FROM_ALL "solution/trymultiherit.sol.cpp" ) -target_link_libraries( trymultiherit.sol PRIVATE textboxsol ) -add_dependencies( solution trymultiherit.sol ) diff --git a/exercises/virtual_inheritance/Makefile b/exercises/virtual_inheritance/Makefile deleted file mode 100644 index 252b5dc6..00000000 --- a/exercises/virtual_inheritance/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -all: trymultiherit -solution: trymultiherit.sol - -clean: - rm -f *o *so trymultiherit *~ trymultiherit.sol - -libtextbox.so: TextBox.cpp TextBox.hpp - $(CXX) -Wall -Wextra -shared -fPIC -o $@ $< - -trymultiherit : trymultiherit.cpp libtextbox.so - $(CXX) -Wall -Wextra -L. -o $@ $^ - -libtextboxsol.so: solution/TextBox.cpp solution/TextBox.hpp - $(CXX) -Wall -Wextra -shared -fPIC -o $@ $< - -trymultiherit.sol : solution/trymultiherit.sol.cpp libtextboxsol.so - $(CXX) -Wall -Wextra -I. -L. -o $@ $^ diff --git a/exercises/virtual_inheritance/README.md b/exercises/virtual_inheritance/README.md deleted file mode 100644 index 5a995598..00000000 --- a/exercises/virtual_inheritance/README.md +++ /dev/null @@ -1,11 +0,0 @@ - -## Instructions - -Step 1 -* look at the code -* open `trymultiherit.cpp` -* create a `TextBox` and call `draw` -* Fix the code to call both draws by using types - -Step 2 -* retry with virtual inheritance diff --git a/exercises/virtual_inheritance/TextBox.cpp b/exercises/virtual_inheritance/TextBox.cpp deleted file mode 100644 index a790a978..00000000 --- a/exercises/virtual_inheritance/TextBox.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "TextBox.hpp" -#include - -Drawable::Drawable(int id) : m_id(id) {}; - -void Drawable::draw() const { - std::cout << "Drawing " << m_id << '\n'; -}; - -Rectangle::Rectangle(int id, float width, float height) : - Drawable(id), m_width(width), m_height(height) {} - -Text::Text(int id, const std::string &content) : - Drawable(id), m_content(content) {} - -TextBox::TextBox(const std::string &content, - float width, float height) : - Rectangle(1, width, height), Text(2, content) {} diff --git a/exercises/virtual_inheritance/TextBox.hpp b/exercises/virtual_inheritance/TextBox.hpp deleted file mode 100644 index c0f86af8..00000000 --- a/exercises/virtual_inheritance/TextBox.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include - -class Drawable { -public: - Drawable(int id); - void draw() const; -private: - int m_id; -}; - -class Rectangle : public Drawable { -public: - Rectangle(int id, float width, float height); -protected: - float m_width; - float m_height; -}; - -class Text : public Drawable { -public: - Text(int id, const std::string &content); -protected: - std::string m_content; -}; - -class TextBox : public Rectangle, public Text { -public: - TextBox(const std::string &content, - float width, float height); -}; diff --git a/exercises/virtual_inheritance/solution/TextBox.cpp b/exercises/virtual_inheritance/solution/TextBox.cpp deleted file mode 100644 index 964c924d..00000000 --- a/exercises/virtual_inheritance/solution/TextBox.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "TextBox.hpp" -#include - -Drawable::Drawable(int id) : m_id(id) {}; - -void Drawable::draw() const { - std::cout << "Drawing " << m_id << '\n'; -}; - -Rectangle::Rectangle(int id, float width, float height) : - Drawable(id), m_width(width), m_height(height) {} - -Text::Text(int id, std::string content) : - Drawable(id), m_content(content) {} - -TextBox::TextBox(std::string content, - float width, float height) : - Drawable(3), Rectangle(1, width, height), Text(2, content) {} diff --git a/exercises/virtual_inheritance/solution/TextBox.hpp b/exercises/virtual_inheritance/solution/TextBox.hpp deleted file mode 100644 index eddeaf1f..00000000 --- a/exercises/virtual_inheritance/solution/TextBox.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include - -class Drawable { -public: - Drawable(int id); - void draw() const; -private: - int m_id; -}; - -class Rectangle : public virtual Drawable { -public: - Rectangle(int id, float width, float height); -protected: - float m_width; - float m_height; -}; - -class Text : public virtual Drawable { -public: - Text(int id, std::string content); -protected: - std::string m_content; -}; - -class TextBox : public Rectangle, public Text { -public: - TextBox(std::string content, - float width, float height); -}; diff --git a/exercises/virtual_inheritance/solution/trymultiherit.sol.cpp b/exercises/virtual_inheritance/solution/trymultiherit.sol.cpp deleted file mode 100644 index 358b5298..00000000 --- a/exercises/virtual_inheritance/solution/trymultiherit.sol.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "TextBox.hpp" -#include - -int main() { - // create a TextBox and call draw - TextBox tb("my text", 10, 5); - // tb.draw(); - // error: request for member ‘draw’ is ambiguous - - // Fix the code to call both draws by using types - Rectangle &r = tb; - r.draw(); - Text &t = tb; - t.draw(); - - // retry with virtual inheritance - // error: no matching function for call to ‘Drawable::Drawable()’ - // add a default constructor to Drawable or call the constructor from TextBox -} diff --git a/exercises/virtual_inheritance/trymultiherit.cpp b/exercises/virtual_inheritance/trymultiherit.cpp deleted file mode 100644 index 8410cecc..00000000 --- a/exercises/virtual_inheritance/trymultiherit.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "TextBox.hpp" -#include - -int main() { - // create a TextBox and call draw - - - // Fix the code to call both draws by using types - - - // try with virtual inheritance - - -} diff --git a/mlc_config.json b/mlc_config.json deleted file mode 100644 index f9b4ab75..00000000 --- a/mlc_config.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "ignorePatterns": [ - { - "pattern": "https://github.com/issues?.*" - }, - { - "pattern": ".*cookiecutter.*" - }, - { - "pattern": ".*opensource.*" - }, - { - "pattern": "https://github.com/hsf-training/cpluspluscourse/raw/download/.*" - } - ] -} diff --git a/notes/2016timing b/notes/2016timing deleted file mode 100644 index 10c6c680..00000000 --- a/notes/2016timing +++ /dev/null @@ -1,6 +0,0 @@ -did 1-2-3 + object orientation in first 3h -stopped after memcheck on day 2 -added 20mn on day 3 to finish (not doing helgrind/ccpcheck) - -1 exercise done for real (templates, 1-4 only) -others done together, and some skipped completely diff --git a/notes/2017timing b/notes/2017timing deleted file mode 100644 index e2351a4f..00000000 --- a/notes/2017timing +++ /dev/null @@ -1,7 +0,0 @@ -First day : 1, 2 fast, 3 and 4 up to constness + went through functors a first time - did together virtual inheritance exercise - skipped the others -Second day : went to the end of tools - did all exercises but all on the screen -Third day : the rest, with only 5mn of delay at the end - did more or ess the exercises on the screen (basically looking at the solution) diff --git a/notes/2018timing b/notes/2018timing deleted file mode 100644 index f9cfb1a8..00000000 --- a/notes/2018timing +++ /dev/null @@ -1,17 +0,0 @@ -Day 1 : - Started from start, fast on basics - Did no exercise (only looked at virtual inheritance one) - stopped after constness, but went through functors and templates a 1st time - -Day 2 : - Redid functors and templates - went through all tools - Did fully the exercise on templates - Did all exercises on tools except helgrind - -Day 3 : - C++11 and 14 in first half up to move semantic - Redid move semantic in 2nd half and finished C++11/14 - Then did python and finally C++17 - only 5mn late - No exercises whatsoever diff --git a/notes/2019Timing b/notes/2019Timing deleted file mode 100644 index ed0e5271..00000000 --- a/notes/2019Timing +++ /dev/null @@ -1,14 +0,0 @@ -Day 1 : - pause after 1:40 before static members in OO - stopped at end of More C++ features (after move and copy elision) - -Day 2 : - repeated move semantic and started tools up to debugging. Did advanced OO up to pure virtual methods then pause - end of advanced OO, operators, templates (and exercise), STL, functors - -Day 3 : - repeated functors and templates quickly, finished advanced C++ - valgrind and cppcheck exercise (minus helgrind), python and concurrency (minus condition variables) - -Corrections : - slide 188 diff --git a/notes/2020Timing b/notes/2020Timing deleted file mode 100644 index c2cd5271..00000000 --- a/notes/2020Timing +++ /dev/null @@ -1,13 +0,0 @@ -Day 1 : - pause after 1:20 before starting Object Orientation - stopped after constness - -Day 2 (on video conference) : - quick recap (15 mn) of course 1 - pause after advanced OO - Then tools until callgrind (included) - -Day 3 (on video conference) : - static code analysis (helgrind was skipped) - pause after templates, before STL - finished advanced C++ and did C++ and python diff --git a/talk/.latexmkrc b/talk/.latexmkrc deleted file mode 100644 index ee3dc529..00000000 --- a/talk/.latexmkrc +++ /dev/null @@ -1 +0,0 @@ -$clean_ext = "cut lex lgb lgp mw nav snm vrb _minted-%R/* _minted-%R"; diff --git a/talk/C++Course.tex b/talk/C++Course.tex deleted file mode 100644 index 88767298..00000000 --- a/talk/C++Course.tex +++ /dev/null @@ -1,294 +0,0 @@ -\documentclass[compress]{beamer} -\usetheme{Warsaw} -\useoutertheme{split} - -\input{setup} - -% setup for the basic/advanced course switch -% create a new latex if called basic (false by default) -\newif\ifbasic - -% There are three ways to switch to the basic course: -% 1. Uncomment the line below. Disadvantage: git diff won't be empty -%\basictrue -% 2. Tell it to the Makefile. -% 2.1 Invoke "make essentials" -% 2.2 export HEPCPP_ESSENTIALS=1 -% make -\ifdefined\makebasic - \basictrue -\fi -% 3. Create a file named ./buildbasic -\IfFileExists{./buildbasic}{\basictrue} - -% create a comment environment advanced. depending on the value of basic, we exclude or include it. -\ifbasic - \excludecomment{advanced} -\else - % advanced slides have a different structure color - \specialcomment{advanced}{ - \setbeamercolor{structure}{fg=beamer@blendedblue!40!violet} - \isAdvancedSlidetrue - }{ - \setbeamercolor{structure}{fg=beamer@blendedblue} - \isAdvancedSlidefalse - } -\fi - -\newunicodechar{σ}{$\sigma$} -\newunicodechar{µ}{$\mu$} - -\begin{document} - -\showboxdepth=\maxdimen -\showboxbreadth=\maxdimen - -\begin{frame} - \titlepage -\end{frame} - -\begin{frame} - \frametitle{Foreword} - \begin{block}{What this course is not} - \begin{itemize} - \item It is not for absolute beginners - \item It is not for experts - \item It is not complete at all (would need 3 weeks...) - \begin{itemize} - \item although it is already too long for the time we have - \item \inserttotalframenumber{} slides, \insertpresentationendpage{} pages, \total{ex@counter} exercises... - \end{itemize} - \end{itemize} - \end{block} - \begin{block}{How I see it} - \begin{description} - \item[Adaptative] pick what you want - \item[Interactive] tell me what to skip/insist on - \item[Practical] let's spend time on real code - \end{description} - \end{block} - \begin{block}{Where to find latest version ?} - \begin{itemize} - \item full sources at \href{https://github.com/hsf-training/cpluspluscourse}{github.com/hsf-training/cpluspluscourse} - \item latest pdf on - \ifbasic - \href{https://github.com/hsf-training/cpluspluscourse/raw/download/talk/C++Course\_essentials.pdf}{GitHub} - \else - \href{https://github.com/hsf-training/cpluspluscourse/raw/download/talk/C++Course\_full.pdf}{GitHub} - \fi - \end{itemize} - \end{block} -\end{frame} - - -\begin{frame} - \frametitle{More courses} - \begin{block}{The HSF Software Training Center} - A set of course modules on more software engineering aspects prepared from within the HEP community - \begin{itemize} - \item Unix shell - \item Python - \item Version control (git, gitlab, github) - \item ... - \end{itemize} - {\small \url{https://hepsoftwarefoundation.org/training/curriculum.html}} - \end{block} - -\end{frame} - -\begin{frame} - \frametitle{Outline} - \begin{multicols}{2} - \tableofcontents[sectionstyle=show,subsectionstyle=hide] - \end{multicols} -\end{frame} - -\begin{frame} - \frametitle{Detailed outline} - %\vspace{-0.5cm} - \begin{tiny} - \begin{multicols}{3} - \tableofcontents[sectionstyle=show,subsectionstyle=show] - \end{multicols} - \end{tiny} -\end{frame} - -\section[Intro]{History and goals} -\input{introduction/history} -\input{introduction/goals} - -\section[base]{Language basics} -\input{basicconcepts/coresyntax} -\input{basicconcepts/arrayspointers} -\input{basicconcepts/scopesnamespaces} -\input{basicconcepts/classenum} -\input{basicconcepts/references} -\input{basicconcepts/functions} -\input{basicconcepts/operators} -\input{basicconcepts/control} -\input{basicconcepts/headersinterfaces} -\input{basicconcepts/auto} -\begin{advanced} - \input{basicconcepts/inline} - \input{basicconcepts/assert} -\end{advanced} - -\section[OO]{Object orientation (OO)} -\input{objectorientation/objectsclasses} -\input{objectorientation/inheritance} -\input{objectorientation/constructors} -\input{objectorientation/static} -\input{objectorientation/allocations} -\input{objectorientation/advancedoo} -\begin{advanced} - \input{objectorientation/typecasting} -\end{advanced} -\input{objectorientation/operators} -\input{objectorientation/functors} -\begin{advanced} - \input{objectorientation/adl} -\end{advanced} - -\section[Core]{Core modern \cpp} -\input{morelanguage/constness} -\begin{advanced} - \input{morelanguage/constexpr} -\end{advanced} -\input{morelanguage/exceptions} -\begin{advanced} - \input{morelanguage/move} - \input{morelanguage/copyelision} -\end{advanced} -\input{morelanguage/templates} -\input{morelanguage/lambda} -\input{morelanguage/stl} -\begin{advanced} - \input{morelanguage/morestl} - \input{morelanguage/random} - \input{morelanguage/ranges} -\end{advanced} -\input{morelanguage/raii} -\begin{advanced} - \input{morelanguage/initialization} -\end{advanced} - -\begin{advanced} - \section[exp]{Expert \cpp} - \input{expert/cpp20spaceship} - \input{expert/variadictemplate} - \input{expert/perfectforwarding} - \input{expert/sfinae} - \input{expert/cpp20concepts} - \input{expert/modules} - \input{expert/coroutines} -\end{advanced} - -\section[Tool]{Useful tools} -\input{tools/editors} -\input{tools/vcs} -\input{tools/formatting} -\input{tools/compiling} -\input{tools/webtools} -\input{tools/debugging} -\begin{advanced} - \input{tools/sanitizers} - \input{tools/valgrind} - \input{tools/staticanalysis} - \input{tools/profiling} - \input{tools/doxygen} - - \section[conc]{Concurrency} - \input{concurrency/threadsasync} - \input{concurrency/mutexes} - \input{concurrency/atomic} - \input{concurrency/threadlocal} - \input{concurrency/condition} - - \section[py]{\cpp and python} - \input{python/modulewriting} - \input{python/marryingcandcpp} - \input{python/ctypes} - \input{python/cppyy} -\end{advanced} - -\begin{frame} - \frametitle{This is the end} - \begin{center} - \Huge Questions ?\\ - \vspace{.5cm} - \tiny \url{https://github.com/hsf-training/cpluspluscourse/raw/download/talk/C++Course\_full.pdf}\\ - \tiny \url{https://github.com/hsf-training/cpluspluscourse} - \end{center} -\end{frame} - -\appendix - -\section*{Index} - -\begin{frame} - \frametitle{Index of Good Practices} - \listofgoodpractices -\end{frame} - -\begin{frame} - \frametitle{Index of Exercises} - \listofexercises -\end{frame} - -\begin{frame} - \frametitle{Index of Godbolt code examples} - \listofgodbolt -\end{frame} - -\section*{External Resources and Further Reading} - -\begin{frame} - \frametitle{Books} - \begin{thebibliography}{10} - \scriptsize - \beamertemplatebookbibitems - - \bibitem{} A Tour of C++, Third Edition - \newblock Bjarne Stroustrup, Addison-Wesley, Sep 2022 - \newblock ISBN-13: \href{https://learning.oreilly.com/library/view/a-tour-of/9780136823575/}{978-0136816485} - - \bibitem{} Effective Modern C++ - \newblock Scott Meyers, O'Reilly Media, Nov 2014 - \newblock ISBN-13: \href{https://learning.oreilly.com/library/view/effective-modern-c/9781491908419/}{978-1-491-90399-5} - - \bibitem{} C++ Templates - The Complete Guide, 2nd Edition - \newblock David Vandevoorde, Nicolai M. Josuttis, and Douglas Gregor - \newblock ISBN-13: \href{https://learning.oreilly.com/library/view/c-templates-the/9780134778808/}{978-0-321-71412-1} - - \bibitem{} C++ Best Practices, 2nd Edition - \newblock Jason Turner - \newblock \url{https://leanpub.com/cppbestpractices} - - \bibitem{} Clean Architecture - \newblock Robert C. Martin, Pearson, Sep 2017 - \newblock ISBN-13: \href{https://learning.oreilly.com/library/view/clean-architecture-a/9780134494272/}{978-0-13-449416-6} - - \bibitem{} The Art of UNIX Programming - \newblock Eric S. Raymond, Addison-Wesley, Sep 2002 - \newblock ISBN-13: \href{https://learning.oreilly.com/library/view/the-art-of/0131429019/}{978-0131429017} - - \bibitem{} Introduction to Algorithms, 4th Edition - \newblock T. H. Cormen, C. E. Leiserson, R. L. Rivest, C. Stein, Apr 2022 - \newblock ISBN-13: \href{https://mitpress.mit.edu/9780262046305/introduction-to-algorithms/}{978-0262046305} - \end{thebibliography} -\end{frame} - -\begin{frame} - \frametitle{Conferences} - \begin{itemize} - \item CppCon --- \href{https://cppcon.org/}{cppcon.org} --- \youtubeuser{CppCon} - \item \cpp Now --- \href{https://cppnow.org/}{cppnow.org} --- \youtubeuser{BoostCon} - \item Code::Dive --- \href{https://codedive.pl/}{codedive.pl} --- \youtubechannel{codediveconference} - \item ACCU Conference --- \href{https://accu.org/}{accu.org} --- \youtubechannel{ACCUConf} - \item Meeting \cpp\ --- \href{https://meetingcpp.com/}{meetingcpp.com} --- \youtubechannel{MeetingCPP} - \item See link below for more information - \url{https://isocpp.org/wiki/faq/conferences-worldwide} - \end{itemize} -\end{frame} - -\end{document} diff --git a/talk/C++Course_essentials.pdf b/talk/C++Course_essentials.pdf new file mode 100644 index 00000000..0e4d307d Binary files /dev/null and b/talk/C++Course_essentials.pdf differ diff --git a/talk/C++Course_full.pdf b/talk/C++Course_full.pdf new file mode 100644 index 00000000..0d30c577 Binary files /dev/null and b/talk/C++Course_full.pdf differ diff --git a/talk/CERN-logo.jpg b/talk/CERN-logo.jpg deleted file mode 100644 index c241dfaf..00000000 Binary files a/talk/CERN-logo.jpg and /dev/null differ diff --git a/talk/Makefile b/talk/Makefile deleted file mode 100644 index 7dc47044..00000000 --- a/talk/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -all: C++Course.pdf - -LATEXMK=latexmk -OPTIONS=-pdf -xelatex -shell-escape -halt-on-error - -essentials: all -essentials: OPTIONS+=-usepretex='\def\makebasic{}' - -preview: all -preview: OPTIONS+=-pvc - -ifeq ($(QUIET), 1) - OPTIONS+=-quiet -else - OPTIONS+=-interaction=nonstopmode -endif - -ifeq ($(HEPCPP_ESSENTIALS), 1) - OPTIONS+=-usepretex='\def\makebasic{}' -endif - -.PHONY: clean clobber FORCE - -%.pdf: %.tex FORCE - $(LATEXMK) $(OPTIONS) $< - -clean: - $(LATEXMK) -C - -clobber: - $(LATEXMK) -C - $(RM) C++Course.pdf diff --git a/talk/basicconcepts/arrayspointers.tex b/talk/basicconcepts/arrayspointers.tex deleted file mode 100644 index 7a6c4edd..00000000 --- a/talk/basicconcepts/arrayspointers.tex +++ /dev/null @@ -1,274 +0,0 @@ -\subsection[Ptr]{Arrays and Pointers} - -\begin{frame}[fragile] - \frametitlecpp[98]{Static arrays} - \begin{cppcode} - int ai[4] = {1,2,3,4}; - int ai[] = {1,2,3,4}; // identical - - char ac[3] = {'a','b','c'}; // char array - char ac[4] = "abc"; // valid C string - char ac[4] = {'a','b','c',0}; // same valid string - - int i = ai[2]; // i = 3 - char c = ac[8]; // at best garbage, may segfault - int i = ai[4]; // also garbage ! - \end{cppcode} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Pointers} - \begin{multicols}{2} - % the code has to be repeated n times here. Anyone finding a better solution - % is welcome, but it's not a trivial task, due to the verbatim nature of minted - \begin{overprint}[\columnwidth] - \onslide<1> - \begin{minted}[linenos]{cpp} -int i = 4; -int *pi = &i; -int j = *pi + 1; - -int ai[] = {1,2,3}; -int *pai = ai; // decay to ptr -int *paj = pai + 1; -int k = *paj + 1; - -// compile error -int *pak = k; - -// seg fault ! -int *pak = (int*)k; -int l = *pak; - \end{minted} - \onslide<2> - \begin{minted}[linenos,highlightlines=1]{cpp} -int i = 4; -int *pi = &i; -int j = *pi + 1; - -int ai[] = {1,2,3}; -int *pai = ai; // decay to ptr -int *paj = pai + 1; -int k = *paj + 1; - -// compile error -int *pak = k; - -// seg fault ! -int *pak = (int*)k; -int l = *pak; - \end{minted} - \onslide<3> - \begin{minted}[linenos,highlightlines=2]{cpp} -int i = 4; -int *pi = &i; -int j = *pi + 1; - -int ai[] = {1,2,3}; -int *pai = ai; // decay to ptr -int *paj = pai + 1; -int k = *paj + 1; - -// compile error -int *pak = k; - -// seg fault ! -int *pak = (int*)k; -int l = *pak; - \end{minted} - \onslide<4> - \begin{minted}[linenos,highlightlines=3]{cpp} -int i = 4; -int *pi = &i; -int j = *pi + 1; - -int ai[] = {1,2,3}; -int *pai = ai; // decay to ptr -int *paj = pai + 1; -int k = *paj + 1; - -// compile error -int *pak = k; - -// seg fault ! -int *pak = (int*)k; -int l = *pak; - \end{minted} - \onslide<5> - \begin{minted}[linenos,highlightlines=5]{cpp} -int i = 4; -int *pi = &i; -int j = *pi + 1; - -int ai[] = {1,2,3}; -int *pai = ai; // decay to ptr -int *paj = pai + 1; -int k = *paj + 1; - -// compile error -int *pak = k; - -// seg fault ! -int *pak = (int*)k; -int l = *pak; - \end{minted} - \onslide<6> - \begin{minted}[linenos,highlightlines=6]{cpp} -int i = 4; -int *pi = &i; -int j = *pi + 1; - -int ai[] = {1,2,3}; -int *pai = ai; // decay to ptr -int *paj = pai + 1; -int k = *paj + 1; - -// compile error -int *pak = k; - -// seg fault ! -int *pak = (int*)k; -int l = *pak; - \end{minted} - \onslide<7> - \begin{minted}[linenos,highlightlines=7]{cpp} -int i = 4; -int *pi = &i; -int j = *pi + 1; - -int ai[] = {1,2,3}; -int *pai = ai; // decay to ptr -int *paj = pai + 1; -int k = *paj + 1; - -// compile error -int *pak = k; - -// seg fault ! -int *pak = (int*)k; -int l = *pak; - \end{minted} - \onslide<8> - \begin{minted}[linenos,highlightlines=8]{cpp} -int i = 4; -int *pi = &i; -int j = *pi + 1; - -int ai[] = {1,2,3}; -int *pai = ai; // decay to ptr -int *paj = pai + 1; -int k = *paj + 1; - -// compile error -int *pak = k; - -// seg fault ! -int *pak = (int*)k; -int l = *pak; - \end{minted} - \onslide<9> - \begin{minted}[linenos,highlightlines=11]{cpp} -int i = 4; -int *pi = &i; -int j = *pi + 1; - -int ai[] = {1,2,3}; -int *pai = ai; // decay to ptr -int *paj = pai + 1; -int k = *paj + 1; - -// compile error -int *pak = k; - -// seg fault ! -int *pak = (int*)k; -int l = *pak; - \end{minted} - \end{overprint} - \columnbreak - \onslide<2->{ - \begin{tikzpicture} - \memorystack[size x=3cm,word size=1,block size=4,nb blocks=11] - \onslide<2-> {\memorypush{i = 4}} - \onslide<3-> {\memorypushpointer[pi =]{1}} - \onslide<4-> {\memorypush{j = 5}} - \onslide<5-> {\memorypush{ai[0] = 1}} - \onslide<5-> {\memorypush{ai[1] = 2}} - \onslide<5-> {\memorypush{ai[2] = 3}} - \onslide<6-> {\memorypushpointer[pai =]{4}} - \onslide<7-> {\memorypushpointer[paj =]{5}} - \onslide<8-> {\memorypush{k = 3}} - \onslide<9-> {\memorypush{pak = 3}} - \onslide<9-> {\draw[\stackcolor!80,->] (stack10-1.west) -- +(-0.5cm,0) - node [anchor=east] {??};} - \end{tikzpicture} - } - \end{multicols} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{nullptr} - \begin{block}{A pointer to nothing} - \begin{itemize} - \item if a pointer doesn't point to anything, set it to \cppinline{nullptr} - \begin{itemize} - \item useful to e.g.\ mark the end of a linked data structure - \item or absence of an optional function argument (pointer) - \end{itemize} - \item same as setting it to 0 or \cppinline{NULL} (before \cpp11) - \item triggers compilation error when assigned to integer - \end{itemize} - \end{block} - \pause - \begin{exampleblock}{Example code} - \begin{cppcode*}{} - int* ip = nullptr; - int i = NULL; // compiles, bug? - int i = nullptr; // ERROR - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Dynamic arrays using C} - \begin{cppcode} - #include - #include - - int *bad; // pointer to random address - int *ai = nullptr; // better, deterministic, testable - - // allocate array of 10 ints (uninitialized) - ai = (int*) malloc(10*sizeof(int)); - memset(ai, 0, 10*sizeof(int)); // and set them to 0 - - ai = (int*) calloc(10, sizeof(int)); // both in one go - - free(ai); // release memory - \end{cppcode} - \begin{goodpractice}[C's memory management]{Don't use C's memory management} - Use \cppinline{std::vector} and friends or smart pointers - \end{goodpractice} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Manual dynamic arrays using \cpp} - \begin{cppcode} - #include - #include - - // allocate array of 10 ints - int* ai = new int[10]; // uninitialized - int* ai = new int[10]{}; // zero-initialized - - delete[] ai; // release array memory - - // allocate a single int - int* pi = new int; - int* pi = new int{}; - delete pi; // release scalar memory - \end{cppcode} - \begin{goodpractice}[Manual memory management]{Don't use manual memory management} - Use \cppinline{std::vector} and friends or smart pointers - \end{goodpractice} -\end{frame} diff --git a/talk/basicconcepts/assert.tex b/talk/basicconcepts/assert.tex deleted file mode 100644 index 6911443c..00000000 --- a/talk/basicconcepts/assert.tex +++ /dev/null @@ -1,95 +0,0 @@ -\subsection[assert]{Assertions} - -\begin{frame}[fragile] - \frametitlecpp[98]{Assertions} - \begin{block}{Checking invariants in a program} - \begin{itemize} - \item An invariant is a property that is guaranteed to be true during certain phases of a program, and the program might crash or yield wrong results if it is violated - \begin{itemize} - \item ``Here, `a' should always be positive'' - \end{itemize} - \item This can be checked using \cppinline{assert} - \item The program will be aborted if the assertion fails - \end{itemize} - \end{block} - \begin{exampleblockGB}{\texttt{assert} in practice}{https://godbolt.org/z/eo78cY7hM}{\texttt{assert}} - \begin{overprint} - \onslide<1> - \begin{cppcode*}{} - #include - double f(double a) { - // [...] do stuff with a - // [...] that should leave it positive - assert(a > 0.); - return std::sqrt(a); - } - \end{cppcode*} - \onslide<2> - \begin{Verbatim} -% ./testAssert -Assertion failed: (a > 0.), function f, - file testAssert.cpp, line 5. -Abort trap: 6 - \end{Verbatim} - \end{overprint} - \end{exampleblockGB} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Assertions} - \begin{goodpractice}{Assert} - \begin{itemize} - \item Assertions are mostly for developers and debugging - \item Use them to check important invariants of your program - \item Prefer handling user-facing errors with helpful error messages/exceptions - \item Assertions can impact the speed of a program - \begin{itemize} - \item Assertions are disabled when the macro \cppinline{NDEBUG} is defined - \item Decide if you want to disable them when you release code - \end{itemize} - \end{itemize} - \end{goodpractice} - \begin{exampleblock}{Disabling assertions} - \small - Compile a program with NDEBUG defined:\\ - \texttt{g++ \textcolor{blue}{-DNDEBUG} -O2 -W[...] test.cpp -o test.exe} - - \begin{cppcode*}{} - double f(double a) { - assert(a > 0.); // no effect - return std::sqrt(a); - } - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Static Assert} - \begin{block}{Checking invariants at compile time} - \begin{itemize} - \item To check invariants at compile time, use \cppinline{static_assert} - \item The assertion can be any constant expression (see later) - \item The message argument is optional in \cpp 17 and later - \end{itemize} - \end{block} - \begin{exampleblock}{\texttt{static\_assert}} - \small - \begin{cppcode*}{} - double f(UserType a) { - static_assert( - std::is_floating_point_v, // C++17 - "This function expects floating-point types."); - return std::sqrt(a); - } - \end{cppcode*} - \end{exampleblock} - \scriptsize - \begin{Verbatim}[commandchars=\\\{\}] -a.cpp: In function 'double f(UserType)': -\textcolor{blue}{a.cpp:3:9:} \textcolor{red}{error:} \textcolor{blue}{static assertion failed: This function} - \textcolor{blue}{expects floating-point types.} - 2 | static_assert( - | \textcolor{red}{std::is_floating_point_v}, - | \textcolor{red}{~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~} - \end{Verbatim} -\end{frame} diff --git a/talk/basicconcepts/auto.tex b/talk/basicconcepts/auto.tex deleted file mode 100644 index 331dd76a..00000000 --- a/talk/basicconcepts/auto.tex +++ /dev/null @@ -1,40 +0,0 @@ -\subsection[auto]{Auto keyword} - -\begin{frame}[fragile] - \frametitlecpp[11]{Auto keyword} - \begin{block}{Reason of being} - \begin{itemize} - \item Many type declarations are redundant - \item They are often a source for compiler warnings and errors - \item Using auto prevents unwanted/unnecessary type conversions - \end{itemize} - \begin{cppcode*}{} - std::vector v; - float a = v[3]; // conversion intended? - int b = v.size(); // bug? unsigned to signed - \end{cppcode*} - \end{block} - \pause - \begin{block}{Practical usage} - \begin{cppcode*}{} - std::vector v; - auto a = v[3]; - const auto b = v.size(); // std::size_t - int sum{0}; - for (auto n : v) { sum += n; } - \end{cppcode*} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Loops, references, auto} - \begin{exerciseWithShortcut}{Loops, references, auto}{Loops, refs, auto} - Familiarise yourself with range-based for loops and references - \begin{itemize} - \item Go to \texttt{exercises/loopsRefsAuto} - \item Look at \texttt{loopsRefsAuto.cpp} - \item Compile it (\texttt{make}) and run the program (\texttt{./loopsRefsAuto}) - \item Work on the tasks that you find in \texttt{loopsRefsAuto.cpp} - \end{itemize} - \end{exerciseWithShortcut} -\end{frame} diff --git a/talk/basicconcepts/classenum.tex b/talk/basicconcepts/classenum.tex deleted file mode 100644 index aabdcc6c..00000000 --- a/talk/basicconcepts/classenum.tex +++ /dev/null @@ -1,224 +0,0 @@ -\subsection[Class/Enum]{Class and enum types} - -\begin{frame}[fragile] - \frametitlecpp[98]{struct} - \begin{mdframed}[style=simplebox] - \center ``members'' grouped together under one name - \end{mdframed} - \begin{multicols}{2} - \begin{cppcode*}{} - struct Individual { - unsigned char age; - float weight; - }; - - Individual student; - student.age = 25; - student.weight = 78.5f; - - Individual teacher = { - 45, 67.0f - }; - \end{cppcode*} - \columnbreak - \begin{cppcode*}{firstnumber=14} - Individual *ptr = &student; - ptr->age = 25; - // same as: (*ptr).age = 25; - \end{cppcode*} - \pause - \vfill - \hspace{-1.5cm} - \begin{tikzpicture} - \memorystack[nb blocks=5] - \onslide<3-> { - \memorypush{25,?,?,?} - \memorypushwidevalue{78.5} - \memorystruct{1}{2}{\scriptsize student} - } - \onslide<4-> { - \memorypush{45,?,?,?} - \memorypushwidevalue{67.0} - \memorystruct{3}{4}{\scriptsize teacher} - } - \onslide<5-> { - \memorypushwidevalue{0x3000} - \draw[->] (0,2.25) .. controls +(left:1) and +(left:1) .. (-.4,.25); - } - \end{tikzpicture} - \vfill \null - \end{multicols} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{union} - \begin{mdframed}[style=simplebox] - \center ``members'' packed together at same memory location - \end{mdframed} - \begin{multicols}{2} - \begin{cppcode*}{} - union Duration { - int seconds; - short hours; - char days; - }; - Duration d1, d2, d3; - d1.seconds = 259200; - d2.hours = 72; - d3.days = 3; - d1.days = 3; // d1.seconds overwritten - int a = d1.seconds; // d1.seconds is garbage - \end{cppcode*} - \pause - \columnbreak - \null \vfill - \begin{tikzpicture} - \clip (0,0) rectangle (6cm, 3cm); - \memorystack[word size=4,nb blocks=4] - \visible<3-5>{\memorypushwidevalue{d1 259200}} - \onslide<4->{\memorypushhalfvalue{d2 72}} - \memorygoto{2} - \onslide<4->{\memorypush{,,?,?}} - \onslide<5->{\memorypush{d3 3,?,?,?}} - \memorygoto{1} - \onslide<6->{\memorypush{d1 3,?,?,?}} - \end{tikzpicture} - \vfill \null - \end{multicols} - \onslide<7->{ - \begin{goodpractice}{Avoid unions} - \begin{itemize} - \item Starting with \cpp17: prefer \cppinline{std::variant} - \end{itemize} - \end{goodpractice} - } -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Enums} - \begin{block}{} - \begin{itemize} - \item use to declare a list of related constants (enumerators) - \item has an underlying integral type - \item enumerator names leak into enclosing scope - \end{itemize} - \end{block} - \begin{multicols}{2} - \begin{cppcode*}{} - enum VehicleType { - - BIKE, // 0 - CAR, // 1 - BUS, // 2 - }; - VehicleType t = CAR; - \end{cppcode*} - \columnbreak - \begin{cppcode*}{firstnumber=8} - enum VehicleType - : int { // C++11 - BIKE = 3, - CAR = 5, - BUS = 7, - }; - VehicleType t2 = BUS; - \end{cppcode*} - \end{multicols} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Scoped enumeration, aka enum class} - \begin{block}{Same syntax as enum, with scope} - \begin{cppcode*}{} - enum class VehicleType { Bus, Car }; - VehicleType t = VehicleType::Car; - \end{cppcode*} - \end{block} - \pause - \begin{exampleblock}{Only advantages} - \begin{itemize} - \item scopes enumerator names, avoids name clashes - \item strong typing, no automatic conversion to int - \end{itemize} - \small - \begin{cppcode*}{firstnumber=3} - enum VType { Bus, Car }; enum Color { Red, Blue }; - VType t = Bus; - if (t == Red) { /* We do enter */ } - int a = 5 * Car; // Ok, a = 5 - - enum class VT { Bus, Car }; enum class Col { Red, Blue }; - VT t = VT::Bus; - if (t == Col::Red) { /* Compiler error */ } - int a = t * 5; // Compiler error - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{More sensible example} - \begin{multicols}{2} - \begin{cppcode*}{} - enum class ShapeType { - Circle, - Rectangle - }; - - struct Rectangle { - float width; - float height; - }; - \end{cppcode*} - \columnbreak - \pause - \begin{cppcode*}{firstnumber=10} - struct Shape { - ShapeType type; - union { - float radius; - Rectangle rect; - }; - }; - \end{cppcode*} - \end{multicols} - \pause - \begin{multicols}{2} - \begin{cppcode*}{firstnumber=17} - Shape s; - s.type = - ShapeType::Circle; - s.radius = 3.4; - - \end{cppcode*} - \columnbreak - \begin{cppcode*}{firstnumber=20} - Shape t; - t.type = - Shapetype::Rectangle; - t.rect.width = 3; - t.rect.height = 4; - \end{cppcode*} - \end{multicols} -\end{frame} - -\begin{frame}[fragile] - \frametitle{typedef and using \hfill \cpp98 / \cpp11} - Used to create type aliases - \begin{alertblock}{\cpp98} - \begin{cppcode*}{} - typedef std::uint64_t myint; - myint count = 17; - typedef float position[3]; - \end{cppcode*} - \end{alertblock} - \begin{exampleblock}{\cpp11} - \begin{cppcode*}{firstnumber=4} - using myint = std::uint64_t; - myint count = 17; - using position = float[3]; - - template using myvec = std::vector; - myvec myintvec; - \end{cppcode*} - \end{exampleblock} -\end{frame} diff --git a/talk/basicconcepts/control.tex b/talk/basicconcepts/control.tex deleted file mode 100644 index c2004a0c..00000000 --- a/talk/basicconcepts/control.tex +++ /dev/null @@ -1,313 +0,0 @@ -\subsection[Control]{Control structures} - -\begin{frame}[fragile] - \frametitlecpp[98]{Control structures: if} - \begin{block}{if syntax} - \begin{cppcode*}{} - if (condition1) { - Statement1; Statement2; - } else if (condition2) - OnlyOneStatement; - else { - Statement3; - Statement4; - } - \end{cppcode*} - \begin{itemize} - \item The \cppinline{else} and \cppinline{else if} clauses are optional - \item The \cppinline{else if} clause can be repeated - \item Braces are optional if there is a single statement - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Control structures: if} - \begin{exampleblock}{Practical example} - \begin{cppcode*}{} - int collatz(int a) { - if (a <= 0) { - std::cout << "not supported\n"; - return 0; - } else if (a == 1) { - return 1; - } else if (a%2 == 0) { - return collatz(a/2); - } else { - return collatz(3*a+1); - } - } - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Control structures: conditional operator} - \begin{block}{Syntax} - \begin{cppcode*}{linenos=false} - test ? expression1 : expression2; - \end{cppcode*} - \vspace{-0.2cm} - \begin{itemize} - \item If test is \cppinline{true} \cppinline{expression1} is returned - \item Else, \cppinline{expression2} is returned - \end{itemize} - \end{block} - \pause - \begin{exampleblock}{Practical example} - \begin{cppcode*}{} - const int charge = isLepton ? -1 : 0; - \end{cppcode*} - \end{exampleblock} - \pause - \begin{alertblock}{Do not abuse it} - \begin{cppcode*}{} - int collatz(int a) { - return a==1 ? 1 : collatz(a%2==0 ? a/2 : 3*a+1); - } - \end{cppcode*} - \begin{itemize} - \item Explicit \cppinline{if}s are generally easier to read - \item Use the ternary operator with short conditions and expressions - \item Avoid nesting - \end{itemize} - \end{alertblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Control structures: switch} - \begin{block}{Syntax} - \begin{cppcode*}{} - switch(identifier) { - case c1 : statements1; break; - case c2 : statements2; break; - case c3 : statements3; break; - ... - default : statementsn; break; - } - \end{cppcode*} - \begin{itemize} - \item The \cppinline{break} statement is not mandatory but... - \item Cases are entry points, not independent pieces - \item Execution ``falls through'' to the next case without a \cppinline{break}! - \item The \cppinline{default} case may be omitted - \end{itemize} - \end{block} - \pause - \begin{alertblock}{Use break} - Avoid \cppinline{switch} statements with fall-through cases - \end{alertblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Control structures: switch} - \begin{exampleblock}{Practical example} - \begin{cppcode*}{} - enum class Lang { French, German, English, Other }; - Lang language = ...; - switch (language) { - case Lang::French: - std::cout << "Bonjour"; - break; - case Lang::German: - std::cout << "Guten Tag"; - break; - case Lang::English: - std::cout << "Good morning"; - break; - default: - std::cout << "I do not speak your language"; - } - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\AtBeginEnvironment{minted}{\renewcommand{\fcolorbox}[4][]{#4}} - -\begin{frame}[fragile] - \frametitlecpp[17]{\texttt{[[fallthrough]]} attribute} - \begin{block}{New compiler warning} - Since \cpp17, compilers are encouraged to warn on fall-through - \end{block} - \begin{exampleblock}{\cpp17} - \begin{cppcode*}{} - switch (c) { - case 'a': - f(); // Warning emitted - case 'b': // Warning probably suppressed - case 'c': - g(); - [[fallthrough]]; // Warning suppressed - case 'd': - h(); - } - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{Init-statements for if and switch} - \begin{block}{Purpose} - Allows to limit variable scope in \cppinline{if} and \cppinline{switch} statements - \end{block} - \begin{exampleblock}{\cpp17} - \begin{cppcode*}{} - if (Value val = GetValue(); condition(val)) { - f(val); // ok - } else - g(val); // ok - h(val); // error, no `val` in scope here - \end{cppcode*} - \end{exampleblock} - \pause - \begin{alertblock}{\cpp98} - Don't confuse with a variable declaration as condition: - \begin{cppcode*}{firstnumber=7} - if (Value* val = GetValuePtr()) - f(*val); - \end{cppcode*} - \end{alertblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Control structures: for loop} - \begin{block}{for loop syntax} - \begin{cppcode*}{} - for(initializations; condition; increments) { - statements; - } - \end{cppcode*} - \vspace{-0.2cm} - \begin{itemize} - \item Multiple initializations / increments are comma separated - \item Initializations can contain declarations - \item Braces are optional if loop body is a single statement - \end{itemize} - \end{block} - \pause - \begin{exampleblock}{Practical example} - \begin{cppcode*}{firstnumber=4} - for(int i = 0, j = 0 ; i < 10 ; i++, j = i*i) { - std::cout << i << "^2 is " << j << '\n'; - } - \end{cppcode*} - \end{exampleblock} - \pause - \begin{goodpractice}[\texttt{for} syntax]{Don't abuse the \texttt{for} syntax} - \begin{itemize} - \item The \cppinline{for} loop head should fit in 1-3 lines - \end{itemize} - \end{goodpractice} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Range-based loops} - \begin{block}{Reason of being} - \begin{itemize} - \item Simplifies loops over ``ranges'' tremendously - \item Especially with STL containers and ranges - \end{itemize} - \end{block} - \begin{block}{Syntax} - \begin{cppcode*}{} - for ( type iteration_variable : range ) { - // body using iteration_variable - } - \end{cppcode*} - \end{block} - \begin{exampleblock}{Example code} - \begin{cppcode*}{firstnumber=4} - int v[4] = {1,2,3,4}; - int sum = 0; - for (int a : v) { sum += a; } - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Init-statements for range-based loops} - \begin{block}{Purpose} - Allows to limit variable scope in range-based loops - \end{block} - \begin{alertblock}{\cpp17} - \begin{cppcode*}{} - std::array data = {"hello", ",", "world"}; - std::size_t i = 0; - for (auto& d : data) { - std::cout << i++ << ' ' << d << '\n'; - } - \end{cppcode*} - \end{alertblock} - \begin{exampleblock}{\cpp20} - \begin{cppcode*}{firstnumber=6} - for (std::size_t i = 0; auto const & d : data) { - std::cout << i++ << ' ' << d << '\n'; - } - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Control structures: while loop} - \begin{block}{while loop syntax} - \begin{cppcode*}{} - while(condition) { - statements; - } - - do { - statements; - } while(condition); - \end{cppcode*} - \begin{itemize} - \item Braces are optional if the body is a single statement - \end{itemize} - \end{block} - \pause - \begin{alertblock}{Bad example} - \begin{cppcode*}{} - while (n != 1) - if (0 == n%2) n /= 2; - else n = 3 * n + 1; - \end{cppcode*} - \end{alertblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Control structures: jump statements} - \begin{block}{} - \begin{description} - \item[break] Exits the loop and continues after it - \item[continue] Goes immediately to next loop iteration - \item[return] Exits the current function - \item[goto] Can jump anywhere inside a function, avoid! - \end{description} - \end{block} - \pause - \begin{alertblock}{Bad example} - \begin{cppcode*}{} - while (1) { - if (n == 1) break; - if (0 == n%2) { - std::cout << n << '\n'; - n /= 2; - continue; - } - n = 3 * n + 1; - } - \end{cppcode*} - \end{alertblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Control structures} - \begin{exerciseWithShortcut}{Control structures}{Control structs} - Familiarise yourself with different kinds of control structures. Re-implement them in different ways. - \begin{itemize} - \item Go to \texttt{exercises/control} - \item Look at \texttt{control.cpp} - \item Compile it (\texttt{make}) and run the program (\texttt{./control}) - \item Work on the tasks that you find in \texttt{README.md} - \end{itemize} - \end{exerciseWithShortcut} -\end{frame} diff --git a/talk/basicconcepts/coresyntax.tex b/talk/basicconcepts/coresyntax.tex deleted file mode 100644 index ce5d7552..00000000 --- a/talk/basicconcepts/coresyntax.tex +++ /dev/null @@ -1,186 +0,0 @@ -\subsection[Core]{Core syntax and types} - -\begin{frame}[fragile] - \frametitlecpp[98]{Hello World} - \begin{cppcode} - #include - - // This is a function - void print(int i) { - std::cout << "Hello, world " << i << std::endl; - } - - int main(int argc, char** argv) { - int n = 3; - for (int i = 0; i < n; i++) { - print(i); - } - return 0; - } - \end{cppcode} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Comments} - \begin{cppcode} - // simple comment until end of line - int i; - - /* multiline comment - * in case we need to say more - */ - double /* or something in between */ d; - - /** - * Best choice : doxygen compatible comments - * \brief checks whether i is odd - * \param i input - * \return true if i is odd, otherwise false - * \see https://www.doxygen.nl/manual/docblocks.html - */ - bool isOdd(int i); - \end{cppcode} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Basic types(1)} - \begin{cppcode} - bool b = true; // boolean, true or false - - char c = 'a'; // min 8 bit integer - // may be signed or not - // can store an ASCII character - signed char c = 4; // min 8 bit signed integer - unsigned char c = 4; // min 8 bit unsigned integer - - char* s = "a C string"; // array of chars ended by \0 - string t = "a C++ string";// class provided by the STL - - short int s = -444; // min 16 bit signed integer - unsigned short s = 444; // min 16 bit unsigned integer - short s = -444; // int is optional - \end{cppcode} -\end{frame} -\begin{frame}[fragile] - \frametitlecpp[98]{Basic types(2)} - \begin{cppcode} - int i = -123456; // min 16, usually 32 bit - unsigned int i = 1234567; // min 16, usually 32 bit - - long l = 0L // min 32 bit - unsigned long l = 0UL; // min 32 bit - - long long ll = 0LL; // min 64 bit - unsigned long long l = 0ULL; // min 64 bit - - float f = 1.23f; // 32 (1+8+23) bit float - double d = 1.23E34; // 64 (1+11+52) bit float - long double ld = 1.23E34L // min 64 bit float - \end{cppcode} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Portable numeric types} - \begin{cppcode} - #include // defines the following: - - std::int8_t c = -3; // 8 bit signed integer - std::uint8_t c = 4; // 8 bit unsigned integer - - std::int16_t s = -444; // 16 bit signed integer - std::uint16_t s = 444; // 16 bit unsigned integer - - std::int32_t s = -674; // 32 bit signed integer - std::uint32_t s = 674; // 32 bit unsigned integer - - std::int64_t s = -1635; // 64 bit signed integer - std::uint64_t s = 1635; // 64 bit unsigned int - \end{cppcode} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Integer literals} - \begin{cppcode} - int i = 1234; // decimal (base 10) - int i = 02322; // octal (base 8) - int i = 0x4d2; // hexadecimal (base 16) - int i = 0X4D2; // hexadecimal (base 16) - int i = 0b10011010010; // binary (base 2) C++14 - - int i = 123'456'789; // digit separators, C++14 - int i = 0b100'1101'0010; // digit separators, C++14 - - 42 // int - 42u, 42U // unsigned int - 42l, 42L // long - 42ul, 42UL // unsigned long - 42ll, 42LL // long long - 42ull, 42ULL // unsigned long long - \end{cppcode} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Floating-point literals} - \begin{cppcode} - double d = 12.34; - double d = 12.; - double d = .34; - double d = 12e34; // 12 * 10^34 - double d = 12E34; // 12 * 10^34 - double d = 12e-34; // 12 * 10^-34 - double d = 12.34e34; // 12.34 * 10^34 - - double d = 123'456.789'101; // digit separators, C++14 - - double d = 0x4d2.4p3; // hexfloat, 0x4d2.4 * 2^3 - // = 1234.25 * 2^3 = 9874 - - 3.14f, 3.14F, // float - 3.14, 3.14, // double - 3.14l, 3.14L, // long double - \end{cppcode} -\end{frame} - -\begin{advanced} -\begin{frame}[fragile] - \frametitlecpp[11]{Useful aliases} - \begin{cppcode} - #include // (and others) defines: - - // unsigned integer, can hold any variable's size - std::size_t s = sizeof(int); - - #include // defines: - - // signed integer, can hold any diff between two pointers - std::ptrdiff_t c = &s - &s; - - // signed/unsigned integer, can hold any pointer value - std::intptr_t i = reinterpret_cast(&s); - std::uintptr_t i = reinterpret_cast(&s); - \end{cppcode} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[23]{Extended floating-point types} - \begin{block}{Extended floating-point types} - \begin{itemize} - \item \emph{Optional} types, which may be provided - \item Custom conversion and promotion rules - \end{itemize} - \end{block} - \begin{cppcode*}{} - #include // may define these: - - std::float16_t = 3.14f16; // 16 (1+5+10) bit float - std::float32_t = 3.14f32; // like float (1+8+23) - // but different type - std::float64_t = 3.14f64; // like double (1+11+52) - // but different type - std::float128_t = 3.14f128; // 128 (1+15+112) bit float - std::bfloat16_t = 3.14bf16; // 16 (1+8+7) bit float - - // also F16, F32, F64, F128 or BF16 suffix possible - \end{cppcode*} -\end{frame} -\end{advanced} diff --git a/talk/basicconcepts/functions.tex b/talk/basicconcepts/functions.tex deleted file mode 100644 index 6ef973f5..00000000 --- a/talk/basicconcepts/functions.tex +++ /dev/null @@ -1,453 +0,0 @@ -\subsection[$f()$]{Functions} - -\begin{frame}[fragile] - \frametitlecpp[98]{Functions} - \begin{multicols}{2} - \begin{cppcode*}{} - // with return type - int square(int a) { - return a * a; - } - - // multiple parameters - int mult(int a, - int b) { - return a * b; - } - \end{cppcode*} - \columnbreak - \begin{cppcode*}{firstnumber=11} - // no return - void log(char* msg) { - std::cout << msg; - } - - // no parameter - void hello() { - std::cout << "Hello World"; - } - \end{cppcode*} - \end{multicols} - - \pause - - \begin{exampleblock}{Functions and references to returned values} - \begin{cppcode} - int result = square(2); - int & temp = square(2); // Not allowed - int const & temp2 = square(2); // OK - \end{cppcode} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Function default arguments} - \begin{multicols}{2} - \begin{cppcode*}{} - // must be the trailing - // argument - int add(int a, - int b = 2) { - return a + b; - } - // add(1) == 3 - // add(3,4) == 7 - - \end{cppcode*} - \columnbreak - \begin{cppcode*}{firstnumber=11} - // multiple default - // arguments are possible - int add(int a = 2, - int b = 2) { - return a + b; - } - // add() == 4 - // add(3) == 5 - \end{cppcode*} - \end{multicols} -\end{frame} - - -\begin{frame}[fragile] - \frametitlecpp[98]{Functions: parameters are passed by value} - \begin{multicols}{2} - % the code has to be repeated n times here. Anyone finding a better solution - % is welcome, but it's not a trivial task, due to the verbatim nature of minted - \begin{overprint}[\columnwidth] - \onslide<1-2> - \begin{minted}[linenos,highlightlines=2]{cpp} -struct BigStruct {...}; -BigStruct s; - -// parameter by value -void printVal(BigStruct p) { - ... -} -printVal(s); // copy - -// parameter by reference -void printRef(BigStruct &q) { - ... -} -printRef(s); // no copy - \end{minted} - \onslide<3> - \begin{minted}[linenos,highlightlines={5,8}]{cpp} -struct BigStruct {...}; -BigStruct s; - -// parameter by value -void printVal(BigStruct p) { - ... -} -printVal(s); // copy - -// parameter by reference -void printRef(BigStruct &q) { - ... -} -printRef(s); // no copy - \end{minted} - \onslide<4-> - \begin{minted}[linenos,highlightlines={11,14}]{cpp} -struct BigStruct {...}; -BigStruct s; - -// parameter by value -void printVal(BigStruct p) { - ... -} -printVal(s); // copy - -// parameter by reference -void printRef(BigStruct &q) { - ... -} -printRef(s); // no copy - \end{minted} - \end{overprint} - \columnbreak - \null \vfill - \begin{tikzpicture} - \memorystack[word size=1, block size=80, nb blocks=7, size x=3cm] - \onslide<2-> { - \memorypush{s1} - \memorypush{...} - \memorypush{sn} - \memorystruct{1}{3}{s} - } - \onslide<3> { - \memorypush{p1 = s1} - \memorypush{...} - \memorypush{pn = sn} - \memorystruct{4}{6}{p} - } - \memorygoto{4} - \onslide<4> { - \memorypushpointer[q =]{1} - } - \end{tikzpicture} - \vfill \null - \end{multicols} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Functions: pass by value or reference?} - \begin{multicols}{2} - % the code has to be repeated n times here. Anyone finding a better solution - % is welcome, but it's not a trivial task, due to the verbatim nature of minted - \begin{overprint}[\columnwidth] - \onslide<1> - \begin{minted}[linenos]{cpp} -struct SmallStruct {int a;}; -SmallStruct s = {1}; - -void changeVal(SmallStruct p) { - p.a = 2; -} -changeVal(s); -// s.a == 1 - -void changeRef(SmallStruct &q) { - q.a = 2; -} -changeRef(s); -// s.a == 2 - \end{minted} - \onslide<2> - \begin{minted}[linenos,highlightlines=2]{cpp} -struct SmallStruct {int a;}; -SmallStruct s = {1}; - -void changeVal(SmallStruct p) { - p.a = 2; -} -changeVal(s); -// s.a == 1 - -void changeRef(SmallStruct &q) { - q.a = 2; -} -changeRef(s); -// s.a == 2 - \end{minted} - \onslide<3> - \begin{minted}[linenos,highlightlines={4,7}]{cpp} -struct SmallStruct {int a;}; -SmallStruct s = {1}; - -void changeVal(SmallStruct p) { - p.a = 2; -} -changeVal(s); -// s.a == 1 - -void changeRef(SmallStruct &q) { - q.a = 2; -} -changeRef(s); -// s.a == 2 - \end{minted} - \onslide<4> - \begin{minted}[linenos,highlightlines=5]{cpp} -struct SmallStruct {int a;}; -SmallStruct s = {1}; - -void changeVal(SmallStruct p) { - p.a = 2; -} -changeVal(s); -// s.a == 1 - -void changeRef(SmallStruct &q) { - q.a = 2; -} -changeRef(s); -// s.a == 2 - \end{minted} - \onslide<5> - \begin{minted}[linenos,highlightlines=8]{cpp} -struct SmallStruct {int a;}; -SmallStruct s = {1}; - -void changeVal(SmallStruct p) { - p.a = 2; -} -changeVal(s); -// s.a == 1 - -void changeRef(SmallStruct &q) { - q.a = 2; -} -changeRef(s); -// s.a == 2 - \end{minted} - \onslide<6> - \begin{minted}[linenos,highlightlines={10,13}]{cpp} -struct SmallStruct {int a;}; -SmallStruct s = {1}; - -void changeVal(SmallStruct p) { - p.a = 2; -} -changeVal(s); -// s.a == 1 - -void changeRef(SmallStruct &q) { - q.a = 2; -} -changeRef(s); -// s.a == 2 - \end{minted} - \onslide<7> - \begin{minted}[linenos,highlightlines=11]{cpp} -struct SmallStruct {int a;}; -SmallStruct s = {1}; - -void changeVal(SmallStruct p) { - p.a = 2; -} -changeVal(s); -// s.a == 1 - -void changeRef(SmallStruct &q) { - q.a = 2; -} -changeRef(s); -// s.a == 2 - \end{minted} - \onslide<8> - \begin{minted}[linenos,highlightlines=14]{cpp} -struct SmallStruct {int a;}; -SmallStruct s = {1}; - -void changeVal(SmallStruct p) { - p.a = 2; -} -changeVal(s); -// s.a == 1 - -void changeRef(SmallStruct &q) { - q.a = 2; -} -changeRef(s); -// s.a == 2 - \end{minted} - \end{overprint} - \columnbreak - \null \vfill - \begin{tikzpicture} - \memorystack[word size=1, block size=4, nb blocks=3, size x=3cm] - \onslide<2-6> { - \memorypush{s.a = 1} - } - \memorygoto{1} - \onslide<7-> { - \memorypush{s.a = 2} - } - - \memorygoto{2} - \onslide<3> { - \memorypush{p.a = 1} - } - \memorygoto{2} - \onslide<4> { - \memorypush{p.a = 2} - } - \memorygoto{2} - \onslide<6-7> { - \memorypushpointer[q =]{1} - } - \end{tikzpicture} - \vfill \null - \end{multicols} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Pass by value, reference or pointer} - \begin{block}{Different ways to pass arguments to a function} - \begin{itemize} - \item By default, arguments are passed by value (= copy) \\ - good for small types, e.g.\ numbers - \item Use references for parameters to avoid copies \\ - good for large types, e.g.\ objects - \item Use \cppinline{const} for safety and readability whenever possible - \end{itemize} - \end{block} - \pause - \begin{block}{Syntax} - \begin{cppcode*}{escapeinside=||} -struct T {...}; T a; -void fVal(T value); fVal(a); // by value -void fRef(const T &value); fRef(a); // by reference -void fPtr(const T *value); fPtr(|{\setlength{\fboxsep}{0pt}\color{gray}\colorbox{yellow}{\textsc{&}}}|a); // by pointer -void fWrite(T &value); fWrite(a); // non-const ref - \end{cppcode*} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Overloading} - \begin{block}{Overloading} - \begin{itemize} - \item We can have multiple functions with the same name - \begin{itemize} - \item Must have different parameter lists - \item A different return type alone is not allowed - \item Form a so-called ``overload set'' - \end{itemize} - \item Default arguments can cause ambiguities - \end{itemize} - \end{block} - \begin{exampleblock}{} - \begin{cppcode*}{} - int sum(int b); // 1 - int sum(int b, int c); // 2, ok, overload - // float sum(int b, int c); // disallowed - sum(42); // calls 1 - sum(42, 43); // calls 2 - int sum(int b, int c, int d = 4); // 3, overload - sum(42, 43, 44); // calls 3 - sum(42, 43); // error: ambiguous, 2 or 3 - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Functions} - \begin{exercise}{Functions} - Familiarise yourself with pass by value / pass by reference. - \begin{itemize} - \item Go to \texttt{exercises/functions} - \item Look at \texttt{functions.cpp} - \item Compile it (\texttt{make}) and run the program (\texttt{./functions}) - \item Work on the tasks that you find in \texttt{functions.cpp} - \end{itemize} - \end{exercise} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Functions: good practices} - \begin{onlyenv}<1> - \begin{goodpractice}{Write readable functions} - \begin{itemize} - \item Keep functions short - \item Do one logical thing (single-responsibility principle) - \item Use expressive names - \item Document non-trivial functions - \end{itemize} - \end{goodpractice} - \begin{exampleblock}{Example: Good} - \begin{cppcode*}{} - /// Count number of dilepton events in data. - /// \param d Dataset to search. - unsigned int countDileptons(Data &d) { - selectEventsWithMuons(d); - selectEventsWithElectrons(d); - return d.size(); - } - \end{cppcode*} - \end{exampleblock} - \end{onlyenv} - \begin{onlyenv}<2-> - \begin{alertblock}{Example: don't! Everything in one long function} - \begin{multicols}{2} - \begin{cppcode*}{} - unsigned int runJob() { - // Step 1: data - Data data; - data.resize(123456); - data.fill(...); - - // Step 2: muons - for (....) { - if (...) { - data.erase(...); - } - } - // Step 3: electrons - for (....) { - \end{cppcode*} - \columnbreak - \begin{cppcode*}{firstnumber=last} - if (...) { - data.erase(...); - } - } - - // Step 4: dileptons - int counter = 0; - for (....) { - if (...) { - counter++; - } - } - - return counter; - } - \end{cppcode*} - \end{multicols} - \end{alertblock} - \end{onlyenv} -\end{frame} diff --git a/talk/basicconcepts/headersinterfaces.tex b/talk/basicconcepts/headersinterfaces.tex deleted file mode 100644 index 84e8ba57..00000000 --- a/talk/basicconcepts/headersinterfaces.tex +++ /dev/null @@ -1,95 +0,0 @@ -\subsection[.h]{Headers and interfaces} - -\begin{frame}[fragile] - \frametitlecpp[98]{Headers and interfaces} - \begin{block}{Interface} - Set of declarations defining some functionality - \begin{itemize} - \item Put in a so-called ``header file'' - \item The implementation exists somewhere else - \end{itemize} - \end{block} - \begin{block}{Header: hello.hpp} - \begin{cppcode*}{linenos=false} - void printHello(); - \end{cppcode*} - \end{block} - \begin{block}{Usage: myfile.cpp} - \begin{cppcode*}{} - #include "hello.hpp" - int main() { - printHello(); - } - \end{cppcode*} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Preprocessor} - \begin{cppcode} - // file inclusion - #include "hello.hpp" - // macro constants and function-style macros - #define MY_GOLDEN_NUMBER 1746 - #define CHECK_GOLDEN(x) if ((x) != MY_GOLDEN_NUMBER) \ - std::cerr << #x " was not the golden number\n"; - // compile time or platform specific configuration - #if defined(USE64BITS) || defined(__GNUG__) - using myint = std::uint64_t; - #elif - using myint = std::uint32_t; - #endif - \end{cppcode} - \pause - \begin{goodpractice}[preprocessor]{Use preprocessor only in very restricted cases} - \begin{itemize} - \item Conditional inclusion of headers - \item Customization for specific compilers/platforms - \end{itemize} - \end{goodpractice} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Header include guards} - \begin{block}{Problem: redefinition by accident} - \begin{itemize} - \item Headers may define new names (e.g.\ types) - \item Multiple (transitive) inclusions of a header would define those names multiple times, which is a compile error - \item Solution: guard the content of your headers! - \end{itemize} - \end{block} - \begin{block}{Include guards} - \begin{cppcode*}{} - #ifndef MY_HEADER_INCLUDED - #define MY_HEADER_INCLUDED - ... // header file content - #endif - \end{cppcode*} - \end{block} - \begin{block}{Pragma once (non-standard)} - \begin{cppcode*}{} - #pragma once - ... // header file content - \end{cppcode*} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Header / source separation} - \begin{goodpractice}[Header / source]{Headers and source files} - \begin{itemize} - \item Headers should contain declarations of functions / classes - \begin{itemize} - \item Only create them if interface is used somewhere else - \end{itemize} - \item Might be included/compiled many times - \item Good to keep them short - \item Minimise \cppinline{#include} statements - \item Put long code in implementation files. Exceptions: - \begin{itemize} - \item Short functions - \item Templates and constexpr functions - \end{itemize} - \end{itemize} - \end{goodpractice} -\end{frame} diff --git a/talk/basicconcepts/inline.tex b/talk/basicconcepts/inline.tex deleted file mode 100644 index 0dbf2a9d..00000000 --- a/talk/basicconcepts/inline.tex +++ /dev/null @@ -1,78 +0,0 @@ -\subsection[inline]{Inline keyword} - -\begin{frame}[fragile] - \frametitlecpp[98]{Inline keyword} - \begin{block}{Inline functions originally} - \begin{itemize} - \item Applies to a function to tell the compiler to inline it - \begin{itemize} - \item That is, replace function calls by the function's content\\ - (similar to how a macro works) - \end{itemize} - \item Only a hint, compiler can still choose to not inline - \item Avoids call overhead at the cost of increasing binary size - \end{itemize} - \end{block} - \begin{exampleblock}{Major side effect} - \begin{itemize} - \item The linker reduces the duplicated functions into one - \item An inline function definition can thus live in header files - \end{itemize} - \end{exampleblock} - \begin{block}{} - \begin{cppcode*}{} - inline int mult(int a, int b) { - return a * b; - } - \end{cppcode*} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Inline keyword} - \begin{block}{Inline functions nowadays} - \begin{itemize} - \item Compilers can judge far better when to inline or not - \begin{itemize} - \item thus primary purpose is gone - \end{itemize} - \item Putting functions into headers became main purpose - \item Many types of functions are marked \cppinline{inline} by default: - \begin{itemize} - \item function templates - \item \cppinline{constexpr} functions - \item class member functions - \end{itemize} - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{Inline keyword} - \begin{block}{Inline variables} - \begin{itemize} - \item Global (or \cppinline{static} member) variable specified as \cppinline{inline} - \item Same side effect, linker merges all occurrences into one - \item Allows to define global variables/constants in headers - \end{itemize} - \end{block} - \begin{block}{} - \small - \begin{cppcode*}{} - // global.h - inline int count = 0; - inline const std::string filename = "output.txt"; - // a.cpp - #include "global.h" - int f() { return count; } - // b.cpp - #include "global.h" - void g(int i) { count += i; } - \end{cppcode*} - \end{block} - \begin{alertblock}{} - \begin{itemize} - \item Avoid global variables! Global constants are fine. - \end{itemize} - \end{alertblock} -\end{frame} diff --git a/talk/basicconcepts/operators.tex b/talk/basicconcepts/operators.tex deleted file mode 100644 index e9834e83..00000000 --- a/talk/basicconcepts/operators.tex +++ /dev/null @@ -1,69 +0,0 @@ -\subsection[Op]{Operators} - -\begin{frame}[fragile] - \frametitlecpp[98]{Operators(1)} - \begin{block}{Binary and Assignment Operators} - \begin{cppcode*}{} - int i = 1 + 4 - 2; // 3 - i *= 3; // 9, short for: i = i * 3; - i /= 2; // 4 - i = 23 % i; // modulo => 3 - \end{cppcode*} - \end{block} - \pause - \begin{block}{Increment / Decrement Operators \uncover<3->{\hfill \alert{\bf Use wisely}}} - \begin{cppcode*}{} - int i = 0; i++; // i = 1 - int j = ++i; // i = 2, j = 2 - int k = i++; // i = 3, k = 2 - int l = --i; // i = 2, l = 2 - int m = i--; // i = 1, m = 2 - \end{cppcode*} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Operators(2)} - \begin{block}{Bitwise and Assignment Operators} - \begin{cppcode*}{} - unsigned i = 0xee & 0x55; // 0x44 - i |= 0xee; // 0xee - i ^= 0x55; // 0xbb - unsigned j = ~0xee; // 0xffffff11 - unsigned k = 0x1f << 3; // 0xf8 - unsigned l = 0x1f >> 2; // 0x7 - \end{cppcode*} - \end{block} - \pause - \begin{block}{Logical Operators} - \begin{cppcode*}{} - bool a = true; - bool b = false; - bool c = a && b; // false - bool d = a || b; // true - bool e = !d; // false - \end{cppcode*} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Operators(3)} - \begin{block}{Comparison Operators} - \begin{cppcode*}{} - bool a = (3 == 3); // true - bool b = (3 != 3); // false - bool c = (4 < 4); // false - bool d = (4 <= 4); // true - bool e = (4 > 4); // false - bool f = (4 >= 4); // true - auto g = (5 <=> 5); // C++20 (later) - \end{cppcode*} - \end{block} - \pause - \begin{block}{Precedences \uncover<3->{\hfill \alert{\bf Avoid}\uncover<4->{\color{green} \bf\ - use parentheses}}} - \begin{cppcode*}{linenos=false} - c &= 1+(++b)|(a--)*4%5^7; // ??? - \end{cppcode*} - Details can be found on {\color{blue!50!white} \href{https://en.cppreference.com/w/cpp/language/operator_precedence}{cppreference}} - \end{block} -\end{frame} diff --git a/talk/basicconcepts/references.tex b/talk/basicconcepts/references.tex deleted file mode 100644 index 40e775fc..00000000 --- a/talk/basicconcepts/references.tex +++ /dev/null @@ -1,51 +0,0 @@ -\subsection[Refs]{References} - -\begin{frame}[fragile] - \frametitlecpp[98]{References} - \begin{block}{References} - \begin{itemize} - \item References allow for direct access to another object - \item They can be used as shortcuts / better readability - \item They can be declared \cppinline{const} to allow only read access - \end{itemize} - \end{block} - - \begin{exampleblock}{Example:} - \begin{cppcode*}{} - int i = 2; - int &iref = i; // access to i - iref = 3; // i is now 3 - - // const reference to a member: - struct A { int x; int y; } a; - const int &x = a.x; // direct read access to A's x - x = 4; // doesn't compile - a.x = 4; // fine - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Pointers vs References} - \begin{block}{Specificities of reference} - \begin{itemize} - \item Natural syntax - \item Cannot be \cppinline{nullptr} - \item Must be assigned when defined, cannot be reassigned - \item References to temporary objects must be \cppinline{const} - \end{itemize} - \end{block} - \begin{block}{Advantages of pointers} - \begin{itemize} - \item Can be \cppinline{nullptr} - \item Can be initialized after declaration, can be reassigned - \end{itemize} - \end{block} - \pause - \begin{goodpractice}{References} - \begin{itemize} - \item Prefer using references instead of pointers - \item Mark references \cppinline{const} to prevent modification - \end{itemize} - \end{goodpractice} -\end{frame} diff --git a/talk/basicconcepts/scopesnamespaces.tex b/talk/basicconcepts/scopesnamespaces.tex deleted file mode 100644 index c49976bd..00000000 --- a/talk/basicconcepts/scopesnamespaces.tex +++ /dev/null @@ -1,244 +0,0 @@ -\subsection[NS]{Scopes / namespaces} - -\begin{frame}[fragile] - \frametitlecpp[98]{Scope} - \begin{block}{Definition} - Portion of the source code where a given name is valid \\ - Typically : - \begin{itemize} - \item simple block of code, within \cppinline{{}} - \item function, class, namespace - \item the global scope, i.e.\ translation unit (.cpp file + all includes) - \end{itemize} - \end{block} - \begin{exampleblock}{Example} - \begin{cppcode*}{} - { int a; - { int b; - } // end of b scope - } // end of a scope - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Scope and lifetime of variables} - \begin{block}{Variable life time} - \begin{itemize} - \item Variables are (statically) allocated when defined - \item Variables are freed at the end of a scope - \end{itemize} - \end{block} - \begin{goodpractice}{Initialisation} - \begin{itemize} - \item Initialise variables when allocating them! - \item This prevents bugs reading uninitialised memory - \end{itemize} - \end{goodpractice} - \begin{multicols}{2} - % the code has to be repeated n times here. Anyone finding a better solution - % is welcome, but it's not a trivial task, due to the verbatim nature of minted - \begin{overprint}[\columnwidth] - \onslide<1> - \begin{minted}[linenos,highlightlines=1]{cpp} -int a = 1; -{ - int b[4]; - b[0] = a; -} -// Doesn't compile here: -// b[1] = a + 1; - \end{minted} - \onslide<2> - \begin{minted}[linenos,highlightlines=3]{cpp} -int a = 1; -{ - int b[4]; - b[0] = a; -} -// Doesn't compile here: -// b[1] = a + 1; - \end{minted} - \onslide<3> - \begin{minted}[linenos,highlightlines=4]{cpp} -int a = 1; -{ - int b[4]; - b[0] = a; -} -// Doesn't compile here: -// b[1] = a + 1; - \end{minted} - \onslide<4> - \begin{minted}[linenos,highlightlines=7]{cpp} -int a = 1; -{ - int b[4]; - b[0] = a; -} -// Doesn't compile here: -// b[1] = a + 1; - \end{minted} - \end{overprint} - - \columnbreak - - \begin{tikzpicture} - \memorystack[word size=1, block size=4, nb blocks=5, size x = 0.5\columnwidth] - \onslide<1-> { - \memorypush{a = 1} - } - \onslide<2>{ - \memorypush{b[0] = ?} - } - \memorygoto{2} - \onslide<3>{ - \memorypush{b[0] = 1} - } - \memorygoto{3} - \onslide<2-3>{ - \memorypush{b[1] = ?} - \memorypush{b[2] = ?} - \memorypush{b[3] = ?} - } - - \memorygoto{2} - \onslide<4>{ - \memorypush{\color{gray} 1} - \memorypush{\color{gray} ?} - \memorypush{\color{gray} ?} - \memorypush{\color{gray} ?} - } - - \end{tikzpicture} - - \end{multicols} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Namespaces} - \begin{itemize} - \item Namespaces allow to segment your code to avoid name clashes - \item They can be embedded to create hierarchies (separator is '::') - \end{itemize} - \begin{multicols}{2} - \begin{cppcode*}{} - int a; - namespace n { - int a; // no clash - } - namespace p { - int a; // no clash - namespace inner { - int a; // no clash - } - } - void f() { - n::a = 3; - } - \end{cppcode*} - \columnbreak - \begin{cppcode*}{firstnumber=14} - namespace p { // reopen p - void f() { - p::a = 6; - a = 6; //same as above - ::a = 1; - p::inner::a = 8; - inner::a = 8; - n::a = 3; - } - } - using namespace p::inner; - void g() { - a = -1; // err: ambiguous - } - \end{cppcode*} - \end{multicols} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{Nested namespaces} - \begin{alertblock}{\cpp98: Old way to declare nested namespaces} - \begin{cppcode*}{} - namespace A { - namespace B { - namespace C { - //... - } - } - } - \end{cppcode*} - \end{alertblock} - \begin{exampleblock}{\cpp17: Nested declaration} - \begin{cppcode*}{} - namespace A::B::C { - //... - } - \end{cppcode*} - \end{exampleblock} - \begin{exampleblock}{\cpp17: Namespace alias} - \begin{cppcode*}{} - namespace ABC = A::B::C; - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{advanced} -\begin{frame}[fragile] - \frametitlecpp[98]{Unnamed / anonymous namespaces} - \begin{exampleblock}{A namespace without a name!} - \begin{cppcode*}{} - namespace { - int localVar; - } - \end{cppcode*} - \end{exampleblock} - \begin{block}{Purpose} - \begin{itemize} - \item groups a number of declarations - \item visible only in the current translation unit - \item but not reusable outside - \item allows much better compiler optimizations and checking - \begin{itemize} - \item e.g. unused function warning - \item context dependent optimizations - \end{itemize} - \end{itemize} - \end{block} - \begin{alertblock}{Supersedes static} - \begin{cppcode*}{firstnumber=4} - static int localVar; // equivalent C code - \end{cppcode*} - \end{alertblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Using namespace directives} - \begin{alertblock}{Avoid ``using namespace'' directives} - \begin{itemize} - \item Make all members of a namespace visible in current scope - \item Risk of name clashes or ambiguities - \end{itemize} - \begin{cppcode*}{} - using namespace std; - cout << "We can print now\n"; // uses std::cout - \end{cppcode*} - \end{alertblock} - \begin{alertblock}{Never use in headers at global scope!} - \begin{cppcode*}{} - #include "PoorlyWritten.h" // using namespace std; - struct array { ... }; - array a; // Error: name clash with std::array - \end{cppcode*} - \end{alertblock} - \begin{block}{What to do instead} - \begin{itemize} - \item Qualify names: \cppinline{std::vector}, \cppinline{std::cout}, \ldots - \item Put things that belong together in the same namespace - \item Use \textit{using declarations} in local scopes: \cppinline{using std::cout;} - \end{itemize} - \end{block} -\end{frame} - -\end{advanced} diff --git a/talk/concurrency/atomic.tex b/talk/concurrency/atomic.tex deleted file mode 100644 index 0580a041..00000000 --- a/talk/concurrency/atomic.tex +++ /dev/null @@ -1,126 +0,0 @@ -\subsection[atomic]{Atomic types} - -\begin{frame}[fragile] - \frametitlecpp[11]{Atomic types in \cpp} - \begin{block}{\texttt{std::atomic} template} - \begin{itemize} - \item Any trivially copyable type can be made atomic in C++ - \item Most useful for integral types - \item May internally use locks for custom types - \end{itemize} - \end{block} - \begin{exampleblock}{} - \begin{cppcode*}{} - std::atomic a{0}; - std::thread t1([&](){ a++; }); - std::thread t2([&](){ a++; }); - a += 2; - t1.join(); t2.join(); - assert( a == 4 ); // Guaranteed to succeed - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \begin{alertblock}{Warning: Expressions using an atomic type are \textit{not} atomic!} - \begin{cppcode*}{} - std::atomic a{0}; - std::thread t1([&]{ a = a + 2; }); - std::thread t2([&]{ a = a + 2; }); - \end{cppcode*} - \begin{itemize} - \item Atomic load; value+2; atomic store - \end{itemize} - \end{alertblock} - \begin{block}{Sequence diagram} - \begin{tikzpicture} - \begin{umlseqdiag} - \umlobject[x=0]{Thread 1} - \umlobject[x=3, fill=blue!20]{atomic} - \umlobject[x=6]{Thread 2} - \begin{umlcall}[op=load]{Thread 1}{atomic} - \end{umlcall} - \begin{umlcall}[op=+2]{Thread 1}{Thread 1} - \end{umlcall} - \begin{umlcall}[op=load]{Thread 2}{atomic} - \end{umlcall} - \begin{umlcall}[op=+2]{Thread 2}{Thread 2} - \end{umlcall} - \begin{umlcall}[op=store 2]{Thread 1}{atomic} - \end{umlcall} - \begin{umlcall}[op=store 2]{Thread 2}{atomic} - \end{umlcall} - \end{umlseqdiag} - \draw[-triangle 60](9,0) -- (9,-4) node[right, pos=0.5]{time}; - \end{tikzpicture} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \begin{block}{Solution: Use atomic member functions} - \begin{itemize} - \item The member functions of \cppinline{std::atomic} are thread safe - \item \cppinline{fetch_add} and \cppinline{operator+=}: atomic \{ load; add; store \} - \item But don't confuse ``\cppinline{a += 2}'' and ``\cppinline{a = a + 2}'' - \end{itemize} - \end{block} - \begin{exampleblock}{} - \begin{cppcode*}{} - std::atomic a{0}; - std::thread t1([&]{ a.fetch_add(2); }); - std::thread t2([&]{ a += 2; }); - \end{cppcode*} - \end{exampleblock} - \begin{block}{Sequence diagram} - \begin{tikzpicture} - \begin{umlseqdiag} - \umlobject[x=0]{Thread 1} - \umlobject[x=3, fill=blue!20]{atomic} - \umlobject[x=6]{Thread 2} - \begin{umlcall}[op=fetch\_add]{Thread 1}{atomic} - \end{umlcall} - \begin{umlcall}[op=\texttt{+=}, dt=9]{Thread 2}{atomic} - \end{umlcall} - \end{umlseqdiag} - \draw[-triangle 60](9,0) -- (9,-2) node[right, pos=0.5]{time}; - \end{tikzpicture} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Atomic references} - \begin{block}{\texttt{std::atomic\_ref} template} - \begin{itemize} - \item Wraps a \cppinline{T&} and makes access to it atomic - \item Like \cppinline{std::atomic}, but does not contain the \cppinline{T} - \end{itemize} - \end{block} - \begin{exampleblock}{} - \begin{cppcode*}{} - int a{0}; - std::thread t1([&]{ std::atomic_ref r{a}; r++;}); - std::thread t2([&]{ std::atomic_ref{a}++; }); - t1.join(); t2.join(); - a += 2; // non-atomic (fine, threads joined before) - assert( a == 4 ); // Guaranteed to succeed - \end{cppcode*} - \end{exampleblock} - \begin{alertblock}{Don't mix concurrent atomic and non-atomic access} - \begin{cppcode*}{} - std::thread t3([&]{ std::atomic_ref{a}++; }); - a += 2; // data race - t3.join(); - \end{cppcode*} - \end{alertblock} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Atomic types in \cpp} - \begin{exercise}{Atomics} - \begin{itemize} - \item Go to \texttt{exercises/atomic} - \item You'll find a program with the same race condition as in \texttt{race} - \item Fix it using \cppinline{std::atomic} - \end{itemize} - \end{exercise} -\end{frame} diff --git a/talk/concurrency/condition.tex b/talk/concurrency/condition.tex deleted file mode 100644 index d688408a..00000000 --- a/talk/concurrency/condition.tex +++ /dev/null @@ -1,129 +0,0 @@ -\subsection[condition]{Condition Variables} - -\begin{frame}[fragile] - \frametitlecpp[11]{Condition variables} - \begin{block}{Communicating between threads} - \begin{itemize} - \item Take the case where threads are waiting for other thread(s) - \item \cppinline{std::condition_variable} - \begin{itemize} - \item from \cppinline{} header - \end{itemize} - \item Allows for a thread to sleep (= conserve CPU time) until a given condition is satisfied - \end{itemize} - \end{block} - \pause - \begin{block}{Usage} - \begin{itemize} - \item Use RAII-style locks to protect shared data - \item \cppinline{wait()} will block until the condition is met - \begin{itemize} - \item you can have several waiters sharing the same mutex - \end{itemize} - \item \cppinline{notify_one()} will wake up one waiter - \item \cppinline{notify_all()} will wake up all waiters - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{Using condition variables: notify} - \begin{block}{Producer side: providing data to waiting threads} - \begin{itemize} - \item Protect data with a mutex, and use condition variable to notify consumers - \item Optimal use: don't hold lock while notifying - \begin{itemize} - \item waiting threads would be blocked - \end{itemize} - \end{itemize} - \end{block} - \begin{exampleblock}{} - \begin{cppcode*}{} - std::mutex mutex; - std::condition_variable cond; - Data data; - std::thread producer([&](){ - { - std::scoped_lock lock{mutex}; - data = produceData(); // may take long ... - } - cond.notify_all(); - }); - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Using condition variables: wait} - \vspace{-1.2\baselineskip} - \begin{overprint} - \onslide<1> - \begin{block}{Mechanics of wait} - \begin{itemize} - \item Many threads can wait for shared data - \item Pass \cppinline{unique_lock} and optional predicate to \cppinline{wait()} - \item \cppinline{wait()} keeps threads asleep while predicate is \cppinline{false} - \begin{itemize} - \item Threads might wake up spuriously, but \cppinline{wait()} returns only when lock available \emph{and} predicate \cppinline{true} - \end{itemize} - \item \cppinline{wait()} will only lock when necessary; unlocked while sleeping - \end{itemize} - \end{block} - \onslide<2-> - \begin{block}{Waiting / waking up} - \begin{itemize} - \item When \cppinline{notify_all()} is called, threads wake up - \item Threads try to lock mutex, and evaluate predicate - \item One thread succeeds to acquire mutex, starts processing data - \item {\color{red} Problem}: One thread holds mutex, other threads are blocked! - \end{itemize} - \end{block} - \end{overprint} - - \begin{alertblock}{Na\"ive waiting} - \begin{cppcode*}{highlightlines=3} - auto processData = [&](){ - std::unique_lock lock{mutex}; - cond.wait(lock, [&](){ return data.isReady(); }); - process(data); - }; - \end{cppcode*} - \end{alertblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Using condition variables: correct wait} - \begin{block}{Waiting / waking up} - \begin{itemize} - \item {\color{green!50!black} Solution:} Put locking and waiting in a scope - \item Threads will one-by-one wake up, acquire lock, evaluate predicate, release lock - \end{itemize} - \end{block} - - \begin{exampleblock}{Correct waiting} - \begin{cppcode*}{} - auto processData = [&](){ - { - std::unique_lock lock{mutex}; - cond.wait(lock, [&](){ return data.isReady(); }); - } - process(data); - }; - std::thread t1{processData}, t2{processData}, ...; - for (auto t : {&producer, &t1, &t2, ...}) t->join(); - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Condition variables} - \begin{exerciseWithShortcut}{Condition variables}{Condition vars} - \begin{itemize} - \item Go to \texttt{exercises/condition\_variable} - \item Look at the code and run it\\ - See that it has a race condition - \item Fix the race condition in the usage of the condition variable - \item Try to make threads process data in parallel - \end{itemize} - \end{exerciseWithShortcut} -\end{frame} diff --git a/talk/concurrency/mutexes.tex b/talk/concurrency/mutexes.tex deleted file mode 100644 index 5721e8d6..00000000 --- a/talk/concurrency/mutexes.tex +++ /dev/null @@ -1,249 +0,0 @@ -\subsection[mutex]{Mutexes} - -\begin{frame}[fragile] - \frametitlecpp[11]{Races} - \begin{exampleblockGB}{Example code}{https://godbolt.org/z/oGz61Pn19}{Race} - \begin{cppcode*}{} - int a = 0; - void inc() { a++; }; - void inc100() { - for (int i=0; i < 100; i++) inc(); - }; - int main() { - std::thread t1{inc100}; - std::thread t2{inc100}; - for (auto t: {&t1,&t2}) t->join(); - std::cout << a << "\n"; - } - \end{cppcode*} - \end{exampleblockGB} - \pause - \begin{block}{What do you expect? (Exercise exercises/race)} - \pause - Anything between 100 and 200 !!! - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Atomicity} - \begin{exampleblock}{Definition (wikipedia)} - \begin{itemize} - \item an operation (or set of operations) is atomic if it appears to the rest of the system to occur instantaneously - \end{itemize} - \end{exampleblock} - \begin{block}{Practically} - \begin{itemize} - \item an operation that won't be interrupted by other concurrent operations - \item an operation that will have a stable environment during execution - \end{itemize} - \end{block} - \pause - \begin{alertblock}{Is \texttt{++} operator atomic ?} - \pause - Usually not. It behaves like : - \begin{cppcode*}{} - eax = a // memory to register copy - increase eax // increase (atomic CPU instruction) - a = eax // copy back to memory - \end{cppcode*} - \end{alertblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Timing} - \begin{exampleblock}{Code} - \begin{cppcode*}{} - eax = a // memory to register copy - increase eax // increase (atomic CPU instruction) - a = eax // copy back to memory - \end{cppcode*} - \end{exampleblock} - \begin{block}{For 2 threads} - \begin{tikzpicture} - \begin{umlseqdiag} - \umlobject[x=0, class=eax]{Thread 1} - \umlobject[x=3, class=a, fill=blue!20]{Memory} - \umlobject[x=6, class=eax]{Thread 2} - \begin{umlcall}[op=read, type=synchron, return=0]{Thread 1}{Memory} - \end{umlcall} - \begin{umlcall}[padding=3, op=read, type=synchron, return=0]{Thread 2}{Memory} - \end{umlcall} - \begin{umlcallself}[op=incr, type=synchron]{Thread 1} - \end{umlcallself} - \begin{umlcallself}[op=incr, type=synchron]{Thread 2} - \end{umlcallself} - \begin{umlcall}[op=write 1]{Thread 2}{Memory} - \end{umlcall} - \begin{umlcall}[padding=3, op=write 1]{Thread 1}{Memory} - \end{umlcall} - \end{umlseqdiag} - \draw[-triangle 60](8.5,0) -- (8.5,-4) node[right, pos=0.5]{time}; - \end{tikzpicture} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{Mutexes and Locks} - \begin{block}{Concept} - \begin{itemize} - \item Use locks to serialize access to a non-atomic piece of code - \end{itemize} - \end{block} - \pause - \begin{block}{The objects} - \begin{description}[labelwidth=1.8cm] - \item[std::mutex] in the \cppinline{mutex} header. \textbf{Mut}ual \textbf{ex}clusion - \item[std::scoped\_lock] RAII to lock and unlock automatically - \item[std::unique\_lock] same, but can be released/relocked explicitly - \end{description} - \end{block} - \pause - \begin{exampleblockGB}{Practically}{https://godbolt.org/z/a5TaaPrad}{\texttt{mutex}} - \begin{cppcode*}{} - int a = 0; - std::mutex m; - void inc() { - std::scoped_lock lock{m}; - a++; - } - \end{cppcode*} - \end{exampleblockGB} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{Mutexes and Locks} - \begin{goodpractice}{Locking} - \begin{itemize} - \item Generally, use \cppinline{std::scoped_lock} - \begin{itemize} - \item Before \cpp17 use \cppinline{std::lock_guard}. - \end{itemize} - \item Hold as short as possible - \begin{itemize} - \item Consider wrapping critical section in block statement \cppinline|{ }| - \end{itemize} - \item Only if manual control needed, use \cppinline{std::unique_lock} - \end{itemize} - \end{goodpractice} - \begin{exampleblock}{} - \begin{cppcode*}{} - void function(...) { - // uncritical work ... - { - std::scoped_lock myLocks{mutex1, mutex2, ...}; - // critical section - } - // uncritical work ... - } - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Mutexes and Locks} - \begin{exerciseWithShortcut}{Mutexes and Locks}{Mutexes/Locks} - \begin{itemize} - \item Go to \texttt{exercises/race} - \item Look at the code and try it\\ - See that it has a race condition - \item Use a mutex to fix the issue - \item See the difference in execution time - \end{itemize} - \end{exerciseWithShortcut} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Dead locks} - \begin{block}{Scenario} - \begin{itemize} - \item 2 mutexes, 2 threads - \item locking order different in the 2 threads - \end{itemize} - \end{block} - \pause - \begin{block}{Sequence diagram} - \begin{tikzpicture} - \begin{umlseqdiag} - \umlobject[x=0]{Thread 1} - \umlobject[x=2.5, fill=blue!20]{Mutex A} - \umlobject[x=5, fill=blue!20]{Mutex B} - \umlobject[x=7.5]{Thread 2} - \begin{umlcall}[op=lock]{Thread 1}{Mutex A} - \end{umlcall} - \begin{umlcall}[op=lock, dt=6]{Thread 2}{Mutex B} - \end{umlcall} - \begin{umlcall}[op=lock (block), dt=6]{Thread 1}{Mutex B} - \end{umlcall} - \begin{umlcall}[op=lock (block), dt=12]{Thread 2}{Mutex A} - \end{umlcall} - \end{umlseqdiag} - \draw[-triangle 60](9,0) -- (9,-4) node[right, pos=0.5]{time}; - \end{tikzpicture} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{How to avoid dead locks} - \begin{block}{Possible solutions} - \begin{itemize} - \item \cpp17: \cppinline{std::scoped_lock lock{m1, m2};} comes with deadlock-avoidance algorithm - \item Never take several locks - \begin{itemize} - \item Or add master lock protecting the locking phase - \end{itemize} - \item Respect a strict locking order across all threads - \item Do not use locks - \begin{itemize} - \item Use other techniques, e.g.\ lock-free queues - \end{itemize} - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{Shared mutex / locks} - \begin{block}{Sharing a mutex} - \begin{itemize} - \item Normal \cppinline{std::mutex} objects cannot be shared - \item \cppinline{std::shared_mutex} to the rescue, but can be slower - \item It locks \emph{either} in exclusive \emph{or} in shared mode; never both - \end{itemize} - \end{block} - \begin{exampleblock}{} - \begin{cppcode*}{} - Data data; std::shared_mutex mutex; - auto reader = [&](){ - std::shared_lock lock{mutex}; - read(data); // Many can read - }; - std::thread r1{reader}, r2{reader}, ...; - - std::thread writer([&](){ - std::scoped_lock lock{mutex}; // exclusive - modify(data); // Only one can write - }); - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Synchronised \texttt{cout}} - \begin{block}{Parallel writing to streams} - \begin{itemize} - \item Parallel writes to streams become garbled when not synchronised - \item \cppinline{std::osyncstream} wraps and synchronises output to streams - \item Multiple instances of the osyncstream synchronise globally - \end{itemize} - \end{block} - \begin{exampleblock}{} - \begin{cppcode*}{} - void worker(const int id, std::ostream & os); - void func() { - std::osyncstream synccout1{std::cout}; - std::osyncstream synccout2{std::cout}; - std::jthread t1{worker, 0, std::ref(synccout1)}; - std::jthread t2{worker, 1, std::ref(synccout2)}; - } - \end{cppcode*} - \end{exampleblock} -\end{frame} diff --git a/talk/concurrency/threadlocal.tex b/talk/concurrency/threadlocal.tex deleted file mode 100644 index 0473a91f..00000000 --- a/talk/concurrency/threadlocal.tex +++ /dev/null @@ -1,27 +0,0 @@ -\subsection[TLS]{Thread-local storage} - -\begin{frame}[fragile] - \frametitlecpp[20]{Thread-local storage} - \begin{block}{\cppinline{thread_local} keyword} - \begin{itemize} - \item A variable can be declared \cppinline{thread-local} - \item Then every thread will have its own copy - \item Most useful for ``working memory'' in each thread - \item Note: Can also be declared directly on the stack of a thread - \begin{itemize} - \item and will be faster, thus should be preferred when possible - \end{itemize} - \end{itemize} - \end{block} - \begin{exampleblock}{} - \begin{cppcode*}{} - thread_local int a{0}; - { - std::jthread t1([&] { a++; }); - std::jthread t2([&] { a++; }); - a += 2; - } - assert( a == 2 ); // Guaranteed to succeed - \end{cppcode*} - \end{exampleblock} -\end{frame} diff --git a/talk/concurrency/threadsasync.tex b/talk/concurrency/threadsasync.tex deleted file mode 100644 index 26a16357..00000000 --- a/talk/concurrency/threadsasync.tex +++ /dev/null @@ -1,176 +0,0 @@ -\subsection[thr]{Threads and async} - -\begin{frame}[fragile] - \frametitlecpp[11]{Basic concurrency} - \begin{block}{Threading} - \begin{itemize} - \item \cpp11 added \cppinline{std::thread} in \cppinline{} header - \item takes a function as argument of its constructor - \item must be detached or joined before the main thread terminates - \end{itemize} - \end{block} - - \begin{exampleblock}{Example code} - \begin{cppcode*}{} - void foo() {...} - void bar() {...} - int main() { - std::thread t1{foo}; - std::thread t2{bar}; - for (auto t: {&t1,&t2}) t->join(); - return 0; - } - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{The thread constructor} - \begin{exampleblock}{Can take a function and its arguments} - \begin{cppcode*}{} - void function(int j, double j) {...} - std::thread t1{function, 1, 2.0}; - \end{cppcode*} - \end{exampleblock} - \pause - \begin{exampleblock}{Can take any function-like object} - \begin{cppcode*}{} - struct AdderFunctor { - AdderFunctor(int i): m_i(i) {} - int operator() (int j) const { return m_i+j; } - int m_i; - }; - std::thread t2{AdderFunctor{2}, 5}; - int a; - std::thread t3{[](int i) { return i+2; }, a}; - std::thread t4{[a] { return a+2; }}; - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{\texttt{std::jthread}} - \begin{goodpractice}[jthread vs.\ thread]{Prefer \cppinline{std::jthread} if \cpp20 is available} - \begin{itemize} - \item In \cppinline{} header since \cpp20 - \item Automatically joins on destruction - \item Can be stopped from outside - \end{itemize} - \end{goodpractice} - - \begin{exampleblock}{Example with jthread} - \begin{cppcode*}{} - void foo() {...} - void bar() {...} - int main() { - std::jthread t1{foo}; - std::jthread t2{bar}; - // No join required - return 0; - } - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Using jthread's stop\_token} - \begin{block}{} - \begin{itemize} - \item Like \cppinline{std::thread}, \cppinline{jthread} can take a function or functors/lambdas and their arguments - \item New: Can take functions that handle \cppinline{stop_token}s - \end{itemize} - \end{block} - \begin{exampleblock}{stop\_token in a function} - \begin{cppcode*}{} - void function(std::stop_token st, int j) { - while (!st.stop_requested()) { - // ... - }} - std::jthread t1{function, 1}; - t1.request_stop(); - \end{cppcode*} - \end{exampleblock} - \begin{exampleblock}{A lambda with a stop\_token} - \begin{cppcode*}{} - std::jthread t1{ - [](std::stop_token st, int i){ ... }, 1}; - \end{cppcode*} - \end{exampleblock} -\end{frame} - - -\begin{frame}[fragile] - \frametitlecpp[11]{Basic asynchronicity} - \begin{block}{Concept} - \begin{itemize} - \item separation of the specification of what should be done and the retrieval of the results - \item ``start working on this, and let me check if it's done'' - \end{itemize} - \end{block} - \pause - \begin{block}{Practically} - \begin{itemize} - \item \cppinline{std::async} function launches an asynchronous task - \item \cppinline{std::future} allows to retrieve the result - \end{itemize} - \end{block} - \pause - \begin{exampleblock}{Example code} - \begin{cppcode*}{} - int f() {...} - std::future res = std::async(f); - std::cout << res.get() << "\n"; - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Mixing the two} - \begin{block}{Is async running concurrently ?} - \begin{itemize} - \item it depends! - \item you can control this with a launch policy argument - \begin{description} - \item[std::launch::async] start executing immediately on a separate thread (may be a new thread, a thread pool, ...) - \item[std::launch::deferred] causes lazy execution in current thread - \end{description} - \begin{itemize} - \item execution starts when \cppinline{get()} is called on the returned future - \end{itemize} - \item default is not specified, but tries to use existing concurrency! - \end{itemize} - \end{block} - \pause - \begin{exampleblockGB}{Usage}{https://godbolt.org/z/oMGz5jhMr}{\texttt{std::async}} - \begin{cppcode*}{} - int f() {...} - auto res1 = std::async(std::launch::async, f); - auto res2 = std::async(std::launch::deferred, f); - \end{cppcode*} - \end{exampleblockGB} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Fine-grained control on asynchronous execution} - \begin{block}{\texttt{std::packaged\_task} template} - \begin{itemize} - \item creates an asynchronous version of any function-like object - \begin{itemize} - \item identical arguments - \item returns a \cppinline{std::future} - \end{itemize} - \item provides access to the returned future - \item associated with threads, gives full control on execution - \end{itemize} - \end{block} - \pause - \begin{exampleblock}{Usage} - \begin{cppcode*}{} - int f() { return 42; } - std::packaged_task task{f}; - auto future = task.get_future(); - task(); - std::cout << future.get() << std::endl; - \end{cppcode*} - \end{exampleblock} -\end{frame} diff --git a/talk/expert/coroutines.tex b/talk/expert/coroutines.tex deleted file mode 100644 index dc19993e..00000000 --- a/talk/expert/coroutines.tex +++ /dev/null @@ -1,563 +0,0 @@ -\subsection{Coroutines} - -\begin{frame}[fragile] - \frametitlecpp[20]{Why do we need coroutines?} - \begin{block}{The generator use case (one of several)} - In python one can write - {\scriptsize - \begin{pythoncode*}{} - for i in range(0, 10): - print(i) - \end{pythoncode*} - } - What about it in \cpp? - {\scriptsize - \begin{cppcode*}{firstnumber=3} - someType range(int first, int last) { ... } - for (auto i : range(0, 10)) { - std::cout << i << "\n"; - } - \end{cppcode*} - } - How can we implement range? - \end{block} - \begin{exampleblock}{Requirements} - \begin{itemize} - \item \cppinline{someType} needs to be some iterable type - \item \cppinline{range} should execute lazily, only creating values on demand - \item meaning \cppinline{range} should be suspended and resumed - \end{itemize} - That's what coroutines are for! - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{What \cpp20 allows} - \begin{exampleblock}{Interesting part of the implementation (see \href{https://en.cppreference.com/w/cpp/coroutine/coroutine\_handle\#Example}{\color{blue!50!white}cppreference})} - {\scriptsize - \begin{cppcode*}{} - template - Generator range(T first, const T last) { - while (first < last) { - co_yield first++; - } - } - for (const char i : range(65, 91)) { - std::cout << i << ' '; - } - std::cout << '\n'; - \end{cppcode*} - } - \end{exampleblock} - \begin{alertblock}{The bad news} - \begin{itemize} - \item class \cppinline{Generator} is not provided by the STL - \item and is $\sim80$ lines of boiler plate code... - \item may be sorted out in \cpp23 - \item in the meantime, we'll have to dive into some details! - \end{itemize} - \end{alertblock} -\end{frame} - -\begin{frame} - \frametitlecpp[20]{A few concepts first} - \begin{block}{Definition of a coroutine} - \begin{itemize} - \item a function which can be suspended and resumed - \begin{itemize} - \item potentially by another caller (even on a different thread) - \end{itemize} - \item practically a function using one of: - \begin{description} - \item[\cppinline{co_await}] suspends execution - \item[\cppinline{co_yield}] suspends execution and returns a value - \item[\cppinline{co_return}] completes execution - \end{description} - \end{itemize} - \end{block} - \begin{alertblock}{Implications} - \begin{itemize} - \item on suspension, the state of the function needs to be preserved - \item the suspended function becomes pure data on the heap - \item access to this data is given via the returned value - \begin{itemize} - \item so the returned type must follow some convention - \item it needs to contain a \cppinline{struct promise_type} - \end{itemize} - \end{itemize} - \end{alertblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Minimal code} - \begin{block}{Definition of an empty coroutine} - {\scriptsize - \begin{cppcode*}{firstnumber=3} - #include - struct Task { - struct promise_type { - Task get_return_object() { return {}; } - std::suspend_never initial_suspend() { return {}; } - std::suspend_never final_suspend() noexcept { return {}; } - void return_void() {} - void unhandled_exception() { throw; } - }; - }; - Task myCoroutine() { co_return; } - int main() { Task x = myCoroutine(); } - \end{cppcode*} - } - \end{block} - \begin{exampleblock}{\texttt{promise\_type} interface} - \begin{description}[\small \cppinline{initial/final_suspend}] - \setlength{\itemsep}{0pt} - \item[\small \cppinline{get_return_object}] builds a Task from the given promise - \item[\small \cppinline{initial/final_suspend}] called before/after coroutine starts/ends - \item[\small \cppinline{unhandled_exception}] called in case of exception in coroutine - \item[\small \cppinline{return_void/value}] returns final value of the coroutine - \end{description} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Minimal sequence of events (nothing suspended)} - \begin{block}{Compiler generated set of calls when calling \cppinline{myCoroutine}} - \center - \begin{tikzpicture}[->, node distance=.75cm, font=\tiny, scale=0.8, every node/.style={scale=0.8},xscale=6,-{Latex[length=1mm,width=1mm]}] - \tikzstyle{call}=[rectangle,draw=black,thick,inner sep=6pt,rounded corners,minimum width=4.5cm,minimum height=.6cm,fill=red!30] - \tikzstyle{comp}=[trapezium,trapezium left angle=70,trapezium right angle=110,draw=black,thick,inner sep=6pt,trapezium stretches=true,minimum width=4.5cm,minimum height=.6cm,fill=blue!30] - \tikzstyle{box}=[rectangle,draw=black,thick,inner sep=6pt,minimum width=4.5cm,minimum height=.6cm,fill=green!30] - \node[call] at (0, 0) (initCall) {call to coroutine}; - \node[comp] at (0,-1) (allocState) {allocate coroutine state on the heap}; - \node[comp] at (1,-1) (construct) {construct promise inside coroutine state}; - \node[box] at (0,-2) (getReturn) {\texttt{ro = promise.get\_return\_object()}}; - \node[comp] at (1,-2) (localVar) {\texttt{ro} returned to caller}; - \node[box] at (0,-3) (initSuspend) {\texttt{promise.initial\_suspend()}}; - \node[box] at (1,-3) (initWait) {\texttt{co\_await} on result}; - \node[call] at (0,-4) (body) {coroutine body}; - \node[box] at (1,-4) (coreturn) {\texttt{co\_return}}; - \node[box] at (1,-5) (finalSuspend) {\texttt{promise.final\_suspend()}}; - \node[box] at (0,-6) (finalWait) {\texttt{co\_await} on result}; - \node[box] at (0,-5) (return) {\texttt{promise.return\_void()}}; - \node[comp] at (1,-6) (destroyP) {destroy promise}; - \node[call] at (0,-7) (caller) {caller}; - \node[comp] at (1,-7) (destroyC) {destroy coroutine}; - \draw (initCall) edge (allocState) - (allocState) edge (construct) - (construct) -- +(0,-.5) -| +(-1,-0.5) edge (getReturn) - (getReturn) edge (localVar) - (localVar.east) -- +(0.1,0) |- (1,-7.5) -| (caller); - \draw (getReturn) edge (initSuspend) - (initSuspend) edge (initWait) - (initWait) -- +(0,-.5) -| (body) - (body) edge (coreturn) - (coreturn) -- +(0,-.5) -| (return) - (return) edge (finalSuspend) - (finalSuspend) -- +(0,-.5) -| (finalWait) - (finalWait) edge (destroyP) - (destroyP) edge (destroyC) - (destroyC) edge (caller); - \node[call,minimum width=1cm] at (.7, 0) {user code}; - \node[comp,minimum width=1cm] at (1, 0) {compiler}; - \node[box, minimum width=1cm] at (1.3, 0) {promise}; - \end{tikzpicture} - \end{block} - \vspace{-2mm} - \tiny Credits : original idea for this graph comes from \href{https://itnext.io/c-20-coroutines-complete-guide-7c3fc08db89d}{this web site} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Suspending a coroutine} - \begin{block}{Main way to suspend a coroutine: \cppinline{co_wait}} - \begin{itemize} - \item it's an expression taking an ``awaitable''/ ``awaiter'' - \begin{itemize} - \item we'll ignore the distinction for now - \end{itemize} - \item 2 trivial awaiters are provided by the STL: \cppinline{std::suspend_always} and \cppinline{std::suspend_never} - \item obviously only the first one will trigger a suspension - \begin{itemize} - \item note the other one is used in the minimal code - \end{itemize} - \item more details on awaiters later - \end{itemize} - \end{block} - \begin{exampleblock}{Code} - {\scriptsize - \begin{cppcode*}{} - Task myCoroutine() { - std::cout << "Step 1 of coroutine\n"; - co_await std::suspend_always{}; - std::cout << "Step 2 of coroutine\n"; - co_await std::suspend_always{}; - std::cout << "final step\n"; - } - \end{cppcode*} - } - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Resuming a coroutine} - \begin{block}{Principles} - \begin{itemize} - \item one needs to call \cppinline{resume()} on the \cppinline{coroutine_handle} - \item BUT user code has no such handle - \begin{itemize} - \item only the coroutine return object (here a \cppinline{Task} instance) - \end{itemize} - \item so one has to amend the Task class - \begin{itemize} - \item and the \cppinline{promise_type} as it's building the \cppinline{Task} instance - \end{itemize} - \end{itemize} - \end{block} - \begin{exampleblock}{Code} - {\scriptsize - \begin{cppcode*}{} - struct Task { - struct promise_type { - Task get_return_object() { - // build Task with the coroutine handle - return {std::coroutine_handle::from_promise(*this)}; - } - ... // rest is unchanged - }; - std::coroutine_handle h_; - void resume() { h_.resume(); } - }; - \end{cppcode*} - } - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Resuming a coroutine} - \scriptsize - \begin{exampleblockGB}{User code}{https://godbolt.org/z/qx46Pa4v3}{Coroutine resumption} - \begin{cppcode*}{} - Task myCoroutine() { - std::cout << "Step 1 of coroutine\n"; - co_await std::suspend_always{}; - std::cout << "Step 2 of coroutine\n"; - co_await std::suspend_always{}; - std::cout << "final step\n"; - } - int main() { - auto c = myCoroutine(); // Step 1 runs - std::cout << "In main, between Step 1 and 2\n"; - c.resume(); // Step 2 runs - std::cout << "In main, between Step 2 and final step\n"; - c.resume(); // final Step runs - // c.resume(); // would segfault! - } - \end{cppcode*} - \end{exampleblockGB} - \begin{block}{} - \begin{minted}{text} - Step 1 of coroutine - In main, between Step 1 and 2 - Step 2 of coroutine - In main, between Step 2 and final step - final step - \end{minted} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{A few more details} - \begin{block}{About suspension of coroutines} - \begin{itemize} - \item \cppinline{initial/final_suspend} methods allow to suspend a coroutine at the very start/end (after \cppinline{co_return}) - \item a suspended coroutine is not deallocated - \begin{itemize} - \item i.e.\ its state will stay on the heap - \item so you can leak coroutines! - \end{itemize} - \item one can directly call \cppinline{coroutine_handle::destroy} if the execution of a suspended coroutine should be aborted - \begin{itemize} - \item which requires another piece of code in \cppinline{Task}, e.g. - {\scriptsize - \begin{cppcode*}{linenos=false} - ~Task() { if (h_) h_.destroy(); } - \end{cppcode*} - } - \end{itemize} - \item the \cppinline{Task} class should be move only - \end{itemize} - \end{block} - \begin{alertblock}{We need standard \cppinline{Task} classes in the STL!} - \begin{itemize} - \item \cppinline{std::generator} may come in \cpp23 - \end{itemize} - \end{alertblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{\texttt{co\_yield} - returning a value upon suspension} - \begin{block}{What \texttt{co\_yield} really is} - \begin{itemize} - \item an expression like \cppinline{co_await} - \item a shortcut for \cppinline{co_await promise.yield_value(expr)} - \item and we have to provide the \cppinline{yield_value} method of \cppinline{promise_type} and the \cppinline{Task} accessor - \end{itemize} - \end{block} - \begin{exampleblock}{Typical code} - {\scriptsize - \begin{cppcode*}{} - template struct Task { - struct promise_type { - T value_; - std::suspend_always yield_value(T&& from) { - value_ = std::forward(from); // caching the result - return {}; - } - ... // rest is unchanged - }; - T getValue() { return h_.promise().value_; } // accessor for user code - }; - \end{cppcode*} - } - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{\texttt{co\_yield} - generator behavior} - \begin{block}{Generator behavior - more boiler plate code} - {\scriptsize - \begin{cppcode*}{} - template - struct Task { - struct iterator { - std::coroutine_handle handle; - auto &operator++() { - handle.resume(); - if (handle.done()) { handle = nullptr; } // == end iterator - return *this; - } - auto operator++(int) { ++*this; } - T const& operator*() const { return handle.promise().value_; } - ... - }; - iterator begin() { resume(); return {h_}; } - iterator end() { return {nullptr}; } - ... // plus error handling is missing - }; - \end{cppcode*} - } - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{\texttt{co\_yield} - final usage} - \begin{exampleblockGB}{Finally, we can use the generator nicely}{https://godbolt.org/z/6bbrYrss5}{\texttt{co\_yield}} - {\scriptsize - \begin{cppcode*}{} - Task range(int first, int last) { - while (first != last) { - co_yield first++; - } - } - for (int i : range(0, 10)) { - std::cout << i << ""; - } // 1 2 3 4 5 6 7 8 9 - \end{cppcode*} - } - \end{exampleblockGB} - \pause - \begin{alertblock}{Wait a minute: 0 is missing in the output!} - \begin{itemize} - \item resume called in \cppinline{operator++} before 0 is printed - \item we should pause in \cppinline{initial_suspend} - \end{itemize} - {\scriptsize - \begin{cppcode*}{firstnumber=10} - struct Task { - struct promise_type { - ... - std::suspend_always initial_suspend() { return {}; } - ... - } - }; - \end{cppcode*} - } - \end{alertblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Laziness allows for infinite ranges} - \begin{exampleblockGB}{Generators do not need to be finite}{https://godbolt.org/z/MP6qdGWYe}{Infinite generator} - \begin{cppcode*}{} - Task range(int first) { - while (true) { - co_yield first++; - } - } - for (int i : range(0) | std::views::take(10)) { - std::cout << i << "\n"; - } - \end{cppcode*} - \end{exampleblockGB} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Real life example} - \begin{exampleblockGB}{A Fibonacci generator, from \cpprefLink{https://en.cppreference.com/w/cpp/language/coroutines}}{https://godbolt.org/z/3Pev1M8se}{Fibonacci generator} - \scriptsize - \begin{cppcode*}{} - Task fibonacci(unsigned n) { - if (n==0) co_return; - co_yield 0; - if (n==1) co_return; - co_yield 1; - if (n==2) co_return; - uint64_t a=0; - uint64_t b=1; - for (unsigned i = 2; i < n; i++) { - uint64_t s=a+b; - co_yield s; - a=b; - b=s; - } - } - - int main() { - for (int i : fibonacci(10)) { - std::cout << i << "\n"; - } - } - \end{cppcode*} - \end{exampleblockGB} -\end{frame} - -\begin{frame} - \frametitlecpp[20]{Coming back to awaitables/awaiters} - \begin{block}{awaitables vs awaiters} - \begin{itemize} - \item awaitable is the type required by \cppinline{co_await}/\cppinline{co_yield} - \begin{itemize} - \item or the expression given has to be convertible to awaitable - \item alternatively the \cppinline{promise_type} can have an \cppinline{await_transform} method returning an awaitable - \end{itemize} - \item an awaiter is retrieved from the awaitable by the compiler - \begin{itemize} - \item either by calling operator \cppinline{co_wait} on it - \item or via direct conversion if no such operator exists - \end{itemize} - \item an awaiter has 3 main methods - \begin{itemize} - \item \cppinline{await_ready}, \cppinline{await_suspend} \cppinline{and await_resume} - \end{itemize} - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{How awaiters work} - \begin{block}{Compiler generated set of calls} - \center - \begin{tikzpicture}[->, node distance=.75cm, font=\tiny, scale=0.8, every node/.style={scale=0.8},xscale=6,-{Latex[length=1mm,width=1mm]}] - \tikzstyle{call}=[rectangle,draw=black,thick,inner sep=6pt,rounded corners,minimum width=4.5cm,minimum height=.6cm,fill=red!30] - \tikzstyle{comp}=[trapezium,trapezium left angle=70,trapezium right angle=110,draw=black,thick,inner sep=6pt,trapezium stretches=true,minimum width=4.5cm,minimum height=.6cm,fill=blue!30] - \tikzstyle{box}=[rectangle,draw=black,thick,inner sep=6pt,minimum width=4.5cm,minimum height=.6cm,fill=green!30] - \tikzstyle{choice}=[diamond,draw=black,thick,inner sep=3pt,minimum width=4.5cm,minimum height=.6cm,fill=green!30,aspect=5] - \node[call] at (0, 0) (co_await) {\texttt{co\_await} awaitable}; - \node[choice] at (0,-1) (await_ready) {\texttt{awaiter.await\_ready()}}; - \node[comp] at (1,-1) (suspend) {coroutine suspended}; - \node[choice] at (.5,-2.5) (await_suspend) {\texttt{awaiter.await\_suspend(handle)}}; - \node[comp] at (0,-4) (handleresume) {\texttt{handle.resume()}}; - \node[call] at (1,-4) (caller) {coroutine caller}; - \node[comp] at (0,-5) (corofin) {coroutine behind handle suspended or finished}; - \node[call] at (1,-5) (callresume) {caller calls \texttt{resume}}; - \node[comp] at (0,-6) (resumed) {coroutine resumed}; - \node[box] at (1,-6) (await_resume) {\texttt{awaiter.await\_resume()}}; - \node[call] at (1,-7) (body) {continue coroutine body}; - \draw (co_await) edge (await_ready) - (await_ready) edge node[above] {false} (suspend) - (await_ready.west) -- node[above] {true} +(-0.1,0) |- (body); - \draw (suspend) -- +(0,-.5) -| (await_suspend); - \draw (await_suspend) -- node[above,pos=.1] {false} +(-.95,0) |- (resumed); - \draw (await_suspend) edge node[text width=1cm,left,pos=.3] {coroutine handle} (handleresume) - (handleresume) edge (corofin) - (corofin) edge (resumed) - (await_suspend) |- node[right,pos=0.1] {\texttt{true}} (caller) - (caller) edge (callresume) - (callresume) -- +(0,-.5) -| (resumed) - (await_suspend) -| node[right,pos=0.6] {\texttt{void}} (caller) - (resumed) edge (await_resume) - (await_resume) edge (body); - \node[call,minimum width=1cm] at (.7, 0) {user code}; - \node[comp,minimum width=1cm] at (1, 0) {compiler}; - \node[box, minimum width=1cm] at (1.3, 0) {awaiter}; - \end{tikzpicture} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{\texttt{awaiter} example} - \begin{exampleblockGB}{Switch to new thread, from \cpprefLink{https://en.cppreference.com/w/cpp/language/coroutines}}{https://godbolt.org/z/K7svE4P7s}{Thread switching} - \scriptsize - \begin{cppcode*}{} - auto switch_to_new_thread(std::jthread& out) { - struct awaiter { - std::jthread* th; - bool await_ready() { return false; } - void await_suspend(std::coroutine_handle<> h) { - *th = std::jthread([h] { h.resume(); }); - std::cout << "New thread ID: " << th->get_id() << '\n'; - } - void await_resume() {} - }; - return awaiter{&out}; - } - Task resuming_on_new_thread(std::jthread& out) { - std::cout << "Started on " << std::this_thread::get_id() << '\n'; - co_await switch_to_new_thread(out); - std::cout << "Resumed on " << std::this_thread::get_id() << std::endl; - } - int main() { - std::jthread out; - resuming_on_new_thread(out); - } - \end{cppcode*} - \end{exampleblockGB} - \pause - \vspace{-2.1cm} - \begin{columns} - \begin{column}{.45\textwidth} - \end{column} - \begin{column}{.55\textwidth} - \setlength{\textwidth}{5.4cm} - \raggedright - \begin{block}{Output} - \scriptsize - \begin{minted}{text} - Started on thread: 140144191063872 - New thread ID: 140144191059712 - Resumed on thread: 140144191059712 - \end{minted} - \end{block} - \end{column} - \end{columns} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Summary on coroutines} - \begin{exampleblock}{Coroutines are usable in \cpp20} - \begin{itemize} - \item allow to have nice generators - \item also very useful for async/IO code - \begin{itemize} - \item another big use case which we did not touch - \end{itemize} - \end{itemize} - \end{exampleblock} - \begin{alertblock}{But library support is poor for now} - \begin{itemize} - \item standard Task/Generator classes are not provided - \item leading to \emph{lots of boiler plate code} for the end user - \item \cppinline{std::generator} is part of \cpp23's draft - \item in the meantime, libraries exist, e.g. \href{https://github.com/lewissbaker/cppcoro}{CppCoro} - \end{itemize} - \end{alertblock} -\end{frame} diff --git a/talk/expert/cpp20concepts.tex b/talk/expert/cpp20concepts.tex deleted file mode 100644 index f77a9657..00000000 --- a/talk/expert/cpp20concepts.tex +++ /dev/null @@ -1,291 +0,0 @@ -\subsection[concepts]{Concepts} - -\begin{frame}[fragile] - \frametitlecpp[20]{Requirements and concepts} - \begin{block}{Motivation} - \begin{itemize} - \item Generic programming is made of variable, function and class templates which can be instantiated with different types. - \item It is frequent to instantiate them with \textbf{unsuited types}, and the resulting compilation errors are cryptic. - \item As a last resort, authors provide \textbf{documentation}, and practice tricky \textbf{template meta-programming}. - \item C++20 brings \textbf{simpler ways to define constraints} on template parameters. - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{The world before concepts} - \begin{block}{\cpp17 work around: SFINAE} - \begin{itemize} - \item Unsuited arguments can be avoided by inserting fake template arguments, - leading to a substitution failure - \end{itemize} - \end{block} - \begin{exampleblockGB}{Practical code}{https://godbolt.org/z/e4T9q1jfh}{SFINAE failure} - \scriptsize - \begin{cppcode*}{} - template - >> - bool equal( T e1, T e2 ) { - return std::abs(e1-e2) < std::numeric_limits::epsilon(); - } - ... equal(10,5+5) ... - \end{cppcode*} - \pause - \tiny - \begin{Verbatim}[commandchars=\|\[\]] -|fvtextcolor[blue][:11:12:] |fvtextcolor[red][error:] |fvtextcolor[blue][no matching function for call to 'equal(int, int)'] - 11 | if (|fvtextcolor[red][equal(10,5+5)]) { std::cout << "FAILURE\n"; } -|fvtextcolor[blue][:7:6:] |fvtextcolor[blue!50!green][note:] |fvtextcolor[blue][candidate: 'template bool equal(T, T)'] - 7 | bool |fvtextcolor[blue!50!green][equal]( T e1, T e2 ) -|fvtextcolor[blue][:7:6:] |fvtextcolor[blue!50!green][note:] |fvtextcolor[blue][template argument deduction/substitution failed:] -In file included from :1: -.../type_traits: In substitution of 'template -using enable_if_t = typename std::enable_if::type [with bool _Cond = false; _Tp = void]': -|fvtextcolor[blue][:6:14: required from here] -.../type_traits:2514:11: |fvtextcolor[red][error:] no type named 'type' in 'struct std::enable_if' - 2514 | using |fvtextcolor[red][enable_if_t] = typename enable_if<_Cond, _Tp>::type; - \end{Verbatim} - \end{exampleblockGB} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Basic requirements} - \begin{block}{A new keyword} - \begin{itemize} - \item The keyword \cppinline{requires} lets us define various constraints. - \end{itemize} - \end{block} - \begin{exampleblockGB}{With concepts}{https://godbolt.org/z/dWvM9Pvee}{concept failure} - \scriptsize - \begin{cppcode*}{} - template - requires std::is_floating_point_v - bool equal( T e1, T e2 ) { - return std::abs(e1-e2) < std::numeric_limits::epsilon(); - } - ... equal(10,5+5) ... - \end{cppcode*} - \pause - \tiny - \begin{Verbatim}[commandchars=\|\[\]] -|fvtextcolor[blue][:11:12:] |fvtextcolor[red][error:] |fvtextcolor[blue][no matching function for call to 'equal(int, int)'] - 11 | if (|fvtextcolor[red][equal(10,5+5)]) { std::cout << "FAILURE\n"; } -|fvtextcolor[blue][:7:6:] |fvtextcolor[blue!50!green][note:] |fvtextcolor[blue][candidate: 'template bool equal(T, T)'] - 7 | bool |fvtextcolor[blue!50!green][equal]( T e1, T e2 ) -|fvtextcolor[blue][:7:6:] |fvtextcolor[blue!50!green][note:] |fvtextcolor[blue][template argument deduction/substitution failed:] -|fvtextcolor[blue][:7:6:] |fvtextcolor[blue!50!green][note:] |fvtextcolor[blue][constraints not satisfied] -: In substitution of 'template ... bool equal(T, T) [with T = int]': -|fvtextcolor[blue][:11:12: required from here] -|fvtextcolor[blue][:7:6: required by the constraints of 'template ... bool equal(T, T)'] -|fvtextcolor[blue][:6:15:] |fvtextcolor[blue!50!green][note:] |fvtextcolor[blue][the expression 'is_floating_point_v [with T = int]' evaluated to 'false'] - 6 | requires |fvtextcolor[blue!50!green][std::is_floating_point_v] - \end{Verbatim} - \end{exampleblockGB} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Requirements and overloads} - \begin{exampleblock}{Example of several competing templates} - \small - \begin{cppcode*}{} - template - bool equal( T e1, T e2 ) { return (e1==e2); } - - template< typename T> - requires std::is_floating_point_v - bool equal( T e1, T e2 ) - {return std::abs(e1-e2)::epsilon();} - \end{cppcode*} - \end{exampleblock} - \begin{block}{Requirements affect overload resolution} - \begin{itemize} - \item Overload resolution considers the second function as a better match when the requirements are fulfilled. - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Concepts} - \begin{block}{Definition} - \begin{itemize} - \item a \textbf{concept} gives a name to a given set of requirements - \item useful when the same requirements are reused frequently - \end{itemize} - \end{block} - \begin{exampleblock}{A new keyword: \texttt{concept}} - \small - \begin{cppcode*}{} - template< typename T> - concept MyFloatingPoint = - std::is_floating_point_v && - std::numeric_limits::epsilon() > 0; - - template - requires MyFloatingPoint - bool equal( T e1, T e2 ) - {return std::abs(e1-e2)::epsilon();} - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Some usages of concepts} - \begin{block}{Constrained template parameters} - \begin{itemize} - \item a concept can replace \cppinline{typename} in a template parameter list - \end{itemize} - \end{block} - \begin{exampleblock}{} - \small - \begin{cppcode*}{} - template - bool equal( T e1, T e2 ) { - return std::abs(e1-e2)::epsilon(); - } - \end{cppcode*} - \end{exampleblock} - \begin{block}{Constrained variables} - \begin{itemize} - \item a concept can be used together with \cppinline{auto} to impose requirements on the type of a variable - \end{itemize} - \end{block} - \begin{exampleblock}{Example code} - \begin{cppcode*}{firstnumber=4} - MyFloatingPoint auto f = 3.14f; - MyFloatingPoint auto d = 3.14; - MyFloatingPoint auto i = 3; // compile error - \end{cppcode*} - \end{exampleblock} -\end{frame} - - -\begin{frame}[fragile] - \frametitlecpp[20]{Some usages of concepts} - \begin{block}{Abbreviated function templates} - \begin{itemize} - \item function parameters can be constrained as well - \begin{itemize} - \item similar to variables - \end{itemize} - \item the template head becomes obsolete - \item the function is still a template though! - \item unconstrained \cppinline{auto} parameters are allowed as well - \end{itemize} - \end{block} - \begin{exampleblock}{} - \small - \begin{cppcode*}{} - // no template <...> here! - bool equal( MyFloatingPoint auto e1, - MyFloatingPoint auto e2 ) { - return std::abs(e1-e2) < - std::numeric_limits::epsilon(); - } - - // unconstrained abbreviated function template: - void equal(auto e1, auto e2) { ... } - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Standard concepts} - \begin{block}{Never reinvent the wheel} - \begin{itemize} - \item Writing a bug-proof concept is an expert task - \item Prefer the ones provided by the standard library - \end{itemize} - \end{block} - \begin{exampleblock}{E.g.: the floating point concept} - \small - \begin{cppcode*}{} - #include - bool equal( std::floating_point auto e1, - std::floating_point auto e2 ) { - return std::abs(e1-e2) < - std::numeric_limits::epsilon(); - } - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Checking concepts} - \begin{block}{Concepts as Boolean operators} - \begin{itemize} - \item Concepts can be used wherever a \mintinline{c}{bool} is expected - \item they can appear in \cppinline{if constexpr} conditions - \begin{itemize} - \item since they are evaluated at compile-time - \end{itemize} - \end{itemize} - \end{block} - \begin{exampleblock}{Using concepts with \texttt{if constexpr}} - \small - \begin{cppcode*}{} - template - bool equal( T e1, T e2 ) - { - if constexpr (std::floating_point) { - return std::abs(e1-e2) - < std::numeric_limits::epsilon(); - } else { - return (e1==e2); - } - } - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Advanced requirements overview} - \begin{block}{\texttt{requires} as an expression} - \cppinline{requires} can express more than basic requirements. It can - \begin{itemize} - \item include other basic requirements - \item list expressions that must be valid - \item check the return type of some expressions - \end{itemize} - \end{block} - \begin{exampleblock}{Practically} - \small - \begin{cppcode*}{} - template - concept StreamableAndComparableNumber = - requires( T v1, T v2, std::ostream os ) { - requires std::integral || std::floating_point; - os< std::convertible_to; - }; - \end{cppcode*} - \end{exampleblock} - \begin{block}{} - Remember: use standard concepts first - \end{block} -\end{frame} - -\begin{frame} - \frametitlecpp[20]{Requirements and concepts} - \begin{block}{Summary} - \begin{itemize} - \item A template can now \emph{require} properties of its parameters - \item Compiler error messages clearly state which argument does not fulfill which requirement - \item A set of requirements can be gathered in a \emph{concept} - \item Overload resolution takes requirements into account - \item The standard library provides many ready-to-use concepts - \item Writing a new good concept is an expert task - \end{itemize} - \end{block} -\end{frame} - -\begin{frame} - \frametitlecpp[20]{Exercise time} - \begin{exercise}{Concepts} - \begin{itemize} - \item go to \texttt{exercises/concepts} - \item you will use concepts to optimize some loop on iterators - \item follow the instructions in the source code - \end{itemize} - \end{exercise} -\end{frame} diff --git a/talk/expert/cpp20spaceship.tex b/talk/expert/cpp20spaceship.tex deleted file mode 100644 index 7a3770e5..00000000 --- a/talk/expert/cpp20spaceship.tex +++ /dev/null @@ -1,165 +0,0 @@ -\subsection[spaceship]{The \texttt{<=>} operator} - -\begin{frame}[fragile] - \frametitle{The burden of comparison operators} - \begin{block}{Motivation} - \begin{itemize} - \item One often needs \cppinline{operator<} for a user-defined class - \begin{itemize} - \item e.g.\ when sorting a \cppinline{std::vector} - \item e.g.\ when using it as a key for \cppinline{std::set} or \cppinline{std::map} - \end{itemize} - \item Many other operators are also desirable for completeness - \begin{itemize} - \item \cppinline{operator>}, \cppinline{operator>=}, \cppinline{operator<=}, ... - \item often implemented reusing e.g.\ \cppinline{operator<} and \cppinline{operator==} - \end{itemize} - \item Should be defined as hidden friend functions - \item Much boilerplate code to write. Too much... - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{The three-way comparison operator} - \begin{block}{Idea} - \begin{itemize} - \item C++20 introduces \cppinline{operator<=>} - \item named the \textbf{three-way comparison operator}. - \begin{itemize} - \item unofficially called \textbf{spaceship operator} - \end{itemize} - \item allowing to implement all comparisons in one go - \end{itemize} - \end{block} - \begin{exampleblock}{How it works} - \begin{itemize} - \item it returns \emph{something} which can be compared to \cppinline{0} - \begin{itemize} - \item similar to \cppinline{std::strcmp} - \end{itemize} - \item lower, greater, or equal to \cppinline{0} means respectively \emph{lower than}, \emph{greater than} and \emph{equivalent to} - \item It is provided by default for all built-in types and many types in the standard library - \end{itemize} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{The three-way comparison operator practically} - \begin{exampleblockGB}{Output of \texttt{operator<=>}}{https://godbolt.org/z/o6Er1zjrf}{\texttt{<=>} output} - \begin{cppcode*}{} - template - void three_way_compare( T lhs, T rhs ) { - auto res = lhs <=> rhs; - std::cout << lhs << "<=>" << rhs << ": " - << (res<0) << (res==0) << (res>0) - << '\n'; - } - int main() { - three_way_compare(1, 2); // 1<=>2: 100 - three_way_compare(2, 2); // 2<=>2: 010 - three_way_compare(2, 1); // 2<=>1: 001 - } - \end{cppcode*} - \end{exampleblockGB} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Different kinds of ordering} - \begin{block}{The return type of \texttt{operator<=>}} - \begin{itemize} - \item for integers \cppinline{operator<=>} returns \cppinline{std::strong_ordering} - \item \cppinline{weak_ordering} and \cppinline{partial_ordering} also exist - \end{itemize} - \end{block} - \begin{exampleblock}{3 types of ordering} - \begin{description}[partial] - \item[strong] exactly one test among \cppinline{<0}, \cppinline{==0}, and \cppinline{>0} will return \cppinline{true} - \item[weak] like strong but two \emph{equivalent} values may differ - \begin{itemize} - \item they are however \emph{equivalent} for ranking - \item e.g.\ rational numbers $2/3$ and $4/6$ - \end{itemize} - \item[partial] like weak but some values are incomparable - \begin{itemize} - \item for some values all tests may return \cppinline{false} - \item e.g.\ compare a floating point to \cppinline{NaN} - \end{itemize} - \end{description} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Exercising different orderings} - \scriptsize - \begin{exampleblockGB}{Example}{https://godbolt.org/z/s8Gdae4bW}{various orderings} - \begin{cppcode*}{} - struct Ratio { - unsigned n, d ; - friend std::weak_ordering operator<=>( Ratio const & a, - Ratio const & b ) { - return (a.n * b.d) <=> (a.d * b.n); - } - friend std::ostream & operator<<( std::ostream & os, Ratio const & r ) { - return (os << r.n << '/' << r.d); - } - }; - int main() { - // Ratio uses weak_ordering - three_way_compare(Ratio{1, 2}, Ratio{2, 3}); // 1/2<=>2/3 : 100 - three_way_compare(Ratio{2, 3}, Ratio{4, 6}); // 2/3<=>4/6 : 010 - three_way_compare(Ratio{2, 3}, Ratio{1, 2}); // 2/3<=>1/2 : 001 - - // floats use partial_ordering - three_way_compare(+0., -0.); // 0<=>-0 : 010 - three_way_compare(0., 1./0.); // 0<=>inf : 100 - three_way_compare(0., 0./0.); // 0<=>-nan : 000 - } - \end{cppcode*} - \end{exampleblockGB} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Compiler-generated comparison operators} - \begin{block}{For a given user-defined class} - \begin{itemize} - \item defining \cppinline{operator<=>} allows the compiler to use it when encountering the comparison operators \cppinline{<}, \cppinline{<=}, \cppinline{>} and \cppinline{>=} - \item of course, one can still provide a custom implementation - \item the compiler will \emph{NOT} add a default implementation for \cppinline{operator==} and \cppinline{operator!=} - \begin{itemize} - \item as those operators mean \textbf{equal}, rather than \textbf{equivalent} - \item if \cppinline{operator<=>} does not provide a strong order, it is advised not to define \cppinline{operator==} - \end{itemize} - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Compiler-generated \texttt{operator<=>}} - \begin{block}{Default \texttt{operator<=>} implementation} - \begin{itemize} - \item One can ask the compiler to provide a default implementation for \cppinline{operator<=>} and/or \cppinline{operator==} - \begin{itemize} - \item declaring them with ``\cppinline{= default}'' - \item it will compare the member variables, one by one - \end{itemize} - \item Can be useful e.g.\ for tuples - \item Can be wrong, e.g.\ for the Ratio class - \item If \cppinline{operator<=>} is defaulted and no \cppinline{operator==} is defined, then the compiler also provides \cppinline{operator==} - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{\texttt{operator<=>} summary} - \begin{block}{Summary} - \begin{itemize} - \item Defining \cppinline{operator<=>} allows you to use \cppinline{operator<}, \cppinline{operator>}, \cppinline{operator<=}, and \cppinline{operator>=} for free - \item The standard library defines a few kinds of orderings - \begin{itemize} - \item strong, weak and partial - \end{itemize} - \item If \cppinline{operator<=>} does not define a strong ordering, avoid defining \cppinline{operator==} - \end{itemize} - \end{block} -\end{frame} diff --git a/talk/expert/modules.tex b/talk/expert/modules.tex deleted file mode 100644 index 5ff95577..00000000 --- a/talk/expert/modules.tex +++ /dev/null @@ -1,695 +0,0 @@ -\subsection[modules]{Modules} - -\begin{frame}[fragile] - \frametitlecpp[20]{Modules} - \begin{block}{Motivation} - \begin{itemize} - \item Modules allow for sharing declarations and definitions across translation units - \item Header files do the same, but modules have benefits: - \begin{itemize} - \item Better isolation. No cross-talk between multiple pieces of included code, or between included code and your code. - \item Better control over public interface of your library. Avoid leaking library dependencies into user code. - \item Faster compilation (\href{https://youtu.be/DJTEUFRslbI?si=ZRvH1wx0sVJVriLh&t=3259}{import fmt; \textgreater1500x faster}) - \end{itemize} - \end{itemize} - \end{block} - \begin{alertblock}{Textual includes} - \begin{cppcode} - #include "math.h" - \end{cppcode} - \end{alertblock} - \begin{exampleblock}{Module importation} - \begin{cppcode} - import math; - \end{cppcode} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Writing modules} - \begin{exampleblock}{ratio.cpp} - \begin{cppcode*}{} - export module math; - import ; - namespace utils { // ns. and module names orthogonal - export struct Ratio { float num, denom; }; - export std::string toString(const Ratio& r) { ... } - void normalize(Ratio& r) { ... } // not exported - } - \end{cppcode*} - \end{exampleblock} - \begin{exampleblock}{main.cpp} - \begin{cppcode*}{} - import ; - import math; - int main() { - auto r = utils::Ratio{1, 3}; - std::cout << utils::toString(r); - } - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Writing modules} - \begin{block}{Exporting declarations} - \begin{itemize} - \item By default, everything inside a module is internal - \item Declarations become visible when declared with \cppinline{export} in the primary module interface - \item You can only export entities at namespace scope (including the global scope) - \item You cannot export entities with internal linkage (declared static or inside anonymous namespace) - \item You cannot export aliases to non-exported types - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Writing modules} - \begin{exampleblock}{What to export} - \begin{cppcode*}{} - export module math; - - export void f(); // function - export float pi = 3.14f; // variable - export namespace utils { // namespace - enum Status { Yes, No }; // enum (exported) - } - namespace utils { - export struct Ratio { ... }; // class - export using R = Ratio; // alias - float e = 2.71f; // (not exported) - } - export { // content of export block - void h(); - } - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Writing modules} - \begin{alertblock}{What not to export} - \begin{cppcode*}{} - export module math; - - namespace { - export void f(); // error - export float pi = 3.14f; // error - export struct Ratio { ... }; // error - } - - export static void f(); // error - export static float pi = 3.14f; // error - - class C { ... }; - export using D = C; // error - \end{cppcode*} - \end{alertblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Visibility and reachability} - \begin{exampleblock}{ratio.cpp} - \begin{cppcode*}{} - export module math; - struct Ratio { float num, denom; }; - export Ratio golden() { ... } // golden is visible - \end{cppcode*} - \end{exampleblock} - \begin{exampleblock}{main.cpp} - \begin{cppcode*}{} - import math; - import ; - int main() { - Ratio r = golden(); // error: Ratio not visible - auto r = golden(); // OK: Ratio is reachable - std::cout << r.num; // OK: members of reachable - // types are visible - using R = decltype(r); - R r2{1.f, 3.f}; // OK - } - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Module structure} - \begin{exampleblock}{} - \small - \begin{cppcode*}{} - module; // global module fragment (opt.) - #include // only preprocessor - // ... // statements allowed - - export module math; // module preamble starts with - // exported module name. - import ; // only imports allowed - // ... // - - export struct S { ... }; // module purview started - export S f(); // at first non-import - std::string h() { ... } - - module :private // private module fragment (opt.) - S f() { ... } // changes here trigger - // no recompilation of BMI - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Module structure} - \begin{alertblock}{Pitfall} - \begin{cppcode*}{} - export module math; - #include - import ; - // ... - \end{cppcode*} - \end{alertblock} - \begin{block}{} - \begin{itemize} - \item Headers included after \cppinline{export module} add to the module's preamble and purview - \item This is usually not what you want - \end{itemize} - \end{block} - \begin{exampleblock}{Put includes into global module fragment} - \begin{cppcode*}{} - module; - #include - export module math; - import ; - // ... - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile,shrink=5] - \frametitlecpp[20]{Module structure} - \begin{block}{} - Like with header files, we can split interface and implementation: - \end{block} - \begin{exampleblock}{Interface} - \begin{cppcode*}{} - export module math; - - export struct S { ... }; - export S f(); - \end{cppcode*} - \end{exampleblock} - \begin{exampleblock}{Implementation} - \begin{cppcode*}{} - module; - #include - module math; - import ; - - S f() { ... } - std::string b() { ... } - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile,shrink=5] - \frametitlecpp[20]{Submodules and re-exporting} - \begin{block}{} - Modules can (re-)export other modules using \cppinline{export import}: - \end{block} - \vspace{-5mm} - \begin{columns}[t] - \begin{column}{.45\textwidth} - \begin{exampleblock}{Module one} - \begin{cppcode*}{} - export module one; - - export struct S { ... }; - \end{cppcode*} - \end{exampleblock} - \end{column} - \begin{column}{.45\textwidth} - \begin{exampleblock}{Module two} - \begin{cppcode*}{} - export module two; - import ; - - export std::string b() - { ... } - \end{cppcode*} - \end{exampleblock} - \end{column} - \end{columns} - \begin{columns}[t] - \begin{column}{.45\textwidth} - \begin{exampleblock}{Module three} - \begin{cppcode*}{} - export module three; - import one; - export import two; - - export S f() { ... } - \end{cppcode*} - \end{exampleblock} - \end{column} - \begin{column}{.45\textwidth} - \begin{exampleblock}{Module four} - \begin{cppcode*}{} - export module four; - import three; - // b and f visible - // S and std::string only - // reachable - \end{cppcode*} - \end{exampleblock} - \end{column} - \end{columns} -\end{frame} - -\begin{frame}[fragile,shrink=5] - \frametitlecpp[20]{Module partitions} - \begin{block}{} - We can split a module's \emph{interface} into multiple files: - \end{block} - \vspace{-5mm} - \begin{columns}[t] - \begin{column}{.4\textwidth} - \begin{exampleblock}{Primary module interface} - \begin{cppcode*}{} - export module math; - export import :structs; - - export S f(); - \end{cppcode*} - \end{exampleblock} - \end{column} - \begin{column}{.5\textwidth} - \begin{exampleblock}{Module interface partition} - \begin{cppcode*}{} - - export module math:structs; - - export struct S { ... }; - \end{cppcode*} - \end{exampleblock} - \end{column} - \end{columns} - \begin{exampleblock}{Implementation} - \begin{cppcode*}{} - module math; - import ; - - S f() { ... } - std::string b() { ... } - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile,shrink=5] - \frametitlecpp[20]{Module implementation units} - \begin{block}{} - We can split a module's \emph{implementation} into multiple files: - \end{block} - \begin{exampleblock}{Interface} - \begin{cppcode*}{} - export module math; - import :foo; // no export - import :bar; // no export - import ; - - export struct S { ... }; - export S f(); - std::string b(); - \end{cppcode*} - \end{exampleblock} - \vspace{-5mm} - \begin{columns}[t] - \begin{column}{.45\textwidth} - \begin{exampleblock}{Implementation unit foo} - \begin{cppcode*}{} - module math:foo; - - S f() { ... } - \end{cppcode*} - \end{exampleblock} - \end{column} - \begin{column}{.45\textwidth} - \begin{exampleblock}{Implementation unit bar} - \begin{cppcode*}{} - module math:bar; - - std::string b() { ... } - \end{cppcode*} - \end{exampleblock} - \end{column} - \end{columns} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[23]{Standard library modules} - % see: Minimal module support for the standard library http://wg21.link/P2412 - \begin{block}{Standard library modules} - \begin{itemize} - \item Use \cppinline|import std;| for the entire C++ standard library. Basically everything in namespace \cppinline|std|. - \begin{itemize} - \item E.g.\ \cppinline{memcpy(a, b, n)}, \cppinline{sqrt(val)}, \cppinline{uint32_t} - \item Note that you need to prefix with \cppinline{std::} - \end{itemize} - \item Use \cppinline|import std.compat;| for the entire C and C++ standard library - \item No macros are exported. For these, you still need to include the corresponding headers. - \begin{cppcode*}{} - import std; // everything C++ - #include // for assert() - #include // for e.g. CHAR_BIT - \end{cppcode*} - \item Definition of further, smaller modules of the standard library is in progress (e.g.\ fundamentals, containers, networking, etc.) - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Header units} - \begin{block}{Purpose} - \begin{itemize} - \item For easier transition from header-based projects to modules - \item Allows to import any header file as if it was a module - \item Can be mixed with regular header inclusion - \end{itemize} - \end{block} - \begin{cppcode} - #include - import ; - - #include "header.hpp" - import "otherheader.hpp"; - \end{cppcode} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Header units} - \begin{block}{Effect} - \begin{itemize} - \item All declarations in the imported header will be exported - \item An imported header is not affected by the preprocessor state. - Thus, you cannot ``configure'' the header by defining a macro before importing. - This allows the header to be precompiled. - \item An imported header may still provide preprocessor macros - \end{itemize} - \end{block} - \begin{cppcode} - #define MY_MACRO 1 - #include "header.hpp" // may be affected by MY_MACRO - import "otherheader.hpp"; // ignores MY_MACRO - \end{cppcode} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Automatic include to import translation} - \begin{block}{Importable headers} - \begin{itemize} - \item A header file which can successfully be either included or imported is called ``importable'' - \begin{itemize} - \item I.e.\ the header does not require setup of preprocessor state before inclusion - \end{itemize} - \item All \cpp standard library headers are importable - \item C wrapper headers (\cppinline{}) are not - \end{itemize} - \end{block} - \begin{block}{Include translation} - \begin{itemize} - \item Allows the compiler to automatically turn includes into imports - \item Controlled via compiler flags and the build system - \item Basically a standard replacement for precompiled headers - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Build system} - \begin{columns} - \begin{column}{.35\textwidth} - \begin{block}{h.hpp} - \begin{cppcode*}{linenos=false} - #include - ... - \end{cppcode*} - \end{block} - \begin{block}{a.cpp} - \begin{cppcode*}{linenos=false} - #include "h.hpp" - ... - \end{cppcode*} - \end{block} - \begin{block}{b.cpp} - \begin{cppcode*}{linenos=false} - #include - #include "h.hpp" - ... - \end{cppcode*} - \end{block} - \begin{block}{c.cpp} - \begin{cppcode*}{linenos=false} - #include - ... - \end{cppcode*} - \end{block} - \end{column} - \begin{column}{.6\textwidth} - \begin{block}{Traditional workflow} - \center - \begin{tikzpicture} [ - -Triangle, - very thick - ] - \draw [-Latex](5,6) -- (5,0) node [midway,right] {t}; - \path[thick] - node (vec) at(3,6) [draw, rectangle] {\textless{}vector\textgreater{}} - node (hpp) at(1,4.5) [draw, rectangle] {h.hpp} - node (acpp) at(0,3) [draw, rectangle] {a.cpp} - node (bcpp) at(2,3) [draw, rectangle] {b.cpp} - node (ccpp) at(4,3) [draw, rectangle] {c.cpp} - node (ao) at(0,1.5) [draw, rectangle] {a.o} - node (bo) at(2,1.5) [draw, rectangle] {b.o} - node (co) at(4,1.5) [draw, rectangle] {c.o}; - - \node[below= 0.5 cm of bo,fill=white,rounded rectangle] (link) {Linker}; - \node[below= 0.2 cm of link,rectangle,draw] (bin) {binary}; - - \draw[very thick,dotted] (vec) -- (hpp) node [midway,fill=white,rounded rectangle] {\scriptsize \#}; - \draw[very thick,dotted] (vec) -- (bcpp) node [midway,fill=white,rounded rectangle] {\scriptsize \#}; - \draw[very thick,dotted] (vec) -- (ccpp) node [midway,fill=white,rounded rectangle] {\scriptsize \#}; - \draw[very thick,dotted] (hpp) -- (acpp) node [midway,fill=white,rounded rectangle] {\scriptsize \#}; - \draw[very thick,dotted] (hpp) -- (bcpp) node [midway,fill=white,rounded rectangle] {\scriptsize \#}; - \draw[very thick] (acpp) -- (ao) node [pos=0.4,fill=white,rounded rectangle] {\scriptsize \texttt{Compiler}}; - \draw[very thick] (bcpp) -- (bo) node [pos=0.4,fill=white,rounded rectangle] {\scriptsize \texttt{Compiler}}; - \draw[very thick] (ccpp) -- (co) node [pos=0.4,fill=white,rounded rectangle] {\scriptsize \texttt{Compiler}}; - \draw[very thick] (ao) -- (link); - \draw[very thick] (bo) -- (link); - \draw[very thick] (co) -- (link); - \draw[thick] (link) -- (bin); - - \end{tikzpicture} - \end{block} - \end{column} - \end{columns} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Build system} - \begin{columns} - \begin{column}{.35\textwidth} - \small - \begin{block}{h.cpp} - \begin{cppcode*}{linenos=false} - export module foo; - import ; - ... - \end{cppcode*} - \end{block} - \begin{block}{a.cpp} - \begin{cppcode*}{linenos=false} - import foo; - ... - \end{cppcode*} - \end{block} - \begin{block}{b.cpp} - \begin{cppcode*}{linenos=false} - import ; - import foo; - ... - \end{cppcode*} - \end{block} - \begin{block}{c.cpp} - \begin{cppcode*}{linenos=false} - #include - ... - \end{cppcode*} - \end{block} - \end{column} - \begin{column}{.6\textwidth} - \begin{block}{New workflow} - \center - \resizebox{0.8\textwidth}{!}{% - \begin{tikzpicture}[ - -Triangle, - very thick - ] - \draw [-Latex](7,10) -- (7,0) node [midway,right] {t}; - \draw[thick] node at(3, 10) [fill=white,rounded rectangle] {scan dependencies}; - \path[thick] - node (vec) at(5,9) [rectangle,draw] {\textless{}vector\textgreater{}} - node (vecbmi) at(4,7.5) [rectangle,draw] {vector.bmi} - node (hcpp) at(2,6) [rectangle,draw] {h.cpp} - node (ho) at(0,4.5) [rectangle,draw] {h.o} - node (hbmi) at(2,4.5) [rectangle,draw] {foo.bmi} - node (acpp) at(2,3) [rectangle,draw] {a.cpp} - node (bcpp) at(4,3) [rectangle,draw] {b.cpp} - node (ccpp) at(6,6) [rectangle,draw] {c.cpp} - node (ao) at(2,1.5) [rectangle,draw] {a.o} - node (bo) at(4,1.5) [rectangle,draw] {b.o} - node (co) at(6,4.5) [rectangle,draw] {c.o} - node (link) at(3,0.7) [fill=white, rounded rectangle] {\small Linker} - node (bin) at(3,0) [rectangle,draw] {binary}; - \draw[very thick,dotted] (vec) -- (ccpp) node [midway,fill=white,rounded rectangle] {\scriptsize \#}; - \draw[very thick] (vec) -- (vecbmi) node [midway,fill=white,rounded rectangle] {\scriptsize Compiler}; - \draw[very thick,dotted] (vecbmi) -- (hcpp) node [midway,fill=white,rounded rectangle] {\scriptsize imp}; - \draw[very thick] (hcpp) -- (ho) node [pos=0.4] (hoLeft) {}; - \draw[very thick] (hcpp) -- (hbmi) node [pos=0.4] (hoRight) {}; - \path (hoLeft) -- (hoRight) node[midway,fill=white,rounded rectangle] {\scriptsize Compiler}; - \draw[very thick,dotted] (vecbmi) -- (bcpp) node [midway,fill=white,rounded rectangle] {\scriptsize imp}; - \draw[very thick,dotted] (hbmi) -- (acpp) node [pos=0.4,fill=white,rounded rectangle] {\scriptsize imp}; - \draw[very thick,dotted] (hbmi) -- (bcpp) node [pos=0.4,fill=white,rounded rectangle] {\scriptsize imp}; - \draw[very thick] (acpp) -- (ao) node [pos=0.4,fill=white,rounded rectangle] {\scriptsize \texttt{Compiler}}; - \draw[very thick] (bcpp) -- (bo) node [pos=0.4,fill=white,rounded rectangle] {\scriptsize \texttt{Compiler}}; - \draw[very thick] (ccpp) -- (co) node [pos=0.4,fill=white,rounded rectangle] {\scriptsize \texttt{Compiler}}; - \draw[very thick] (ho) to [bend right=40] (link); - \draw[very thick] (ao) -- (link); - \draw[very thick] (bo) -- (link); - \draw[very thick] (co) to [bend left=40] (link); - \draw[thick] (link) -- (bin); - \end{tikzpicture} - } - \end{block} - \end{column} - \end{columns} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Build system} - \begin{block}{New challenges} - \begin{itemize} - \item Resolving a module name to the file name building it - \item Translation units no longer independent - \begin{itemize} - \item Extra tool needs to infer dependency graph before building - \begin{itemize} - \item Called a ``dependency scanner'' - \item Needs to be communicated to the build system - \item Using a new \href{https://wg21.link/P1689}{standard dependency file format} - \end{itemize} - \item Parallel and distributed builds need synchronization - \end{itemize} - \item Compilation of module translation units produces a binary module interface (BMI) \emph{and} an object file - \begin{itemize} - \item Need to manage BMIs between multiple compiler invocations - \end{itemize} - \item Tools beside the compiler need to build/read BMIs - \begin{itemize} - \item E.g.\ static analysis, language servers for auto completion, etc. - \end{itemize} - \item The \cpp standard specifies very little on how this works - \begin{itemize} - \item We may experience large implementation divergence - \end{itemize} - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Build system} - \begin{block}{Status} - \begin{itemize} - \item Dependency scanner since clang 16: \texttt{clang-scan-deps} - \item Experimental module support in cmake since 3.26, uses \texttt{clang-scan-deps}, many fixes in later versions % see: https://discourse.cmake.org/t/c-20-modules-update/7330/24 and https://youtu.be/c563KgO-uf4?si=HUpnSivtDxvBoTr3&t=3592 - \item MSBuild (Windows) fully handles dependency scanning - \item \cppinline{g++ a.cpp b.cpp ...} ``just works'', must be one line though - \item \href{https://wg21.link/p1602}{Experimental extensions to GNU make} exist to grow dependency graph on the fly while modules are discovered - \item Header units unsupported in all build systems (May 2023) % See talk: https://youtu.be/_LGR0U5Opdg?si=yQoCYD2yGFhi_vs6&t=3768 - \item C++23: \cppinline{import std;} supported in MSVC, partially in clang - \begin{itemize} - \item GCC/clang/MSVC also plan support in C++20 % see: https://github.com/microsoft/STL/issues/3945 - \end{itemize} - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Building modules (g++)} - \begin{block}{Case study: g++} - \begin{itemize} - \item BMI is called CMI (compiled module interfaces) - \item By default, g++ caches CMIs in subdirectory \texttt{./gcm.cache} - \item Uses a \href{https://wg21.link/P1184}{module mapper} to resolve imports, which specifies a protocol and uses a central server for module maintenance - \item Each module needs to be built before it can be imported - \begin{itemize} - \item {\footnotesize \cppinline{g++ -std=c++20 -fmodules-ts -c ratio.cpp -o ratio.o}} - \item Generates \texttt{ratio.o} and \texttt{./gcm.cache/ratio.gcm} (CMI) - \end{itemize} - \item Each header unit needs to be built before it can be imported - \begin{itemize} - \item {\footnotesize \cppinline{g++ -std=c++20 -fmodules-ts -x c++-system-header vector}} - \item Generates e.g.\ \texttt{./gcm.cache/usr/include/c++/11/vector.gcm} (CMI) - \item {\footnotesize \cppinline{g++ -std=c++20 -fmodules-ts -x c++-header ratio.h}} - \item Generates e.g.\ \texttt{./gcm.cache/,/ratio.h.gcm} (CMI) - \end{itemize} - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Modules} - \begin{exampleblock}{Guidance for today} - \begin{itemize} - \item Start writing importable headers (no macro dependencies) - \begin{itemize} - \item Dual use: \cppinline{#include} before \cpp20 and \cppinline{import} with \cpp20 - \end{itemize} - \item Watch progress on module support in your build system - \end{itemize} - \end{exampleblock} - \begin{exampleblock}{Guidance for tomorrow} - \begin{itemize} - \item Start writing modules when your users have \cpp20 - \item Maybe import standard headers when \cpp20 is available - \item Start using \cppinline{import std;} when available - \item Future of header units unclear (implementation difficulties) - \end{itemize} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Modules} - \begin{block}{Resources} - \small - \begin{itemize} - \item \href{https://www.youtube.com/watch?v=nP8QcvPpGeM}{A (Short) Tour of C++ Modules - Daniela Engert - CppCon 2021} (very technical) - \item Understanding C++ Modules: \href{https://vector-of-bool.github.io/2019/03/10/modules-1.html}{Part1}, \href{https://vector-of-bool.github.io/2019/03/31/modules-2.html}{Part2} and \href{https://vector-of-bool.github.io/2019/10/07/modules-3.html}{Part3}. - \item \href{https://www.youtube.com/watch?v=DJTEUFRslbI}{So, You Want to Use C++ Modules … Cross-Platform? - Daniela Engert - C++ on Sea 2023} - \item \href{https://www.youtube.com/watch?v=c563KgO-uf4&t=686s}{import CMake: 2023 State of C++20 modules in CMake - Bill Hoffman - CppNow 2023} - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Modules} - \begin{exercise}{Modules} - \begin{itemize} - \item go to \texttt{exercises/modules} - \item convert the \texttt{Complex.hpp} header into a module named \texttt{math} - \end{itemize} - \end{exercise} - \begin{exercise}{Header units} - \begin{itemize} - \item go to \texttt{exercises/header\_units} - \item convert all \cppinline{#include}s into header unit \cppinline{import}s - \end{itemize} - \end{exercise} -\end{frame} diff --git a/talk/expert/perfectforwarding.tex b/talk/expert/perfectforwarding.tex deleted file mode 100644 index 3cf1db3d..00000000 --- a/talk/expert/perfectforwarding.tex +++ /dev/null @@ -1,318 +0,0 @@ -\subsection[forward]{Perfect forwarding} - -%http://eli.thegreenplace.net/2014/perfect-forwarding-and-universal-references-in-c/ -\begin{frame}[fragile] - \frametitlecpp[11]{The problem} - How to write a generic wrapper function? - \begin{block}{} - \begin{cppcode*}{} - template - void wrapper(T arg) { - // code before - func(arg); - // code after - } - \end{cppcode*} - \end{block} - Example usage : - \begin{itemize} - \item \cppinline{emplace_back} - \item \cppinline{make_unique} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Why is it not so simple?} - \begin{block}{} - \begin{cppcode*}{} - template - void wrapper(T arg) { - func(arg); - } - \end{cppcode*} - \end{block} - \begin{alertblock}{What about references?} - \begin{itemize} - \item what if \cppinline{func} takes a reference to avoid copies? - \item wrapper would force a copy and we fail to use references - \end{itemize} - - \end{alertblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Second try, second failure ?} - \begin{block}{} - \begin{cppcode*}{} - template - void wrapper(T& arg) { - func(arg); - } - wrapper(42); - // invalid initialization of - // non-const reference from - // an rvalue - \end{cppcode*} - \end{block} - \begin{alertblock}{} - and \cppinline{const T&} won't work when passing something non const - \end{alertblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Solution: cover all cases} - \begin{block}{} - \begin{cppcode*}{} - template - void wrapper(T& arg) { func(arg); } - - template - void wrapper(const T& arg) { func(arg); } - - template - void wrapper(T&& arg) { func(std::move(arg)); } - \end{cppcode*} - \end{block}{} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{The new problem: scaling to more arguments} - \begin{block}{} - \begin{cppcode*}{} - template - void wrapper(T1& arg1, T2& arg2) - { func(arg1, arg2); } - - template - void wrapper(const T1& arg1, T2& arg2) - { func(arg1, arg2); } - - template - void wrapper(T1& arg1, const T2& arg2) - { func(arg1, arg2); } - ... - \end{cppcode*} - \end{block}{} - \begin{alertblock}{Exploding complexity} - \begin{itemize} - \item for $n$ arguments, 3$^{n}$ overloads - \item you do not want to try n = 5... - \end{itemize} - \end{alertblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Reference collapsing} - \begin{block}{Reference to references} - \begin{itemize} - \item Are formally forbidden, but can occur sometimes - \end{itemize} - \end{block} - \begin{block}{} - \begin{cppcode*}{} - template - void foo(T t) { T& k = t; } //int& &, error in C++98 - int ii = 4; - foo(ii); // want to pass by reference - \end{cppcode*} - \end{block} - \begin{block}{\cpp11 added rvalue-references} - \begin{itemize} - \item More combinations possible, like: \cppinline{int&& &}, or \cppinline{int&& &&} - \end{itemize} - \end{block} - \begin{exampleblock}{Reference collapsing} - \begin{itemize} - \item Rule: When multiple references are involved, \cppinline{&} always wins - \item \cppinline{T&& &, T& &&, T& &} $\rightarrow$ \cppinline{T&} - \item \cppinline{T&& &&} $\rightarrow$ \cppinline{T&&} - \end{itemize} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Forwarding references} - \begin{exampleblock}{Rvalue reference in type-deducing context} - \begin{cppcode*}{} - template - void f(T&& t) { ... } - \end{cppcode*} - \end{exampleblock} - \begin{block}{Forwarding reference} - \begin{itemize} - \item Next to a template parameter, that can be deduced, \cppinline{&&} is not an rvalue reference, but a ``forwarding reference'' - \begin{itemize} - \item aka.\ ``universal reference'' - \item So, this applies only to functions - \end{itemize} - \item The template parameter is additionally allowed to be deduced as an lvalue reference, and reference collapsing proceeds: - \begin{itemize} - \item if an lvalue of type \cppinline{U} is given, \cppinline{T} is deduced as \cppinline{U&} and the parameter type \cppinline{U& &&} collapses to \cppinline{U&} - \item otherwise (rvalue), T is deduced as \cppinline{U} - \begin{itemize} - \item and forms the parameter type \cppinline{U&&} - \end{itemize} - \end{itemize} - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Forwarding references} - \begin{exampleblock}{Examples} - \begin{cppcode*}{} - template - void f(T&& t) { ... } - - f(4); // rvalue -> T&& is int&& - double d = 3.14; - f(d); // lvalue -> T&& is double& - float g() {...} - f(g()); // rvalue -> T&& is float&& - std::string s = "hello"; - f(s); // lvalue -> T&& is std::string& - f(std::move(s)); // rvalue -> T&& is std::string&& - f(std::string{"hello"}); // rvalue -> std::string&& - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Forwarding references} - \begin{alertblock}{Careful!} - \begin{cppcode*}{} - template struct S { - S(T&& t) { ... } // rvalue references - void f(T&& t) { ... } // NOT forwarding references - }; - \end{cppcode*} - \end{alertblock} - \vspace{-1.2\baselineskip} - \begin{overprint} - \onslide<1> - \begin{exampleblock}{Half-way correct version} - \begin{cppcode*}{} - template struct S { - - template - S(U&& t) { ... } // deducing context -> fwd. ref. - template - void f(U&& t) // deducing context -> fwd. ref. - // ... but now U can be a different type than T - }; - \end{cppcode*} - \end{exampleblock} - \onslide<2> - \begin{exampleblock}{Correct version} - \begin{cppcode*}{} - template struct S { - template , T>, int> = 0> - S(U&& t) { ... } // deducing context -> fwd. ref. - template - void f(U&& t) // deducing context -> fwd. ref. - requires std::same_as, T> { ... } - }; - \end{cppcode*} - \end{exampleblock} - \end{overprint} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Perfect forwarding} - \begin{block}{\texttt{std::remove\_reference}} - \begin{itemize} - \item Type trait to remove reference from a type - \item If \cppinline{T} is a reference type, \cppinline{remove_reference_t} is the type referred to by \cppinline{T}, otherwise it is \cppinline{T}. - \end{itemize} - \end{block} - \begin{block}{} - \begin{cppcode*}{} - template - struct remove_reference { using type = T; }; - template - struct remove_reference { using type = T; }; - template - struct remove_reference { using type = T; }; - - template - using remove_reference_t = - typename remove_reference::type; // C++14 - \end{cppcode*} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Perfect forwarding} - \begin{block}{\texttt{std::forward}} - \begin{itemize} - \item Forward lvalue-/rvalueness - \item Keeps references and maps non-references to rvalue references - \end{itemize} - \end{block} - \begin{block}{} - \small - \begin{cppcode*}{} - template - T&& forward(remove_reference_t& t) noexcept { // 1. - return static_cast(t); - } - template - T&& forward(remove_reference_t&& t) noexcept { // 2. - return static_cast(t); - } - \end{cppcode*} - \end{block} - \begin{block}{} - \begin{itemize} - \item if \cppinline{T} is \cppinline{int}, selects 2., returns \cppinline{int&&} - \item if \cppinline{T} is \cppinline{int&}, selects 1., returns \cppinline{int& &&}, i.e.\ \cppinline{int&} - \item if \cppinline{T} is \cppinline{int&&}, selects 2., returns \cppinline{int&& &&}, i.e.\ \cppinline{int&&} - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Perfect forwarding} - \begin{exampleblock}{Example - putting it all together} - \begin{cppcode} - template - void wrapper(T&&... args) { - func(std::forward(args)...); - } - \end{cppcode} - \end{exampleblock} - \begin{block}{} - \begin{itemize} - \item if we pass an rvalue reference \cppinline{U&&} to wrapper - \begin{itemize} - \item \cppinline{T=U}, arg is of type \cppinline{U&&} - \item func will be called with a \cppinline{U&&} - \end{itemize} - \item if we pass an lvalue reference \cppinline{U&} to wrapper - \begin{itemize} - \item \cppinline{T=U&}, arg is of type \cppinline{U&} (reference collapsing) - \item func will be called with a \cppinline{U&} - \end{itemize} - \item if we pass a plain \cppinline{U} (rvalue) to wrapper - \begin{itemize} - \item \cppinline{T=U}, arg is of type \cppinline{U&&} (no copy in wrapper) - \item func will be called with a \cppinline{U&&} - \item if func takes a plain \cppinline{U}, copy happens there, as expected - \end{itemize} - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Real life example} - \begin{block}{} - \begin{cppcode*}{} - template - unique_ptr make_unique(Args&&... args) { - return unique_ptr - (new T(std::forward(args)...)); - } - \end{cppcode*} - \end{block} -\end{frame} diff --git a/talk/expert/sfinae.tex b/talk/expert/sfinae.tex deleted file mode 100644 index dc637dfc..00000000 --- a/talk/expert/sfinae.tex +++ /dev/null @@ -1,323 +0,0 @@ -\subsection[sfinae]{SFINAE} - -%https://jguegant.github.io/blogs/tech/sfinae-introduction.html -\begin{frame}[fragile] - \frametitlecpp[11]{Substitution Failure Is Not An Error (SFINAE)} - \begin{block}{The main idea} - \begin{itemize} - \item substitution replaces template parameters with the provided arguments (types or values) - \item if it leads to invalid code, do not report an error but try other overloads/specializations - \end{itemize} - \end{block} - \begin{exampleblock}{Example} - \begin{cppcode*}{} - template - void f(typename T::type arg) { ... } - void f(int a) { ... } - - f(1); // Calls void f(int) - \end{cppcode*} - \end{exampleblock} - \begin{alertblock}{} - Note: SFINAE is largely superseded by concepts in \cpp20 - \end{alertblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{\texttt{decltype}} - \begin{block}{The main idea} - \begin{itemize} - \item gives the type of the result of an expression - \item the expression is not evaluated (i.e.\ unevaluated context) - \item at compile time - \end{itemize} - \end{block} - \begin{exampleblock}{Example} - \begin{cppcode*}{} - struct A { double x; }; - A a; - decltype(a.x) y; // double - decltype((a.x)) z = y; // double& (lvalue) - decltype(1 + 2u) i = 4; // unsigned int - - template - auto add(T t, U u) -> decltype(t + u); - // return type depends on template parameters - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{\texttt{declval}} - \begin{block}{The main idea} - \begin{itemize} - \item function to create reference to a ``fake'' object at compile time - \item useful for types that cannot easily be constructed - \item use only in unevaluated contexts, e.g.\ inside \cppinline{decltype} - \end{itemize} - \end{block} - \begin{exampleblock}{} - \begin{cppcode*}{} - struct Default { - int foo() const; - }; - class NonDefault { - private: NonDefault(); - public: int foo() const; - }; - decltype(Default().foo()) n1 = 1; // int - decltype(NonDefault().foo()) n2 = 2; // error - decltype(std::declval().foo()) n3 = 3; - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{\texttt{true\_type} and \texttt{false\_type}} - \begin{block}{The main idea} - \begin{itemize} - \item encapsulate a compile-time boolean as type - \item can be inherited - \end{itemize} - \end{block} - \begin{exampleblock}{Example} - \begin{cppcode*}{} - struct truth : std::true_type { }; - - constexpr bool test = truth::value; // true - constexpr truth t; - constexpr bool test = t(); // true - constexpr bool test = t; // true - \end{cppcode*} - \end{exampleblock} - \begin{exampleblock}{Possible implementation} - \begin{cppcode*}{} - using true_type = integral_constant; - using false_type = integral_constant; - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Using SFINAE for introspection} - \begin{block}{The main idea} - \begin{itemize} - \item use a primary template, inheriting from \cppinline{false_type} - \item use a template specialization, inheriting from \cppinline{true_type} - \begin{itemize} - \item which depends on the feature you want to introspect, - as part of the context where template argument deduction happens - \end{itemize} - \item let SFINAE choose between the two templates - \end{itemize} - \end{block} - \begin{exampleblock}{Example} - \small - \begin{cppcode*}{} - template - struct hasFoo : std::false_type {}; // primary template - template - struct hasFoo().foo())> - : std::true_type {}; // template special. - struct A{}; struct B{ void foo(); }; - static_assert(!hasFoo::value, "A has no foo()"); - static_assert(hasFoo::value, "B has foo()"); - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Not so easy actually...} - \begin{exampleblockGB}{Example}{https://godbolt.org/z/Y9Ys4hvWq}{\texttt{hasFoo} failing} - \small - \begin{cppcode*}{} - template - struct hasFoo : std::false_type {}; - template - struct hasFoo().foo())> - : std::true_type {}; - - struct A{}; - struct B{ void foo(); }; - struct C{ int foo(); }; - - static_assert(!hasFoo::value, "A has no foo()"); - static_assert(hasFoo::value, "B has foo()"); - static_assert(!hasFoo::value, "C has no foo()"); - static_assert(hasFoo::value, "C has foo()"); - \end{cppcode*} - \end{exampleblockGB} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{Using \texttt{void\_t}} - \begin{block}{Concept} - \begin{itemize} - \item Maps a sequence of given types to \cppinline{void} - \item Introduced in \cpp17, though trivial to implement in \cpp11 - \item Can be used in specializations to check the validity of an expression - \end{itemize} - \end{block} - \begin{block}{Implementation in header type\_traits} - \begin{cppcode*}{} - template - using void_t = void; - \end{cppcode*} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{Previous introspection example using \texttt{void\_t}} - \begin{exampleblockGB}{Example}{https://godbolt.org/z/hfMxndP1x}{\texttt{hasFoo} working} - \begin{cppcode*}{} - template - struct hasFoo : std::false_type {}; - - template - struct hasFoo().foo())>> - : std::true_type {}; - - struct A{}; struct B{ void foo(); }; - struct C{ int foo(); }; - - static_assert(!hasFoo::value,"unexpected foo()"); - static_assert(hasFoo::value, "expected foo()"); - static_assert(hasFoo::value, "expected foo()"); - \end{cppcode*} - \end{exampleblockGB} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Standard type traits} - \begin{block}{Standard type traits} - \begin{itemize} - \item Don't implement SFINAE introspection for everything,\\ - use the standard library! - \item Standard type traits in header \cppinline{} - \item They look like \cppinline{std::is_*} - \item Checks at compile time whether \cppinline{T} is - \begin{itemize} - \item float, signed, final, abstract, default\_constructible, ... - \end{itemize} - \item Result in nested boolean constant \cppinline{value} - \item Since \cpp17, variable template versions: \cppinline{std::is_*_v}, giving the bool directly - \end{itemize} - \end{block} - \begin{cppcode*}{} - constexpr bool b = std::is_pointer::value; - constexpr bool b = std::is_pointer_v; // C++17 - \end{cppcode*} -\end{frame} - -\begin{frame}[fragile] - \frametitle{SFINAE and the STL \hfill \cpp11/\cpp14} - \begin{block}{\texttt{enable\_if} \cpprefLink{https://en.cppreference.com/w/cpp/types/enable_if}} - \begin{cppcode*}{linenos=false} - template - struct enable_if; - \end{cppcode*} - \begin{itemize} - \item If \cppinline{B} is true, has a nested alias \cppinline{type} to type \cppinline{T} - \item otherwise, has no such alias - \end{itemize} - \end{block} - \begin{exampleblock}{Example} - \begin{cppcode*}{} - template - struct enable_if {}; - template - struct enable_if { using type = T; }; - - template // C++14 - using enable_if_t = typename enable_if::type; - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \begin{exampleblockGB}{Usage example}{https://godbolt.org/z/xse8GM8fq}{\texttt{enable\_if}} - \small - \begin{cppcode*}{} - template constexpr bool is_iterable ... ; - - template, bool> = true> - void print(T const& t) { - std::cout << t << "\n"; - } - template, bool> = true> - void print(T const& t) { - for (auto const& item : t) { - std::cout << item << "\n"; - } - } - \end{cppcode*} - Note : using \cppinline{if constexpr} would be simpler - \end{exampleblockGB} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Back to variadic class templates} - \begin{block}{The \texttt{tuple\_element} trait} - \begin{cppcode*}{} - template - struct tuple_element; - - template - struct tuple_element<0, tuple> { - using type = T; - }; - - template - struct tuple_element> { - using type = typename - tuple_element>::type; - }; - \end{cppcode*} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[14]{Back to variadic class templates} - \begin{block}{The tuple get function} - \begin{cppcode*}{} - template - std::enable_if_t>::type&> - get(tuple& t) { - return t.m_head; - } - template - std::enable_if_t>::type&> - get(tuple& t) { - return get(static_cast&>(t)); - } - \end{cppcode*} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{with if constexpr and return type deduction} - \begin{block}{The tuple get function} - \begin{cppcode*}{} - template - auto& get(tuple& t) { - if constexpr(I == 0) - return t.m_head; - else - return get(static_cast&>(t)); - } - \end{cppcode*} - \end{block} - \begin{goodpractice}{SFINAE vs.\ if constexpr} - \begin{itemize} - \item \cppinline{if constexpr} can replace SFINAE in many places. - \item It is usually more readable as well. Use it if you can. - \end{itemize} - \end{goodpractice} -\end{frame} diff --git a/talk/expert/variadictemplate.tex b/talk/expert/variadictemplate.tex deleted file mode 100644 index be012f95..00000000 --- a/talk/expert/variadictemplate.tex +++ /dev/null @@ -1,218 +0,0 @@ -\subsection[tmpl]{Variadic templates} - -%http://eli.thegreenplace.net/2014/variadic-templates-in-c/ - -\begin{frame}[fragile] - \frametitlecpp[11]{Basic variadic template} - \begin{block}{The idea} - \begin{itemize} - \item a parameter accepting arbitrarily many arguments (i.e.\ pack) - \item template parameter pack for e.g.\ types, function parameter packs for values, and expansions, details on \href{https://en.cppreference.com/w/cpp/language/parameter_pack}{cppreference} - \end{itemize} - \end{block} - \begin{exampleblock}{Recursive example \cppinsightLink{https://cppinsights.io/s/1c9fa05f}} - \begin{cppcode*}{} - template - T sum(T v) { return v; } - - template // temp. param. pack - T sum(T first, Args... args) { // func. param. pack - return first + sum(args...); // pack expansion - } - int s = sum(1, 2, 3, 8, 7); - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame} - \frametitlecpp[11]{A couple of remarks} - \begin{block}{About performance} - \begin{itemize} - \item do not be afraid of recursion - \item everything is at compile time! - \item unlike C-style variadic functions \\ - e.g.\ \cppinline{printf(const char* fmt, ...);} - \end{itemize} - \end{block} - \begin{block}{Why it is better than variadic functions} - \begin{itemize} - \item it's more performant - \item type safety is included - \item it applies to everything, including user-defined types - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Parameter packs} - \begin{block}{Parameter packs} - \begin{itemize} - \item only a few operations are supported - \begin{itemize} - \item query the number of elements in a pack with \cppinline{sizeof...} - \item expand it with \cppinline{x...} - \end{itemize} - \item can be empty - \item can hold different types - \end{itemize} - \end{block} - \begin{exampleblock}{} - \begin{cppcode*}{} - template - void f(Args... args) { - constexpr std::size_t N = sizeof...(Args); - std::tuple t{args...}; - } - f(0, 1, 2); // Args = [int, int, int] - f(); // Args = empty - f(0, true, 3.14); // Args = [int, bool, double] - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{Fold expressions} - \begin{block}{The idea} - \begin{itemize} - \item reduces a parameter pack over a binary operator - \item details on \href{https://en.cppreference.com/w/cpp/language/fold}{cppreference} - \end{itemize} - \end{block} - \begin{exampleblock}{Example} - \begin{cppcode*}{} - template - auto sum1(Args... args) { - return (args + ...); // unary fold over + - } // parentheses mandatory - template - auto sum2(Args... args) { - return (args + ... + 0); // binary fold over + - } // parentheses mandatory - int sum = sum1(); // error - int sum = sum2(); // ok - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{Fold expressions} - \begin{exampleblock}{Example: call a function on all arguments - \cppinsightLink{https://cppinsights.io/s/23e7d474}} - \begin{cppcode*}{} - template - void print(const T& t) { - std::cout << t; - } - template - void printAll(const Ts&... ts) { - (print(ts),...); // fold over comma operator - } - \end{cppcode*} - \end{exampleblock} - \begin{alertblock}{\cpp11 workaround (don't use anymore)} - \begin{cppcode*}{} - template - void printAll(const Ts&... ts) { - int dummy[]{(print(ts),0)...}; - } - \end{cppcode*} - \end{alertblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Variadic class template} - \begin{exampleblockGB}{The tuple example, simplified}{https://godbolt.org/z/nxjja4bob}{\texttt{tuple} code} - \begin{cppcode*}{} - template - struct tuple {}; - - template - struct tuple : tuple { - tuple(T head, Ts... tail) : - tuple(tail...), m_head(head) {} - T m_head; - }; - - tuple - t1(12.2, 42, "big"); - \end{cppcode*} - \end{exampleblockGB} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[14]{\texttt{std::integer\_sequence}} - \begin{block}{Packs of values} - \begin{itemize} - \item We can also have non-type template parameter packs - \item Useful to pass lists of compile-time constants around - \item The standard library includes a few helpers - \end{itemize} - \end{block} - \begin{block}{} - \begin{cppcode*}{} - template - struct integer_sequence { ... }; - - template - using index_sequence = - integer_sequence; - - template - using make_index_sequence = - index_sequence; - \end{cppcode*} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[14]{\texttt{std::integer\_sequence}} - \begin{exampleblock}{Example - make\_from\_tuple with helper} - \begin{cppcode*}{} - template - T helper(std::tuple args, - std::index_sequence) { - return T(std::get(args)...); - } - template - T make_from_tuple(std::tuple args) { - return helper(args, - std::make_index_sequence{}); - } - - struct S { S(int, float, bool) { ... } }; - std::tuple t{42, 3.14, false}; - S s = make_from_tuple(t); - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{\texttt{std::integer\_sequence}} - \begin{exampleblock}{Example - make\_from\_tuple with lambda} - \begin{cppcode*}{} - template - T make_from_tuple(std::tuple args) { - return [&]( - std::index_sequence){ - return T(std::get(args)...); - }(std::make_index_sequence{}); - } - - struct S { S(int, float, bool) { ... } }; - std::tuple t{42, 3.14, false}; - S s = make_from_tuple(t); - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Variadic templates} - \begin{exerciseWithShortcut}{Variadic templates}{Variadic tpl} - \begin{itemize} - \item go to \texttt{exercises/variadic} - \item you will extend the \cppinline{tuple} from the last slides - \item follow the instructions in the source code - \end{itemize} - \end{exerciseWithShortcut} -\end{frame} diff --git a/talk/introduction/BjarneStroustrup.jpg b/talk/introduction/BjarneStroustrup.jpg deleted file mode 100644 index dc810380..00000000 Binary files a/talk/introduction/BjarneStroustrup.jpg and /dev/null differ diff --git a/talk/introduction/goals.tex b/talk/introduction/goals.tex deleted file mode 100644 index d0ef26d3..00000000 --- a/talk/introduction/goals.tex +++ /dev/null @@ -1,31 +0,0 @@ -\subsection[Use]{Why we use it?} - -\begin{frame} - \frametitle{Why is \cpp{} our language of choice?} - \begin{block}{Adapted to large projects} - \begin{itemize} - \item statically and strongly typed - \item object oriented - \item widely used (and taught) - \item many available libraries - \end{itemize} - \end{block} - \pause - \begin{block}{Fast} - \begin{itemize} - \item compiled to native machine code - \begin{itemize} - \item unlike Java, C\#, Python, ... - \end{itemize} - \item allows to go close to hardware when needed - \end{itemize} - \end{block} - \pause - \begin{alertblock}{What we get} - \begin{itemize} - \item the most powerful language - \item the most complicated one - \item the most error prone? - \end{itemize} - \end{alertblock} -\end{frame} diff --git a/talk/introduction/history.tex b/talk/introduction/history.tex deleted file mode 100644 index fcb02969..00000000 --- a/talk/introduction/history.tex +++ /dev/null @@ -1,124 +0,0 @@ -\subsection[Hist]{History} - -\begin{frame} - \frametitle{C/\cpp{} origins} - \begin{minipage}{0.4\linewidth} - \tikzstyle{old}=[ellipse,draw=black,fill=orange!30,thick,inner sep=2pt] - \tikzstyle{new}=[rectangle,draw=black,fill=green!50,thick,inner sep=2pt] - \tikzstyle{direct}=[<-,semithick] - \tikzstyle{transverse}=[<-,dotted,semithick] - \begin{tikzpicture}[->, node distance=.75cm, font=\tiny, scale=0.8, every node/.style={scale=0.8}] - \node[old] (Simula) {Simula}; - \node[left of=Simula,node distance=1.5cm] {1967}; - \node[old] (BCPL) [right of=Simula, node distance=2cm] {BCPL}; - \node[old] (B) [below of=BCPL] {B} - edge[transverse] (BCPL); - \node[old] (KandRC) [below of=B] {K and R C} - edge[transverse] (B); - \node[left of=KandRC,node distance=3.5cm] {1978}; - \node[old] (ClassicC) [below of=KandRC] {Classic C} - edge[direct] (KandRC); - \node[old] (CwithClasses) [below of=Simula,node distance=3cm] {C with Classes} - edge[transverse] (Simula) - edge[transverse] (BCPL) - edge[direct] (ClassicC); - \node[left of=CwithClasses,node distance=1.5cm] {1980}; - \node[old] (EarlyC++) [below of=CwithClasses] {Early \cpp} - edge[direct] (CwithClasses); - \node[left of=EarlyC++,node distance=1.5cm] {1985}; - \node[old] (C89) [below of=ClassicC,node distance=2.25cm] {C89} - edge[direct] (ClassicC) - edge[transverse] (CwithClasses); - \node[old] (ARMC++) [below of=EarlyC++] {ARM \cpp} - edge[direct] (EarlyC++) - edge[transverse] (C89); - \node[left of=ARMC++,node distance=1.5cm] {1989}; - \node[old] (C++98) [below of=ARMC++] {\cpp98} - edge[direct] (ARMC++) - edge[transverse] (C89); - \node[old] (C99) [below of=C89] {C99} - edge[direct] (C89) - edge[transverse] (ARMC++); - \node[left of=C++98,node distance=1.5cm] {1998}; - \node[new] (C++11) [below of=C++98] {\cpp11} - edge[direct] (C++98) - edge[transverse] (C99); - \node[left of=C++11,node distance=1.5cm] {2011}; - \node[new] (C11) [below of=C99] {C11} - edge[direct] (C99) - edge[transverse] (C++98); - \node[new] (C17) [below of=C11,node distance=1.8cm] {C17} - edge[direct] (C11); - \node[new] (C23) [below of=C17,node distance=1.2cm] {C23} - edge[direct] (C17); - \node[new] (C++14) [below of=C++11] {\cpp14} - edge[direct] (C++11); - \node[left of=C++14,node distance=1.5cm] {2014}; - \node[new] (C++17) [below of=C++14] {\cpp17} - edge[direct] (C++14); - \node[left of=C++17,node distance=1.5cm] {2017}; - \node[new] (C++20) [below of=C++17] {\cpp20} - edge[direct] (C++17); - \node[left of=C++20,node distance=1.5cm] {2020}; - \node[new] (C++23) [below of=C++20] {\cpp23} - edge[direct] (C++20); - \node[left of=C++23,node distance=1.5cm] {2023}; - \end{tikzpicture} - \end{minipage} - \begin{minipage}{0.57\linewidth} - \begin{tabular}{cc} - \includegraphics[height=2.5cm]{introduction/ritchie.jpeg} & \includegraphics[height=2.5cm]{introduction/BjarneStroustrup.jpg} \\[-1ex] - \tiny{C inventor} & \tiny{\cpp inventor} \\[-1ex] - \scriptsize{Dennis M. Ritchie} & \scriptsize{Bjarne Stroustrup} \\ - \end{tabular} - \begin{itemize} - {\footnotesize - \item Both C and \cpp are born in Bell Labs - \item \cpp {\it almost} embeds C - \item C and \cpp are still under development - \item We will discuss all \cpp specs up to \cpp20 (only partially) - \item Each slide will be marked with first spec introducing the feature - } - \end{itemize} - \end{minipage} -\end{frame} - -\begin{frame} - \frametitle{\cpp11, \cpp14, \cpp17, \cpp20, \cpp23, \cpp26...} - \begin{block}{Status} - \begin{itemize} - \item A new \cpp specification every 3 years - \begin{itemize} - \item \cpp23 complete since 11\textsuperscript{th} of Feb. 2023 - \item work on \cpp26 is ongoing - \end{itemize} - \item Bringing each time a lot of goodies - \end{itemize} - \end{block} - \pause - \begin{block}{How to use \cpp XX features} - \begin{multicols}{2} - \begin{itemize} - \item Use a compatible compiler - \item add \texttt{-std=c++xx} to compilation flags - \item e.g.\ \texttt{-std=c++17} - \end{itemize} - \vfill - \columnbreak - \begin{table}[h!] - \begin{center} - \begin{tabular}{c|c|c} - \textbf{\cpp} & \textbf{gcc} & \textbf{clang}\\ - \hline - 11 & $\geq$4.8 & $\geq$3.3\\ - 14 & $\geq$4.9 & $\geq$3.4\\ - 17 & $\geq$7.3 & $\geq$5\\ - 20 & $\geq$11, 14 & $\geq$19 \\ - 23 & $>$15 & $>$20 \\ - \end{tabular} - \caption{Minimum versions of gcc and clang for a given \cpp version} - \end{center} - \end{table} - \end{multicols} - \end{block} -\end{frame} diff --git a/talk/introduction/ritchie.jpeg b/talk/introduction/ritchie.jpeg deleted file mode 100644 index f4c7d625..00000000 Binary files a/talk/introduction/ritchie.jpeg and /dev/null differ diff --git a/talk/morelanguage/AtlasLego.jpg b/talk/morelanguage/AtlasLego.jpg deleted file mode 100644 index 751d0281..00000000 Binary files a/talk/morelanguage/AtlasLego.jpg and /dev/null differ diff --git a/talk/morelanguage/constexpr.tex b/talk/morelanguage/constexpr.tex deleted file mode 100644 index de68449e..00000000 --- a/talk/morelanguage/constexpr.tex +++ /dev/null @@ -1,195 +0,0 @@ -\subsection[cstexpr]{Constant Expressions} - -\begin{frame}[fragile] - \frametitlecpp[14]{Generalized Constant Expressions} - \begin{block}{Reason of being} - \begin{itemize} - \item use functions to compute constant expressions at compile time - \end{itemize} - \end{block} - \pause - \begin{exampleblock}{Example} - \begin{cppcode*}{} - constexpr int f(int x) { - if (x > 1) return x * f(x - 1); - return 1; - } - constexpr int a = f(5); // computed at compile-time - int b = f(5); // maybe computed at compile-time - int n = ...; // runtime value - int c = f(n); // computed at runtime - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[14]{Generalized Constant Expressions(2)} - \begin{block}{Notes} - \begin{itemize} - \item A \cppinline{constexpr} function \emph{may} be executed at compile time. - \begin{itemize} - \item Arguments must be \cppinline{constexpr} or literals in order to allow compile time evaluation - \item Function body must be visible to the compiler - \end{itemize} - \item A \cppinline{constexpr} function can also be used at runtime - \item A \cppinline{constexpr} variable must be initialized at compile time - \item Classes can have \cppinline{constexpr} member functions - \item Objects used in constant expressions must be of \emph{literal type}: - \begin{itemize} - \item integral, floating-point, enum, reference, pointer type - \item union (of at least one) or array of literal types - \item class type with a \cppinline{constexpr} constructor and - the destructor is trivial (or \cppinline{constexpr} since C++20) - \end{itemize} - \item A constexpr function is implicitly \cppinline{inline} (header files) - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile,shrink=15] - \frametitlecpp[11]{Limitations of constexpr functions} - \begin{block}{C++11} - \begin{itemize} - \item Non-virtual function with a single return statement - \end{itemize} - \end{block} - \begin{block}{C++14/C++17} - \begin{itemize} - \item no try-catch, goto or asm statements - \item no uninitialized/static/thread\_local/non-literal-type variables - \end{itemize} - \end{block} - \begin{block}{C++20} - \begin{itemize} - \item no coroutines or static/thread\_local/non-literal-type variables - \item throw and asm statements allowed, but may not be executed - \item transient memory allocation - (memory allocated at compile-time must be freed again at compile-time) - \item virtual functions and uninitialized variables allowed - \end{itemize} - \end{block} - \begin{block}{C++23} - \begin{itemize} - \item no coroutines, or execution of throw and asm statements - \item transient memory allocation - \item everything else allowed - \end{itemize} - \end{block} - Further details on \href{https://en.cppreference.com/w/cpp/language/constexpr}{cppreference} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Real life example} - \begin{cppcode*}{} - constexpr float toSI(float v, char unit) { - switch (unit) { - case 'k': return 1000.0f*v; - case 'm': return 0.001f*v; - case 'y': return 0.9144f*v; - case 'i': return 0.0254f*v; - ... - default: return v; - } - } - constexpr float fromSI(float v, char unit) { - switch (unit) { - case 'k': return 0.001f*v; - case 'y': return 1.093f*v; - ... - } - } - \end{cppcode*} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Real life example(2)} - \begin{cppcode*}{} - class DimLength { - float m_value; - public: - constexpr DimLength(float v, char unit): - m_value(toSI(v, unit)) { - } - constexpr float get(char unit) const { - return fromSI(m_value, unit); - } - }; - constexpr DimLength km(1, 'k'); - constexpr float km_y = km.get('y'); - constexpr float km_i = km.get('i'); - static_assert(km_y == 1093, "expected km == 1093 yards!"); - \end{cppcode*} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{compile-time branches} - \begin{block}{{\it if constexpr}} - \begin{itemize} - \item takes a \cppinline{constexpr} expression as condition - \item evaluates at compile time - \item key benefit: the discarded branch can contain invalid code - \end{itemize} - \end{block} - \begin{exampleblock}{Example code} - \small - \begin{cppcode*}{} - template - auto remove_ptr(T t) { - if constexpr (std::is_pointer_v) { - return *t; - } else { - return t; - } - } - int i = ...; int *j = ...; - int r = remove_ptr(i); // equivalent to i - int q = remove_ptr(j); // equivalent to *j - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Immediate functions} - \begin{block}{Motivation} - \begin{itemize} - \item Force a function to be executed at compile-time - \item Runtime evaluation is forbidden - \item Same restrictions as \cppinline{constexpr} functions - \item New keyword: \cppinline{consteval} - \end{itemize} - \end{block} - \begin{exampleblock}{Example} - \begin{cppcode*}{} - consteval int f(int x) { - if (x > 1) return x * f(x - 1); - return 1; - } - constexpr int a = f(5); // computed at compile-time - int b = f(5); // computed at compile-time - int n = ...; // runtime value - int c = f(n); // compilation error - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{constinit} - \begin{block}{Motivation} - \begin{itemize} - \item Like a \cppinline{constexpr} variable, a \cppinline{constinit} variable guarantees compile-time initialization, but can be modified afterwards - \item Only allowed for \cppinline{static}/global and \cppinline{thread_local} variables - \item Initializer must be a constant expression, but \cppinline{constexpr} destruction is not required - \end{itemize} - \end{block} - \begin{exampleblock}{Example} - \begin{cppcode} - constexpr int f(int x) { - if (x > 1) return x * f(x - 1); - return 1; - } - constexpr int a = f(5); // CT init, not modifiable - int b = f(5); // maybe CT init, modifiable - constinit int c = f(5); // CT init, modifiable - \end{cppcode} - \end{exampleblock} -\end{frame} diff --git a/talk/morelanguage/constness.tex b/talk/morelanguage/constness.tex deleted file mode 100644 index ede4ade1..00000000 --- a/talk/morelanguage/constness.tex +++ /dev/null @@ -1,107 +0,0 @@ -\subsection[cst]{Constness} - -\begin{frame}[fragile] - \frametitlecpp[98]{Constness} - \begin{block}{The \texttt{const} keyword} - \begin{itemize} - \item indicates that the element to the left is constant - \begin{itemize} - \item when nothing on the left, applies to the right - \end{itemize} - \item this element won't be modifiable in the future - \item this is all checked at compile time - \end{itemize} - \end{block} - \begin{cppcode} - int const i = 6; - const int i = 6; // equivalent - - // error: i is constant - i = 5; - - auto const j = i; // works with auto - \end{cppcode} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Constness and pointers} - \small - \begin{cppcode} - int a = 1, b = 2; - - int const *i = &a; // pointer to const int - *i = 5; // error, int is const - i = &b; // ok, pointer is not const - - int * const j = &a; // const pointer to int - *j = 5; // ok, value can be changed - j = &b; // error, pointer is const - - int const * const k = &a; // const pointer to const int - *k = 5; // error, value is const - k = &b; // error, pointer is const - - int const & l = a; // reference to const int - l = b; // error, reference is const - - int const & const l = a; // compile error - \end{cppcode} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Member function constness} - \begin{block}{The \texttt{const} keyword for member functions} - \begin{itemize} - \item indicates that the function does not modify the object - \item in other words, \cppinline{this} is a pointer to a constant object - \end{itemize} - \end{block} - \begin{cppcode} - struct Example { - void foo() const { - // type of 'this' is 'Example const*' - data = 0; // Error: member function is const - } - void foo() { // ok, overload - data = 1; // ok, 'this' is 'Example*' - } - int data; - }; - Example const e1; e1.foo(); // calls const foo - Example e2; e2.foo(); // calls non-const foo - \end{cppcode} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Member function constness} - \begin{block}{Constness is part of the type} - \begin{itemize} - \item \cppinline{T const} and \cppinline{T} are different types - \item but: \cppinline{T} is automatically converted to \cppinline{T const} when needed - \end{itemize} - \end{block} - \begin{cppcode} - void change(int & a); - void read(int const & a); - - int a = 0; - int const b = 0; - - change(a); // ok - change(b); // error - read(a); // ok - read(b); // ok - \end{cppcode} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{constness} - \begin{exercise}{Constness} - \begin{itemize} - \item go to \texttt{exercises/constness} - \item open constplay.cpp - \item try to find out which lines won't compile - \item check your guesses by compiling for real - \end{itemize} - \end{exercise} -\end{frame} diff --git a/talk/morelanguage/copyelision.tex b/talk/morelanguage/copyelision.tex deleted file mode 100644 index e5fd1917..00000000 --- a/talk/morelanguage/copyelision.tex +++ /dev/null @@ -1,48 +0,0 @@ -\subsection[copy]{Copy elision} - -\begin{frame}[fragile] - \frametitlecpp[17]{Copy elision} - \begin{block}{Where does it take place ?} - \small - \begin{cppcode*}{} - struct Foo { ... }; - Foo f() { - return Foo(); // return-value opt. (RVO) - } - Foo g() { - Foo foo; - return foo; // named return-value opt. (NRVO) - } - int main() { - // compiler must avoid these copies: - Foo a = f(); - Foo b = Foo(); - Foo c = Foo(Foo()); - // copy elision allowed, but not guaranteed: - Foo d = g(); - } - \end{cppcode*} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{Guaranteed copy elision} - Allows to write code not allowed in \cpp14 (would not compile) - \begin{block}{Guaranteed: Return value optimization (RVO)} - \begin{cppcode*}{} - struct Foo { - Foo() { ... } - Foo(const Foo &) = delete; - Foo(Foo &&) = delete; - Foo& operator=(const Foo &) = delete; - Foo& operator=(Foo &&) = delete; - }; - Foo f() { - return Foo(); // ok, no move - } - int main() { - Foo foo = f(); // ok, no move - } - \end{cppcode*} - \end{block} -\end{frame} diff --git a/talk/morelanguage/exceptions.tex b/talk/morelanguage/exceptions.tex deleted file mode 100644 index 77a08686..00000000 --- a/talk/morelanguage/exceptions.tex +++ /dev/null @@ -1,432 +0,0 @@ -\subsection[except]{Exceptions} - -\begin{frame}[fragile] - \frametitlecpp[98]{Exceptions} - \begin{block}{Purpose} - \begin{itemize} - \item to handle \textit{exceptional} events that happen rarely - \item and cleanly jump to a place where the error can be handled - \end{itemize} - \end{block} - \begin{block}{In practice} - \begin{itemize} - \item add an exception handling block with \cppinline{try} ... \cppinline{catch} - \begin{itemize} - \item when exceptions are possible \textit{and can be handled} - \end{itemize} - \item throw an exception using \cppinline{throw} - \begin{itemize} - \item when a function cannot proceed or recover internally - \end{itemize} - \end{itemize} - \end{block} - \begin{multicols}{2} - \begin{cppcode*}{fontsize=\small} - try { - process_data(f); - } catch (const - std::out_of_range& e) { - std::cerr << e.what(); - } - \end{cppcode*} - \columnbreak - \begin{cppcode*}{fontsize=\small,firstnumber=7} - void process_data(file &f) { - ... - if (i >= buffer.size()) - throw std::out_of_range{ - "buf overflow"}; - } - \end{cppcode*} - \end{multicols} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Exceptions} - \begin{block}{Throwing exceptions} - \begin{itemize} - \item objects of any type can be thrown (even e.g.\ \cppinline{int}) - \end{itemize} - \end{block} - \begin{goodpractice}{Throwing exceptions} - \begin{itemize} - \item prefer throwing standard exception classes - \item throw objects by value - \end{itemize} - \end{goodpractice} - \small - \begin{cppcode} - #include - void process_data(file& f) { - if (!f.open()) - throw std::invalid_argument{"stream is not open"}; - auto header = read_line(f); // may throw an IO error - if (!header.starts_with("BEGIN")) - throw std::runtime_error{"invalid file content"}; - std::string body(f.size()); // may throw std::bad_alloc - ... - } - \end{cppcode} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Exceptions} - \begin{block}{Standard exceptions} - \begin{itemize} - \item \cppinline{std::exception}, defined in header \cppinline{} - \begin{itemize} - \item Base class of all standard exceptions - \item Get error message: \cppinline{virtual const char* what() const;} - \item Please derive your own exception classes from this one - \end{itemize} - \item From \cppinline{}: - \begin{itemize} - \item \cppinline{std::runtime_error}, \cppinline{std::logic_error}, \cppinline{std::out_of_range}, \cppinline{std::invalid_argument}, ... - \item Store a string: \cppinline{throw std::runtime_error{"msg"}} - \item You should use these the most - \end{itemize} - \item \cppinline{std::bad_alloc}, defined in header \cppinline{} - \begin{itemize} - \item Thrown by standard allocation functions (e.g.\ \cppinline{new}) - \item Signals failure to allocate - \item Carries no message - \end{itemize} - \item ... - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Exceptions} - \begin{block}{Catching exceptions} - \begin{itemize} - \item a catch clause catches exceptions of the same or derived type - \item multiple catch clauses will be matched in order - \item if no catch clause matches, the exception propagates - \item if the exception is never caught, \cppinline{std::terminate} is called - \end{itemize} - \end{block} - \begin{cppcode} - try { - process_data(f); - } catch (const std::invalid_argument& e) { - bad_files.push_back(f); - } catch (const std::exception& e) { - std::cerr << "Failed to process file: " << e.what(); - } - \end{cppcode} - \begin{goodpractice}{Catching exceptions} - \begin{itemize} - \item Catch exceptions by const reference - \end{itemize} - \end{goodpractice} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Exceptions} - \begin{block}{Rethrowing exceptions} - \begin{itemize} - \item a caught exception can be rethrown inside the catch handler - \item useful when we want to act on an error, but cannot handle and want to propagate it - \end{itemize} - \end{block} - \begin{cppcode} - try { - process_data(f); - } catch (const std::bad_alloc& e) { - std::cerr << "Insufficient memory for " << f.name(); - throw; // rethrow - } - \end{cppcode} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Exceptions} - \begin{block}{Catching everything} - \begin{itemize} - \item sometimes we need to catch all possible exceptions - \item e.g.\ in \cppinline{main}, a thread, a destructor, interfacing with C, \ldots - \end{itemize} - \end{block} - \begin{cppcode} - - try { - callUnknownFramework(); - } catch(const std::exception& e) { - // catches std::exception and all derived types - std::cerr << "Exception: " << e.what() << std::endl; - } catch(...) { - // catches everything else - std::cerr << "Unknown exception type" << std::endl; - } - \end{cppcode} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Exceptions} - \begin{block}{Stack unwinding} - \begin{itemize} - \item all objects on the stack between a \cppinline{throw} and the matching \cppinline{catch} are destructed automatically - \item this should cleanly release intermediate resources - \item make sure you are using the RAII idiom for your own classes - \end{itemize} - \end{block} - \begin{multicols}{2} - \begin{cppcode*}{} - class C { ... }; - void f() { - C c1; - throw exception{}; - // start unwinding - C c2; // not run - } - void g() { - C c3; f(); - } - \end{cppcode*} - \columnbreak - \begin{cppcode*}{firstnumber=11} - int main() { - try { - C c4; - g(); - cout << "done"; // not run - } catch(const exception&) { - // c1, c3 and c4 have been - // destructed - } - } - \end{cppcode*} - \end{multicols} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{Exceptions} - \begin{goodpractice}{Exceptions} - \begin{itemize} - \item use exceptions for \textit{unlikely} runtime errors outside the program's control - \begin{itemize} - \item bad inputs, files unexpectedly not found, DB connection, \ldots - \end{itemize} - \item \textit{don't} use exceptions for logic errors in your code - \begin{itemize} - \item use \cppinline{assert} and tests - \end{itemize} - \item \textit{don't} use exceptions to provide alternative/skip return values - \begin{itemize} - \item you can use \cppinline{std::optional}, \cppinline{std::variant} or \cppinline{std::expected} (\cpp23) - \item avoid using the global C-style \cppinline{errno} - \end{itemize} - \item never throw in destructors - \item see also the \href{https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#S-errors}{\cpp core guidelines} and the \href{https://isocpp.org/wiki/faq/exceptions}{ISO \cpp FAQ} - \end{itemize} - \end{goodpractice} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Exceptions} - \begin{block}{A more illustrative example} - \begin{itemize} - \item exceptions are very powerful when there is much code between the error and where the error is handled - \item they can also rather cleanly handle different types of errors - \item \cppinline{try}/\cppinline{catch} statements can also be nested - \end{itemize} - \end{block} - \begin{multicols}{2} - \begin{cppcode*}{fontsize=\scriptsize} - try { - for (File const &f : files) { - try { - process_file(f); - } - catch (bad_file const & e) { - ... // loop continues - } - } - } catch (bad_db const & e) { - ... // loop aborted - } - \end{cppcode*} - \columnbreak - \begin{cppcode*}{fontsize=\scriptsize} - void process_file(File const & file) { - ... - if (handle = open_file(file)) - throw bad_file(file.status()); - while (!handle) { - line = read_line(handle); - database.insert(line); // can throw - // bad_db - } - } - \end{cppcode*} - \end{multicols} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Exceptions} - \begin{block}{Cost} - \begin{itemize} - \item exceptions have little cost if no exception is thrown - \begin{itemize} - \item they are recommended to report \textit{exceptional} errors - \end{itemize} - \item for performance, when error raising and handling are close, or errors occur often, prefer error codes or a dedicated class - \item when in doubt about which error strategy is better, profile! - \end{itemize} - \end{block} - \begin{multicols}{2} - \begin{minipage}{5cm} - \begin{alertblock}{Avoid} - \begin{cppcode*}{fontsize=\scriptsize,linenos=false} - for (string const &num: nums) { - try { - int i = convert(num); // can - // throw - process(i); - } catch (not_an_int const &e) { - ... // log and continue - } - } - \end{cppcode*} - \end{alertblock} - \end{minipage} - \columnbreak - \begin{minipage}{5cm} - \begin{exampleblock}{Prefer} - \begin{cppcode*}{fontsize=\scriptsize,linenos=false} - for (string const &num: nums) { - optional i = convert(num); - if (i) { - process(*i); - } else { - ... // log and continue - } - } - \end{cppcode*} - \end{exampleblock} - \end{minipage} - \end{multicols} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{noexcept specifier} - \begin{block}{\texttt{noexcept}} - \begin{itemize} - \item a function with the \cppinline{noexcept} specifier states that it guarantees to not throw an exception - \begin{cppcode*}{linenos=false} - int f() noexcept; - \end{cppcode*} - \begin{itemize} - \item either no exceptions is thrown or they are handled internally - \item if one is thrown, `std::terminate` is called - \item allows the compiler to optimize around that knowledge - \end{itemize} - \item a function with \cppinline{noexcept(expression)} is only \cppinline{noexcept} when \cppinline{expression} evaluates to \cppinline{true} at compile-time - \begin{cppcode*}{linenos=false} - int safe_if_8B() noexcept(sizeof(long)==8); - \end{cppcode*} - \end{itemize} - \end{block} - \begin{goodpractice}{\texttt{noexcept}} - \begin{itemize} - \item Use \cppinline{noexcept} on leaf functions where you know the behavior - \item C++11 destructors are \cppinline{noexcept} - never throw from them - \end{itemize} - \end{goodpractice} -\end{frame} - -\begin{advanced} -\begin{frame}[fragile] - \frametitlecpp[11]{noexcept operator} - \begin{block}{} - \begin{itemize} - \item the \cppinline{noexcept(expression)} operator checks at compile-time whether an expression can throw exceptions - \item returns a \cppinline{bool}, which is \cppinline{true} if no exceptions can be thrown - \end{itemize} - \end{block} - \begin{block}{} - \begin{cppcode*}{} - constexpr bool callCannotThrow = noexcept(f()); - if constexpr (callCannotThrow) { ... } - \end{cppcode*} - \end{block} - \begin{block}{} - \begin{cppcode*}{firstnumber=3} - template - void g(Function f) noexcept(noexcept(f())) { - ... - f(); - } - \end{cppcode*} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Exceptions} - \begin{block}{Exception Safety Guarantees} - A function can offer the following guarantees: - \begin{itemize} - \item No guarantee - \begin{itemize} - \item An exception will lead to undefined program state - \end{itemize} - \item Basic exception safety guarantee - \begin{itemize} - \item An exception will leave the program in a defined state - \begin{itemize} - \item At least destructors must be able to run - \item This is similar to the moved-from state - \end{itemize} - \item No resources are leaked - \end{itemize} - \item Strong exception safety guarantee - \begin{itemize} - \item The operation either succeeds or has no effect - \item When an exception occurs, the original state must be restored - \item This is hard to do, possibly expensive, maybe impossible - \end{itemize} - \item No-throw guarantee - \begin{itemize} - \item The function never throws (e.g.\ is marked \cppinline{noexcept}) - \item Errors are handled internally or lead to termination - \end{itemize} - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Exceptions} - \begin{block}{Alternatives to exceptions} - \begin{itemize} - \item The global variable \cppinline{errno} (avoid) - \item Return an error code (e.g.\ an \cppinline{int} or an \cppinline{enum}) - \item Return a \cppinline{std::error_code} (\cpp11) - \item If failing to produce a value is not a hard error, consider returning \cppinline{std::optional} (\cpp17) - \item Return \cppinline{std::expected} (\cpp23), where \cppinline{T} is the return type on success and \cppinline{E} is the type on failure - \item Terminate the program - \begin{itemize} - \item e.g.\ by calling \cppinline{std::terminate()} or \cppinline{std::abort()} - \end{itemize} - \item Contracts: Specify function pre- and postconditions. Planned for \cpp20, but removed. Will come back in the future - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Further resources} - \begin{block}{} - \begin{itemize} - \item \href{https://isocpp.org/wiki/faq/exceptions}{Exceptions and Error Handling} - ISO C++ FAQ - \item \href{https://www.youtube.com/watch?v=0ojB8c0xUd8&t=1505s}{Back to Basics: Exceptions - Klaus Iglberger - CppCon 2020} - \item \href{https://www.youtube.com/watch?v=fOV7I-nmVXw}{The Unexceptional Exceptions - Fedor Pikus - CppCon 2015} - \item \href{https://www.youtube.com/watch?v=ZUH8p1EQswA}{The Dawn of a New Error, (C++ error-handling and exceptions) - Phil Nash - CppCon 2019} (alternatives) - \item \href{https://www.youtube.com/watch?v=mkkaAWNE-Ig}{Exceptions the Other Way Round - Sean Parent - CppNow 2022} (theoretical approach to errors) - \item \href{https://wg21.link/P0709}{P0709}: Zero-overhead deterministic exceptions: Throwing values - Herb Sutter (proposal - distant future) - \begin{itemize} - \item \href{https://www.youtube.com/watch?v=ARYP83yNAWk}{De-fragmenting C++: Making Exceptions and RTTI More Affordable and Usable - Herb Sutter CppCon 2019} - \end{itemize} - \end{itemize} - \end{block} -\end{frame} -\end{advanced} diff --git a/talk/morelanguage/initialization.tex b/talk/morelanguage/initialization.tex deleted file mode 100644 index f04c9962..00000000 --- a/talk/morelanguage/initialization.tex +++ /dev/null @@ -1,180 +0,0 @@ -\subsection[Init]{Initialization} - -\begin{frame}[fragile] - \frametitle{Initialization} - \begin{block}{Initializing scalars} - \begin{cppcode} - int i(42); // direct initialization - int i{42}; // direct list initialization (C++11) - int i = 42; // copy initialization - int i = {42}; // copy list initialization (C++11) - \end{cppcode} - \begin{itemize} - \item All of the above have the same effect: \cppinline{i == 42} - \end{itemize} - \end{block} - \begin{block}{Narrowing conversions} - \begin{cppcode} - int i(42.3); // i == 42 - int i{42.3}; // compilation error - int i = 42.3; // i == 42 - int i = {42.3}; // compilation error - \end{cppcode} - \begin{itemize} - \item Braced initialization prevents narrowing conversions - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile,shrink=10] - \frametitle{Initialization} - \begin{block}{Initializing class types with constructors} - \begin{cppcode} - struct C { - C(int i); - C(int i, int j); - }; - - C c(42); // calls C(42) - C c{42}; // same - C c = 42; // calls C(42) in C++17, before C(C(42)) - C c = {42}; // same - - C c(1, 2); // calls C(1, 2) - C c{1, 2}; // calls C(1, 2) - C c = (1, 2); // calls C(2), comma operator - C c = {1, 2}; // calls C(1, 2) in C++17, before C(C(1, 2)) - - C c(1.1, 2.2); // calls C(1, 2) - C c{1.1, 2.2}; // compilation error - \end{cppcode} - \end{block} -\end{frame} - -\begin{frame}[fragile,shrink=10] - \frametitle{Initialization} - \begin{block}{std::initializer\_list} - \begin{cppcode} - struct C { - C(int i, int j); - C(std::initializer_list l); - }; - - C c(1, 2); // calls C(1, 2) - C c{1, 2}; // calls C(std::initializer_list{1, 2}) - C c = (1, 2); // calls C(2), comma operator, error - C c = {1, 2}; // calls C(std::initializer_list{1, 2}) - \end{cppcode} - \begin{itemize} - \item A constructor with a \cppinline{std::initializer_list} parameter takes precedence over other overloads. - \end{itemize} - \end{block} - \begin{alertblock}{Beware} - \begin{cppcode} - std::vector v1(4, 5); // {5, 5, 5, 5} - std::vector v2{4, 5}; // {4, 5} - \end{cppcode} - \end{alertblock} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Initialization} - \begin{block}{Type deduction} - \begin{cppcode} - auto i(42); // int - auto i{42}; // C++11: std::initializer_list - // since C++17: int - auto i = 42; // int - auto i = {42}; // std::initializer_list - \end{cppcode} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Initialization} - \begin{block}{Default initialization} - \begin{cppcode*}{linenos=false} - T t; - \end{cppcode*} - \begin{itemize} - \item If \cppinline{T} has a default constructor (including compiler generated), calls it - \item If \cppinline{T} is a fundamental type, \cppinline{t} is left uninitialized (undefined value) - \item If \cppinline{T} is an array, the same rules are applied to each item - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Initialization} - \begin{block}{Value initialization} - \begin{cppcode} - T t{}; // value initialization - T t = {}; // same - f(T()); // passes value-initialized temporary - f(T{}); // same - T t(); // function declaration - \end{cppcode} - \begin{itemize} - \item Basically zero-initializes \cppinline{t} (or the temporary), unless \cppinline{T} has a user defined constructor, which is run in this case - \item Details on \href{https://en.cppreference.com/w/cpp/language/value_initialization}{cppreference} - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile,shrink=10] - \frametitlecpp[11]{Initialization} - \begin{block}{Aggregate initialization} - \begin{cppcode} - struct S { int i; double d; }; - - S s{1, 2.3}; // s.i == 1, s.d == 2.3 - S s = {1, 2.3}; // same - S s{.i = 1, .d = 2.3} // same, designated init. (C++20) - S s = {.i = 1, .d = 2.3} // same - S s{1}; // s.i == 1, s.d == 0.0 - S s = {1}; // same - S s{.i = 1} // same (C++20) - S s = {.i = 1} // same (C++20) - S s{}; // value init, s.i == 0, s.d == 0.0 - S s; // default init, undefined values - \end{cppcode} - \begin{itemize} - \item An aggregate is a class with no constructors, only public base classes (\cpp17) and members, no virtual functions, no default member initializers (until \cpp14) - \item Details on \href{https://en.cppreference.com/w/cpp/language/aggregate_initialization}{cppreference} - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Initialization} - \begin{goodpractice}{Initialization} - \begin{itemize} - \item In generic code, for a generic type \cppinline{T}: - \begin{itemize} - \item \cppinline{T t;} performs the minimally necessary initialization - \item \cppinline{T t{};} performs full and deterministic initialization - \end{itemize} - \item Prefer \cppinline{T t{};} over \cppinline{T t; memset(&t, 0, sizeof(t));} - \item Prefer braces over parentheses to avoid accidental narrowing conversions. E.g.\ \cppinline{T t{1, 2};} - \begin{itemize} - \item Unless \cppinline{T} has a \cppinline{std::initializer_list} constructor that you do not want to call! - \item Be wary of \cppinline{std::vector}! - \end{itemize} - \item The STL uses value initialisation when resizing containers - \begin{itemize} - \item E.g. \cppinline{vec.resize(vec.size() + 10);} - \end{itemize} - \item Aggregates are very flexible. If your class does not need special initialization, make it an aggregate (rule of zero) - \end{itemize} - \end{goodpractice} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Initialization} - \begin{block}{Further resources} - \begin{itemize} - \item \href{https://www.youtube.com/watch?v=7DTlWPgX6zs}{The Nightmare of Initialization in C++ - Nicolai Josuttis - CppCon 2018} - \item \href{https://www.youtube.com/watch?v=ZfP4VAK21zc}{Initialization in modern C++ - Timur Doumler - Meeting C++ 2018} - \end{itemize} - \end{block} -\end{frame} diff --git a/talk/morelanguage/lambda.tex b/talk/morelanguage/lambda.tex deleted file mode 100644 index 7c064e4e..00000000 --- a/talk/morelanguage/lambda.tex +++ /dev/null @@ -1,376 +0,0 @@ -\subsection[$\lambda$]{Lambdas} - -\begin{frame}[fragile] - \frametitlecpp[11]{Lambda expressions} - \begin{block}{Definition} - A lambda expression is a function with no name - \end{block} - \pause - \begin{exampleblock}{Python example} - \begin{pythoncode*}{} - data = [1,9,3,8,3,7,4,6,5] - - # without lambdas - def isOdd(n): - return n%2 == 1 - print(filter(isOdd, data)) - - # with lambdas - print(filter(lambda n:n%2==1, data)) - \end{pythoncode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{\cpp Lambdas} - \begin{block}{Simplified syntax} - \begin{cppcode*}{} - auto f = [] (arguments) -> return_type { - statements; - }; - \end{cppcode*} - \begin{itemize} - \item The return type specification is optional - \item \cppinline{f} is an instance of a functor type, generated by the compiler - \end{itemize} - \end{block} - \begin{exampleblock}{Usage example} - \begin{cppcode*}{firstnumber=4} - int data[]{1,2,3,4,5}; - auto f = [](int i) { - std::cout << i << " squared is " << i*i << '\n'; - }; - for (int i : data) f(i); - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Trailing function return type} - \begin{block}{An alternate way to specify a function's return type} - \begin{cppcode*}{linenos=false} - int f(float a); // classic - auto f(float a) -> int; // trailing - auto f(float a) { return 42; } // deduced, C++14 - \end{cppcode*} - \end{block} - \pause - \begin{block}{When to use trailing return type} - \begin{itemize} - \item Only way to specify return type for lambdas - \item Allows to simplify inner type definition - \begin{cppcode*}{} - class Equation { - using ResultType = double; - ResultType evaluate(); - } - Equation::ResultType Equation::evaluate() {...} - auto Equation::evaluate() -> ResultType {...} - \end{cppcode*} - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Capturing variables} - \begin{block}{Adaptable lambdas} - \begin{itemize} - \item Adapt lambda's behaviour by accessing variables outside of it - \item This is called ``capture'' - \end{itemize} - \end{block} - \pause - \begin{block}{First attempt in \cpp} - \begin{cppcode} - int increment = 3; - int data[]{1,9,3,8,3,7,4,6,5}; - auto f = [](int x) { return x+increment; }; - for(int& i : data) i = f(i); - \end{cppcode} - \end{block} - \pause - \begin{alertblock}{Error} - \begin{minted}{text} - error: 'increment' is not captured - [](int x) { return x+increment; }); - ^ - \end{minted} - \end{alertblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Capturing variables} - \begin{block}{The capture list} - \begin{itemize} - \item local variables outside the lambda must be explicitly captured - \begin{itemize} - \item unlike in Python, Java, C\#, Rust, ... - \end{itemize} - \item captured variables are listed within initial \cppinline{[]} - \end{itemize} - \end{block} - \pause - \begin{exampleblock}{Example} - \begin{cppcode*}{} - int increment = 3; - int data[]{1,9,3,8,3,7,4,6,5}; - auto f = [increment](int x) { return x+increment; }; - for(int& i : data) i = f(i); - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Default capture is by value} - \begin{exampleblock}{Code example} - \begin{cppcode} - int sum = 0; - int data[]{1,9,3,8,3,7,4,6,5}; - auto f = [sum](int x) { sum += x; }; - for (int i : data) f(i); - \end{cppcode} - \end{exampleblock} - \pause - \begin{alertblock}{Error} - \begin{minted}{text} - error: assignment of read-only variable 'sum' - [sum](int x) { sum += x; }); - \end{minted} - \end{alertblock} - \pause - \begin{block}{Explanation} - \begin{itemize} - \item By default, variables are captured by value - \item The lambda's \cppinline{operator()} is \cppinline{const inline} - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Capture by reference} - \begin{exampleblock}{Simple example} - In order to capture by reference, add '\&' before the variable - \begin{cppcode*}{} - int sum = 0; - int data[]{1,9,3,8,3,7,4,6,5}; - auto f = [&sum](int x) { sum += x; }; - for (int i : data) f(i); - \end{cppcode*} - \end{exampleblock} - \pause - \begin{exampleblock}{Mixed case} - One can of course mix values and references - \begin{cppcode*}{firstnumber=5} - int sum = 0, off = 1; - int data[]{1,9,3,8,3,7,4,6,5}; - auto f = [&sum, off](int x) { sum += x + off; }; - for (int i : data) f(i); - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Capture by value vs.\ by reference} - \begin{exampleblock}{See the difference between val and ref} - \begin{cppcode*}{} - int data[]{1,9,3,8,3,7,4,6,5}; - int increment = 3; - auto val = [ inc](int x) { return x+inc; }; - auto ref = [&inc](int x) { return x+inc; }; - - increment = 4; - - for(int& i : data) i = val(i); // increments by 3 - for(int& i : data) i = ref(i); // increments by 4 - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[14]{Init capture} - \begin{exampleblock}{Capture with an initializer} - In \cpp14, can declare captures with initializers - \begin{cppcode*}{} - auto f = [inc = 1+2](int x) { return x+inc; }; - auto g = [inc = getInc()](int x) { return x+inc; }; - for(int& i : data) i = f(i); // increments by 3 - for(int& i : data) i = g(i); // unknown increment - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Anatomy of a lambda} - \begin{block}{Lambdas are pure syntactic sugar - \cppinsightLink{https://cppinsights.io/s/67800da8}} - \begin{itemize} - \item They are replaced by a functor during compilation - \end{itemize} - \begin{columns} - \scriptsize - \begin{column}{.25\textwidth} - \begin{cppcode*}{} - int sum = 0, off = 1; - auto l = - [&sum, off] - - - - (int x) { - sum += x + off; - }; - - - l(42); - \end{cppcode*} - \end{column} - \begin{column}{.45\textwidth} - \begin{cppcode*}{firstnumber=13} - int sum = 0, off = 1; - struct __lambda4 { - int& sum; int off; - __lambda4(int& s, int o) - : sum(s), off(o) {} - - auto operator()(int x) const { - sum += x + off; - } - }; - auto l = __lambda4{sum, off}; - l(42); - \end{cppcode*} - \end{column} - \end{columns} - \end{block} - \begin{exampleblock}{Some nice consequences} - \begin{itemize} - \item Lambda expressions create ordinary objects - \item They can be copied, moved, or inherited from - \end{itemize} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Capture list} - \begin{block}{all by value} - \begin{cppcode*}{linenos=false} - [=](...) { ... }; - \end{cppcode*} - \end{block} - \pause - \begin{block}{all by reference} - \begin{cppcode*}{linenos=false} - [&](...) { ... }; - \end{cppcode*} - \end{block} - \pause - \begin{block}{mix} - \begin{cppcode*}{linenos=false} - [&, b](...) { ... }; - [=, &b](...) { ... }; - \end{cppcode*} - \end{block} -\end{frame} - -\begin{advanced} - -\begin{frame}[fragile] - \frametitlecpp[11]{Capture list - this} - \begin{block}{} - Inside a (non-static) member function, we can capture \cppinline{this}. - \end{block} - \begin{block}{} - \begin{cppcode*}{} - [ this](...) { use(*this); }; - [ &](...) { use(*this); }; - [&, this](...) { use(*this); }; - [ =](...) { use(*this); }; // deprecated in C++20 - [=, this](...) { use(*this); }; // allowed in C++20 - \end{cppcode*} - Since the captured \cppinline{this} is a pointer, \cppinline{*this} refers to the object by reference. - \end{block} - \pause - \begin{block}{} - \begin{cppcode*}{} - [ *this](...) { use(*this); }; // C++17 - [&, *this](...) { use(*this); }; // C++17 - [=, *this](...) { use(*this); }; // C++17 - \end{cppcode*} - The object at \cppinline{*this} is captured by value (the lambda gets a copy). - \end{block} - Details in \href{https://www.nextptr.com/tutorial/ta1430524603/capture-this-in-lambda-expression-timeline-of-change}{this blog post}. -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[14]{Generic lambdas} - \begin{block}{Generic lambdas (aka.\ polymorphic lambdas)} - \begin{itemize} - \item The type of lambda parameters may be \cppinline{auto}. - \begin{cppcode*}{linenos=false} - auto add = [](auto a, auto b) { return a + b; }; - \end{cppcode*} - \item The generated \cppinline{operator()} becomes a template function: - \begin{cppcode*}{linenos=false} - template - auto operator()(T a, U b) const { return a + b; } - \end{cppcode*} - \item The types of \cppinline{a} and \cppinline{b} may be different. - \end{itemize} - \end{block} - \begin{block}{Explicit template parameters (\cpp20)} - \begin{cppcode*}{linenos=false} - auto add = [](T a, T b) - { return a + b; }; - \end{cppcode*} - \begin{itemize} - \item The types of \cppinline{a} and \cppinline{b} must be the same. - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Higher-order lambdas} - \begin{exampleblockGB}{Example}{https://godbolt.org/z/GMj76Wer7}{\texttt{lambda}} - \begin{cppcode*}{} - auto build_incrementer = [](int inc) { - return [inc](int value) { return value + inc; }; - }; - auto inc1 = build_incrementer(1); - auto inc10 = build_incrementer(10); - int i = 0; - i = inc1(i); // i = 1 - i = inc10(i); // i = 11 - \end{cppcode*} - \end{exampleblockGB} - \begin{block}{How it works} - \begin{itemize} - \item \cppinline{build_incrementer} returns a function object - \item this function's behavior depends on a parameter - \item note how \cppinline{auto} is useful here! - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Lambda improvements} - \begin{block}{Lambda improvements in \cpp20} - \begin{itemize} - \item Allowed in unevaluated contexts,\\ - e.g.\ within \cppinline{decltype}, \cppinline{sizeof}, \cppinline{typeid}, etc. - \item Without captures, are default-constructible and assignable - \end{itemize} - \end{block} - \begin{exampleblockGB}{Example}{https://godbolt.org/z/GoE6xM8EG}{\texttt{lambda \cpp20}} - \small - \begin{cppcode*}{} - struct S { - decltype([](int i) { std::cout << i; }) f; - } s; - s.f(42); // prints "42" - - std::set s2; - \end{cppcode*} - \end{exampleblockGB} - -\end{frame} - -\end{advanced} diff --git a/talk/morelanguage/morestl.tex b/talk/morelanguage/morestl.tex deleted file mode 100644 index 1c808a8f..00000000 --- a/talk/morelanguage/morestl.tex +++ /dev/null @@ -1,483 +0,0 @@ -\subsection[STD]{Standard library} - -\begin{frame}[fragile] - \frametitlecpp[17]{\texttt{std::string\_view} \cpprefLink{https://en.cppreference.com/w/cpp/string/basic_string_view}} - \begin{block}{Non owning read-only view of a contiguous char sequence} - \begin{itemize} - \item Doesn't allocate memory - \item Similar interface to \cppinline{std::string}, but read-only - \item Easy to copy, faster for some calls eg. \texttt{substr} (O(1) vs O(n)) - \item The data pointed to has to outlive the \cppinline{string_view} - \end{itemize} - \end{block} - \begin{exampleblock}{Some example uses} - \begin{cppcode*}{} - constexpr std::string_view sv {"Some example"}; - auto first = sv.substr(0, sv.find_first_of(" ")); - std::string some_string {"foo bar"}; - std::string_view sv_str(some_string); - char foo[3] = {'f','o','o'}; - std::string_view carr(foo, std::size(foo)); - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{\texttt{std::span} - Concept \cpprefLink{https://en.cppreference.com/w/cpp/container/span}} - \begin{block}{Non owning view of a contiguous sequence of items} - \begin{itemize} - \item Doesn't allocate memory - \item Allows to modify items, but not the container itself - \begin{itemize} - \item no reallocation, push or pop - \end{itemize} - \item Provides container like interface - \begin{itemize} - \item iterators, \cppinline{size}, \cppinline{front}/\cppinline{back}, \cppinline{subspan}, ... - \end{itemize} - \item Standard contiguous containers convert to it automatically - \begin{itemize} - \item \cppinline{std::vector}, \cppinline{std::array}, C arrays, ... - \item not \cppinline{std::list} or \cppinline{std::deque} (no contiguous storage) - \item \cppinline{span} should thus be preferred as function argument - \end{itemize} - \item Simply a pair (pointer, size), so cheap to copy - \begin{itemize} - \item and thus to be passed by value - \end{itemize} - \item \cppinline{span} can also have a \texttt{static extent} - \begin{itemize} - \item meaning the size is determined at compile time - \item and thus only a pointer is stored by \cppinline{span} - \end{itemize} - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{\texttt{std::span} - Usage} - \begin{exampleblockGB}{Some example}{https://godbolt.org/z/nP3jr388z}{\texttt{span}} - \scriptsize - \begin{cppcode*}{} - void print(std::span c) { - for (auto a : c) { std::cout << a << " "; } - std::cout << "\n"; - } - void times2(std::span c) { - for(auto &e : c) { e *= 2; } - } - int a[]{23, 45, 67, 89}; - print(a); // 23 45 67 89 - - std::vector v{1, 2, 3, 4, 5}; - std::span sv = v; - print(sv.subspan(2, 2)); // 3 4 - - std::array a2{-14, 55, 24}; - times2(a2); - print(a2); // -28 110 48 - - std::span sa2 = a2; - std::cout << sizeof(sv) << " " << sizeof(sa2) << "\n"; // 16 8 - std::span s2a2 = a; // compilation failure, invalid conversion - \end{cppcode*} - \end{exampleblockGB} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{std::optional \cpprefLink{https://en.cppreference.com/w/cpp/utility/optional}} - \begin{block}{Manages an optionally contained value} - \begin{itemize} - \item Contextually converts to bool, telling if it contains something - \item Has value semantics (Copy, Move, Compare, stack alloc.) - \item Useful for the return value of a function that may fail - \item Useful in place of pointers where value semantics are intuitive - \end{itemize} - \end{block} - \begin{exampleblock}{} - \small - \begin{cppcode*}{} - std::optional parse_phone(std::string_view in) { - if (is_valid_phone(in)) - return in; // equiv. to optional{in}; - return {}; // or: return std::nullopt; (empty opt.) - } - auto v = parse_phone(...); - if (v) { // or: v.has_value() - process_phone(v.value()); // or: *v (unchecked) - v->call(); // calls Phone::call() (unchecked) - } - v.reset(); assert(!v.has_value()); // or: v = {}; - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{std::optional} - \begin{exampleblock}{Code example} - \small - \begin{cppcode*}{} - // address may be given for a person or not - void processPerson(std::string_view name, - std::optional
address); - Address addr = wonderland(); - processPerson("Alice", std::move(addr)); - - // Every person has a name, but not always an address - struct Person { - std::string name; - std::optional
address; - }; - std::vector ps = ...; - std::sort(ps.begin(), ps.end(), - [](const Person& a, const Person& b) { - return a.address < b.address; - }); // sorts by address, persons w/o address at front - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{std::optional} - \begin{exerciseWithShortcut}{Handling optional results}{std::optional} - \begin{itemize} - \item go to \texttt{exercises/optional/optional.cpp} - \item modify \texttt{mysqrt} so to return an \texttt{std::optional} - \item guess the consequences on \texttt{square} - \end{itemize} - \end{exerciseWithShortcut} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[23]{std::expected \cpprefLink{https://en.cppreference.com/w/cpp/utility/expected}} - \begin{block}{Manages either of 2 values (expected or not)} - \begin{itemize} - \item templated by the 2 value types - \item Useful for the return value of a function that may fail - \begin{itemize} - \item and would then return another type (error type) - \end{itemize} - \end{itemize} - \end{block} - \begin{exampleblockGB}{Practically}{https://godbolt.org/z/9rjn1hzeW}{\texttt{expected}} - \small - \begin{cppcode*}{} - enum class Error {...}; - std::expected parse(std::string_view in) { - if (is_valid(in)) return convert_to_int(in); - return std::unexpected(Error::...); - } - auto v = parse(...); - if (v) { // or v.has_value() - std::cout << *v; // (unchecked) - foo(v.value()); // may throw bad_expected_access - } else - log(v.error()); - \end{cppcode*} - \end{exampleblockGB} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{std::variant \cpprefLink{https://en.cppreference.com/w/cpp/utility/variant}} - \begin{block}{A type-safe union} - \begin{itemize} - \item Allows the variable to hold any of the given types - \item \cppinline{std::get} reads the value of the variant - \item and throws \cppinline{std::bad_variant_access} for bad accesses - \item Currently held alternative can be probed - \end{itemize} - \end{block} - \begin{exampleblock}{Code example} - \small - \begin{cppcode*}{} - std::variant opt{100}; // holding int - int ival = std::get(opt); // or std::get<0>(opt) - try { - float val = std::get(opt) // will throw - } catch (std::bad_variant_access const& ex) {...} - if (std::holds_alternative(opt)) - std::cout << std::get(opt); - if (const float* v = std::get_if(&opt)) { ... } - const int current_alternative = opt.index(); // == 0 - \end{cppcode*} - \end{exampleblock} - -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{std::variant and the visitor pattern} - \begin{block}{\texttt{std::visit} \cpprefLink{https://en.cppreference.com/w/cpp/utility/variant/visit}} - \begin{itemize} - \item Applies a ``visitor'' to a given variant - \begin{itemize} - \item A visitor is a callable able to handle all different types - \item Must return \cppinline{void} or the same type for all overloads - \end{itemize} - \end{itemize} - \end{block} - \begin{exampleblockGB}{Practically}{https://godbolt.org/z/bxzEsM3de}{\texttt{variant visitor}} - \small - \begin{cppcode*}{} - struct Visitor { - auto operator()(int i) {return "i:"+std::to_string(i);} - auto operator()(float f) {return "f:"+std::to_string(f);} - auto operator()(const std::string& s) { return "s:"+s;} - template - auto operator()(const T& t) { return std::string{"?"}; } - }; - void print(std::variant v) { - std::cout << std::visit(Visitor{}, v) << '\n'; - } - print(100); print(42.0f); print("example"); print('A'); - \end{cppcode*} - \end{exampleblockGB} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{std::variant and the lambda visitor pattern} - \begin{block}{Idea} - \begin{itemize} - \item use inheritance to group a set of lambdas - \end{itemize} - \end{block} - \begin{exampleblockGB}{Practically}{https://godbolt.org/z/WcdnT1hra}{\texttt{variant $\lambda$ visitor}} - \small - \begin{cppcode*}{} - template // covered in expert part - struct Overload : Ts ... { using Ts::operator()...; }; - template - Overload(Ts...) -> Overload; // obsolete in C++20 - int main(){ - std::variant v{ ... }; - auto overloadSet = Overload { - [](int i) { std::cout << "i32:" << i;}, - [](std::string s) { std::cout << s;}, - [](auto a) { std::cout << "other"; }, - }; - std::visit(overloadSet, v); - } - \end{cppcode*} - \end{exampleblockGB} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{std::variant exercise} - \begin{exerciseWithShortcut}{An alternative to oo polymorphism}{std::variant} - \begin{itemize} - \item go to \texttt{exercises/variant/variant.cpp} - \item replace inheritance from a common base class with an \cppinline{std::variant} on the three kinds of particle. - \item two solutions given : with \cppinline{std::get_if} and with \cppinline{std::visit}. - \end{itemize} - \end{exerciseWithShortcut} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{std::any \cpprefLink{https://en.cppreference.com/w/cpp/utility/any}} - \begin{block}{a type-safe container for single values of any type} - \begin{itemize} - \item Allows a variable to hold any type (say bye to \cppinline{void*}) - \item \cppinline{std::any_cast} reads the internal value - \item and throws \cppinline{std::bad_any_cast} for bad accesses - \item \cppinline{std::any_cast} only matches types 1:1, ignoring inheritance - \end{itemize} - \end{block} - \begin{exampleblock}{Code example} - \small - \begin{cppcode*}{} - std::any val{100}; // holding int - val = std::string("hello"); // holding string - std::string s = std::any_cast(val); - try { - int val = std::any_cast(val); // will throw - } catch (std::bad_any_cast const& ex) {...} - if (val.type() == typeid(int)) // requires RTTI - std::cout << std::any_cast(val); - val.reset(); assert(!val.has_value()); - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{non-member begin and end} - \begin{alertblock}{The problem in \cpp98} - STL containers and arrays have different syntax for loop - \vspace{-1mm} - \begin{cppcode*}{} - std::vector v; - int a[] = {1,2,3}; - for(auto it = v.begin(); it != v.end(); it++) {...} - for(int i = 0; i < 3; i++) {...} - \end{cppcode*} - \end{alertblock} - \pause - \begin{block}{A new syntax} - \begin{cppcode*}{firstnumber=5} - for(auto it = begin(v); it != end(v); it++) {...} - for(auto i = begin(a); i != end(a); i++) {...} - \end{cppcode*} - \end{block} - \pause - \begin{exampleblock}{Allowing the best syntax} - \begin{cppcode*}{firstnumber=7} - for(auto & element : v) {...} - for(auto & element : a) {...} - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{\texttt{std::tuple} \cpprefLink{https://en.cppreference.com/w/cpp/utility/tuple}} - \begin{exampleblock}{} - \begin{cppcode*}{} - #include - - std::tuple t{42, 3.14f, false}; - auto t = std::make_tuple(42, 3.14f, false); - std::tuple t{42, 3.14f, false}; // C++17 CTAD - - float& f = std::get<1>(t); // get 1. member - bool& b = std::get(t); // get bool member - - using Tup = decltype(t); - constexpr auto s = std::tuple_size_v; // 3 - using E2Type = std::tuple_element<2, Tup>; // bool - - auto t2 = std::tuple_cat(t, std::tuple{'A'}, t); - // - bool& b2 = std::get(t2); // error - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{\texttt{std::tuple}} - \begin{exampleblock}{} - \begin{cppcode*}{} - void f(std::tuple tuple) { - int a; float b; bool c; - std::tie(a, b, c) // tuple - = tuple; - // Use structured bindings in C++17 - } - - int& i = ...; - std::tuple{i}; // tuple - std::make_tuple(i); // tuple - std::make_tuple(std::ref(i)); // tuple - std::tuple{std::ref(i)}; - // C++17 CTAD, tuple> - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{Structured Binding Declarations} - \begin{block}{} - \begin{itemize} - \item Helps with \cppinline{std::tuple}, tuple-like, array or aggregate types - \item Automatically creates variables and ties them - \item CV qualifiers and references allowed - \end{itemize} - \end{block} - \begin{exampleblockGB}{Practically}{https://godbolt.org/z/PfWzxjP7W}{\texttt{Structured binding}} - \small - \begin{cppcode*}{} - std::tuple tuple = ...; - auto [ a, b, c ] = tuple; - - struct S { int i; float f; bool b; } s = ...; - auto&& [ a, b, c ] = std::move(s); - - int arr[] = {1, 3, 4}; - const auto& [ a, b, c ] = arr; - - std::unordered_map map = ...; - for (const auto& [key, value] : map) { ... } - \end{cppcode*} - \end{exampleblockGB} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{Structured Binding Declarations} - \begin{block}{``Tuple-like binding prototcol''} - \begin{itemize} - \item For non-aggregates, you can opt-in to structured bindings - \item The compiler requires these hooks: - \begin{itemize} - \item Specialize \cppinline{std::tuple_size} - \item Specialize \cppinline{std::tuple_element} - \item Provide either \cppinline{T::get()} or \cppinline{get(T)} - \end{itemize} - \end{itemize} - \end{block} - \begin{exampleblock}{} - \small - \begin{cppcode*}{} - class C { ... }; // complex, cannot change - template <> - struct std::tuple_size { - static constexpr std::size_t value = ...; - }; - template - struct std::tuple_element { using type = ...; }; - template - auto& get(C& c) { ... }; // -> std::tuple_element& - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitle{\cpp date and time utilities \hfill \cpp11 / \cpp20} - \cppinline{std::chrono library} present in \cppinline{} header - \begin{block}{Clocks} - \begin{itemize} - \item consists of a starting point (or epoch) and a tick rate - \begin{itemize} - \item E.g. January 1, 1970 and every second - \end{itemize} - \item C++ defines several clock type - \begin{itemize} - \item \href{https://en.cppreference.com/w/cpp/chrono/system_clock}{\color{blue!50!white} \cppinline{system_clock}} system time, aka wall clock time, or C time - \item \href{https://en.cppreference.com/w/cpp/chrono/steady_clock}{\color{blue!50!white} \cppinline{steady_clock}} monotonic but unrelated to wall clock time - \item \href{https://en.cppreference.com/w/cpp/chrono/high_resolution_clock}{\color{blue!50!white} \cppinline{high_resolution_clock}} clock with the smallest tick period - \end{itemize} - \end{itemize} - \end{block} - \begin{block}{\href{https://en.cppreference.com/w/cpp/chrono/time_point}{\color{blue!50!white} \cppinline{time_point}} and \href{https://en.cppreference.com/w/cpp/chrono/duration}{\color{blue!50!white} \cppinline{duration}}} - \begin{itemize} - \item provide easy manipulation of times and duration - \item clock dependent - \item \href{https://en.cppreference.com/w/cpp/chrono/duration/duration_cast}{\color{blue!50!white} \cppinline{duration_cast}} allows conversions between duration types - \begin{itemize} - \item available helper types : nanoseconds, microseconds, milliseconds, seconds, minutes, hours, ... - \end{itemize} - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Practical usage / timing some \cpp code} - \begin{exampleblockGB}{How to measure the time spent in some code}{https://godbolt.org/z/PzKWer5eb}{\texttt{timing}} - \small - \begin{cppcode*}{} - #include - - std::chrono::high_resolution_clock clock; - auto start = clock::now(); - ... // code to be timed - std::chrono::duration ticks = clock.now() - start; - - auto millis = std::chrono::duration_cast - (ticks); - std::cout << "it took " << ticks.count() << " ticks" - << ", that is " << millis.count() << " ms\n"; - \end{cppcode*} - \end{exampleblockGB} - \pause - \begin{alertblock}{Warning} - \begin{itemize} - \item this does not measure the amount of CPU used ! - \item neither the time spent on a CPU (think suspended threads) - \end{itemize} - \end{alertblock} -\end{frame} diff --git a/talk/morelanguage/move.tex b/talk/morelanguage/move.tex deleted file mode 100644 index 038c7baa..00000000 --- a/talk/morelanguage/move.tex +++ /dev/null @@ -1,284 +0,0 @@ -\subsection[mv]{Move semantics} - -\begin{frame}[fragile] - \frametitlecpp[11]{Move semantics: the problem} - \begin{exampleblock}{Inefficient code} - \begin{cppcode*}{} - void swap(std::vector &a, - std::vector &b) { - std::vector c = a; - a = b; - b = c; - } - std::vector v(10000), w(10000); - ... - swap(v, w); - \end{cppcode*} - \end{exampleblock} - \pause - \begin{alertblock}{What happens during swap} - \begin{itemize} - \item one allocation and one release for 10k \cppinline{int}s - \item a copy of 30k \cppinline{int}s - \end{itemize} - \end{alertblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Move semantics: the problem} - \begin{exampleblock}{Vector's built-in efficient swap} - \begin{cppcode*}{} - std::vector v(10'000), w(10'000); - ... - v.swap(w); - \end{cppcode*} - \end{exampleblock} - \pause - \begin{block}{What happens during swap} - \begin{itemize} - \item 3 swaps of \cppinline{int*} (9 copies) - \item only some pointers to the underlying storage are swapped - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Move semantics: the problem} - \begin{exampleblock}{Another potentially inefficient code} - \begin{overprint} - \onslide<1-2> - \begin{cppcode*}{} - T consumeVector(std::vector input) { - // ... change elements, compute result - return result; - } - - std::vector values{...}; - consumeVector(values); // being copied now - \end{cppcode*} - \onslide<3-4> - \begin{cppcode*}{} - T consumeVector(std::vector const & input) { - std::vector tmp{input}; - // ... change elements, compute result - return result; - } - std::vector values{...}; - consumeVector(values); // maybe copied internally? - \end{cppcode*} - \onslide<5-> - \begin{cppcode*}{} - T consumeVector(std::vector & input) { - // ... change elements, compute result - return result; - } - - std::vector values{...}; - consumeVector(values); // maybe modified? - somethingElse(values); // safe to use values now??? - \end{cppcode*} - \end{overprint} - \end{exampleblock} - \begin{overprint} - \onslide<2> - \begin{alertblock}{Pass by copy} - \begin{itemize} - \item One unnecessary (large?) allocation and release - \item Unnecessary copy of the \cppinline{int}s - \end{itemize} - \end{alertblock} - \onslide<4> - \begin{alertblock}{Use references to avoid copies?} - \begin{itemize} - \item Working with pass by reference only moves allocation and copy to a different place - \end{itemize} - \end{alertblock} - \onslide<5> - \begin{alertblock}{So non-const references?} - \begin{itemize} - \item Non-\cppinline{const} references could work, but does the outside know that we're changing the vector? - \item Could lead to bugs - \end{itemize} - \end{alertblock} - \onslide<6> - \begin{block}{The ideal situation} - Have a way to express that we move the vector's content - \end{block} - \end{overprint} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Move semantics} - \begin{block}{The idea} - \begin{itemize} - \item a new type of reference: rvalue reference - \begin{itemize} - \item used for move semantic - \item denoted by \cppinline{&&} - \end{itemize} - \item 2 new special member functions in every class: - \begin{description} - \item[a move constructor] similar to copy constructor - \item[a move assignment operator] similar to assignment operator (now called copy assignment operator) - \end{description} - \end{itemize} - \end{block} - \pause - \begin{exampleblock}{Practically} - \begin{cppcode*}{} - T(T const & other); // copy construction - T( T&& other); // move construction - T& operator=(T const & other); // copy assignment - T& operator=( T&& other); // move assignment - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Move semantics} - \begin{block}{A few points} - \begin{itemize} - \item move constructor and assignment operator are allowed to leave the source object "empty" - \begin{itemize} - \item so do not use the source object afterward - \item leave the source in a valid state (for its destructor) - \end{itemize} - \item if no move semantic is implemented, copies will be performed - \item the language and STL understand move semantic - \item the compiler moves whenever possible - \begin{itemize} - \item e.g.\ when passing temporaries or returning from a function - \end{itemize} - \end{itemize} - \end{block} - \pause - \begin{exampleblock}{Practically} - \begin{cppcode*}{} - T f() { T r; return r; } // move r out of f - T v = f(); // move returned (temporary) T into v - void g(T a, T b, T c); - g(f(), T{}, v); // move, move, copy - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Move semantics} - \begin{block}{In some cases, you want to force a move} - \begin{cppcode*}{} - void swap(T &a, T &b) { - T c = a; // copy construct - a = b; // copy assign - b = c; // copy assign - } - \end{cppcode*} - \end{block} - \pause - \begin{block}{Explicitly request moving} - \begin{itemize} - \item using the \cppinline{std::move} function - \item which is basically a cast to an rvalue reference - \end{itemize} - \begin{cppcode*}{firstnumber=6} - void swap(T &a, T &b) { - T c = std::move(a); // move construct - a = std::move(b); // move assign - b = static_cast(c); // move assign (don't) - } - \end{cppcode*} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Move semantics: recommended implementation} - \begin{block}{Use copy and swap idiom} - \begin{itemize} - \item implement an efficient swap function for your class - \begin{itemize} - \item preferably hidden friend and symmetric - \end{itemize} - \item move constructor - \begin{itemize} - \item consider delegating to default constructor - \item swap \cppinline{*this} with parameter (source) - \end{itemize} - \item move assignment as \cppinline{operator=(T source)} - \begin{itemize} - \item parameter passed by value; caller can move or copy into it - \item swap parameter with \cppinline{*this} - \item end of scope: parameter destroys former content of \cppinline{*this} - \end{itemize} - \item alternative: move assignment as \cppinline{operator=(T&& source)} - \begin{itemize} - \item swap parameter with \cppinline{*this} - \item 1 swap less, separate copy assignment operator needed - \item former content of \cppinline{*this} destroyed with caller argument - \end{itemize} - \item swap, move constructor/assignment must be \cppinline{noexcept} - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile,t] - \frametitlecpp[11]{Move semantics: recommended implementation} - \begin{exampleblock}{Practically} - \small - \begin{cppcode*}{} - class Movable { - Movable(); - Movable(const Movable &other); - Movable(Movable &&other) noexcept : - Movable() { // constructor delegation - swap(*this, other); - } - Movable& operator=(Movable other) noexcept { // by value - swap(*this, other); - return *this; - } - friend void swap(Movable &a, Movable &b) noexcept {...} - }; - Movable a, b; - a = b; // operator= copies b into "other" - a = std::move(b); // operator= moves b into "other" - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile,t] - \frametitlecpp[11]{Move semantics: alternative implementation} - \begin{exampleblock}{Practically} - \small - \begin{cppcode*}{} - class Movable { - Movable(); - Movable(const Movable &other); - Movable(Movable &&other) noexcept : - Movable() { // constructor delegation - swap(*this, other); - } - Movable& operator=(const Movable& other); - Movable& operator=(Movable&& other) noexcept { - swap(*this, other); - return *this; - } - friend void swap(Movable &a, Movable &b) noexcept { ... } - }; - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Move Semantic} - \begin{exercise}{Move semantics} - \begin{itemize} - \item go to \texttt{exercises/move} - \item look at the code and run it with callgrind - \item understand how inefficient it is - \item implement move semantic the easy way in NVector - \item run with callgrind and see no improvement - \item understand why and fix test.cpp - \item see efficiency improvements - \end{itemize} - \end{exercise} - prerequisite: be able to use simple templated code -\end{frame} diff --git a/talk/morelanguage/raii.tex b/talk/morelanguage/raii.tex deleted file mode 100644 index b895fe07..00000000 --- a/talk/morelanguage/raii.tex +++ /dev/null @@ -1,469 +0,0 @@ -\subsection[RAII]{RAII and smart pointers} - -\begin{frame}[fragile] - \frametitlecpp[98]{Pointers: why are they error prone?} - \begin{exampleblock}{They need initialization - \hfill \onslide<2->{\textcolor{orange}{\bf Seg Fault}}} - \begin{cppcode*}{xleftmargin=20pt} - char *s; - try { - foo(); // may throw - s = new char[100]; - read_line(s); - } catch (...) { ... } - process_line(s); - \end{cppcode*} - \end{exampleblock} - \pause - \pause - \vspace{-2cm} - \begin{exampleblock}{They need to be released - \hfill \onslide<4->{\textcolor{orange}{\bf Memory leak}}} - \begin{cppcode*}{xleftmargin=20pt} - char *s = new char[100]; - read_line(s); - if (s[0] == '#') return; - process_line(s); - delete[] s; - \end{cppcode*} - \end{exampleblock} - \pause - \pause - \vspace{-2cm} - \begin{exampleblock}{They need clear ownership - \hfill \onslide<6->{\textcolor{orange}{\bf Who should release ?}}} - \begin{cppcode*}{xleftmargin=20pt} - char *s = new char[100]; - read_line(s); - vec.push_back(s); - set.add(s); - std::thread t1{func1, vec}; - std::thread t2{func2, set}; - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{This problem exists for any resource} - \begin{exampleblock}{For example with a file} - \begin{cppcode*}{} - std::FILE *handle = std::fopen(path, "w+"); - if (nullptr == handle) { throw ... } - std::vector v(100, 42); - write(handle, v); - if (std::fputs("end", handle) == EOF) { - return; - } - std::fclose(handle); - \end{cppcode*} - \end{exampleblock} - \begin{block}{} - Which problems do you spot in the above snippet? - \end{block} -\end{frame} - -\begin{frame} - \frametitlecpp[98]{Resource Acquisition Is Initialization (RAII)} - \begin{block}{Practically} - Use variable construction/destruction and scope semantics: - \begin{itemize} - \item wrap the resource inside a class - \item acquire resource in constructor - \item release resource in destructor - \item create an instance on the stack - \begin{itemize} - \item automatically destructed when leaving the scope - \item including in case of exception - \end{itemize} - \item use move semantics to pass the resource around - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{RAII in practice} - \begin{exampleblock}{An RAII File class} - \small - \begin{cppcode*}{} - class File { - public: - // constructor: acquire resource - File(const char* filename) - : m_handle(std::fopen(filename, "w+")) { - // abort constructor on error - if (m_handle == nullptr) { throw ... } - } - // destructor: release resource - ~File() { std::fclose(m_handle); } - void write (const char* str) { - ... - } - private: - std::FILE* m_handle; // wrapped resource - }; - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{RAII usage} - \begin{exampleblock}{Usage of File class} - \begin{cppcode*}{} - void log_function() { - // file opening, aka resource acquisition - File logfile("logfile.txt"); - - // file usage - logfile.write("hello logfile!"); // may throw - - // file is automatically closed by the call to - // its destructor, even in case of exception! - } - \end{cppcode*} - \end{exampleblock} - \begin{goodpractice}[Use \texttt{std::fstream}]{Use \texttt{std::fstream} for file handling} - The standard library provides \cppinline{std::fstream} to handle files, use it! - \end{goodpractice} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{\texttt{std::unique\_ptr}} - \begin{block}{A RAII pointer} - \begin{itemize} - \item wraps and behaves like a regular pointer - \item get underlying pointer using \cppinline{get()} - \item when destroyed, deletes the object pointed to - \item has move-only semantic - \begin{itemize} - \item the pointer has unique ownership - \item copying will result in a compile error - \end{itemize} - \end{itemize} - \end{block} - \pause - \begin{exampleblock}{} - \begin{cppcode*}{} - #include - void f(std::unique_ptr ptr) { - ptr->bar(); - } // deallocation when f exits - - std::unique_ptr p{ new Foo{} }; // allocation - f(std::move(p)); // transfer ownership - assert(p.get() == nullptr); - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Quiz} - \begin{exampleblock}{What do you expect?} - \begin{cppcode*}{} - void f(std::unique_ptr ptr); - std::unique_ptr uptr(new Foo{}); - f(uptr); // transfer of ownership - \end{cppcode*} - \end{exampleblock} - \pause - \begin{alertblock}{Compilation Error - \godboltLink{https://godbolt.org/z/jfqKjocnh}{\texttt{unique\_ptr} copy}} - \begin{minted}{text} -test.cpp:15:5: error: call to deleted constructor -of 'std::unique_ptr' - f(uptr); - ^~~~ -/usr/include/c++/4.9/bits/unique_ptr.h:356:7: note: - 'unique_ptr' has been explicitly marked deleted here - unique_ptr(const unique_ptr&) = delete; - ^ - \end{minted} - \end{alertblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[14]{\texttt{std::make\_unique}} - \begin{block}{\texttt{std::make\_unique}} - \begin{itemize} - \item allocates and constructs an object with arguments\\ - and wraps it with \cppinline{std::unique_ptr} in one step - \item no \cppinline{new} or \cppinline{delete} calls anymore! - \item no memory leaks if used consistently - \end{itemize} - \end{block} - \pause - \begin{exampleblock}{\texttt{std::make\_unique} usage} - \begin{cppcode*}{} - { - // calls new File("logfile.txt") internally - auto f = std::make_unique("logfile.txt"); - f->write("hello logfile!"); - } // deallocation at end of scope - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{advanced} - -\begin{frame}[fragile] - \frametitlecpp[11]{Arrays and \texttt{unique\_ptr}} - \begin{block}{Dynamic arrays} - \begin{itemize} - \item \cppinline{unique_ptr} can wrap arrays - \item Use \cppinline{T[]} as template parameter - \item This will enable the subscript operator - \item The default constructor is called for each element - \item If size known at compile time, prefer \cppinline{std::array} - \item If size might change, prefer \cppinline{std::vector} - \end{itemize} - \end{block} - \begin{exampleblock}{} - \begin{cppcode*}{} - auto b = std::make_unique(10); - b[3] = ...; - b[4].someFunction(); - - // deallocations at end of scope - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\end{advanced} - -\begin{frame}[fragile] - \frametitlecpp[11]{RAII or raw pointers} - \begin{block}{When to use what?} - \begin{itemize} - \item Always use RAII for resources, in particular allocations - \begin{itemize} - \item You thus never have to release / deallocate yourself - \end{itemize} - \item Use raw pointers as non-owning, re-bindable observers - \item Remember that \cppinline{std::unique_ptr} is move only - \end{itemize} - \end{block} - \pause - \begin{exampleblock}{A question of ownership} - \small - \begin{cppcode*}{} - std::unique_ptr produce(); - void observe(const T&); - void modifyRef(T&); - void modifyPtr(T*); - void consume(std::unique_ptr); - std::unique_ptr pt{produce()}; // Receive ownership - observe(*pt); // Keep ownership - modifyRef(*pt); // Keep ownership - modifyPtr(pt.get()); // Keep ownership - consume(std::move(pt)); // Transfer ownership - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{\texttt{std::unique\_ptr} usage summary} - \begin{goodpractice}{\texttt{std::unique\_ptr}} - \begin{itemize} - \item \cppinline{std::unique_ptr} is about lifetime management - \begin{itemize} - \item use it to tie the lifetime of an object to a unique RAII owner - \item use raw pointers/references to refer to another object\\ - without owning it or managing its lifetime - \end{itemize} - \item use \cppinline{std::make_unique} for creation - \item strive for having no \cppinline{new}/\cppinline{delete} in your code - \item for dynamic arrays, \cppinline{std::vector} may be more useful - \end{itemize} - \end{goodpractice} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{\texttt{std::shared\_ptr}} - \begin{block}{\mintinline{cpp}{std::shared_ptr} : a reference-counting pointer} - \begin{itemize} - \item wraps a regular pointer similar to \cppinline{unique_ptr} - \item has move and copy semantic - \item uses reference counting internally - \begin{itemize} - \item "Would the last person out, please turn off the lights?" - \end{itemize} - \item reference counting is thread-safe, therefore a bit costly - \end{itemize} - \end{block} - \begin{block}{\texttt{std::make\_shared} : creates a \texttt{std::shared\_ptr}} - \begin{cppcode*}{} - { - auto sp = std::make_shared(); // #ref = 1 - vector.push_back(sp); // #ref = 2 - set.insert(sp); // #ref = 3 - } // #ref 2 - \end{cppcode*} - \end{block} -\end{frame} - -\begin{advanced} - -\begin{frame}[fragile] - \frametitlecpp[11]{\texttt{weak\_ptr}} - \begin{block}{\texttt{weak\_ptr}: a non-owning observer} - \small - \begin{itemize} - \item Sometimes want to observe resources without keeping them alive - \begin{itemize} - \item \cppinline{shared_ptr}? Resource stays alive - \item Raw pointer? Risk of dangling pointer - \end{itemize} - \item The solution is to construct a \cppinline{weak_ptr} from a shared pointer - \item To access the resource, convert the weak into a \cppinline{shared_ptr} - \end{itemize} - \end{block} - \begin{exampleblock}{} - \small - \begin{cppcode*}{} - std::shared_ptr getSharedCache(); - std::weak_ptr weakPtr{ getSharedCache() }; - // ... shared cache may be invalidated here - if (std::shared_ptr cache = weakPtr.lock()) { - // Cache is alive, we actively extend its lifetime - return cache->findItem(...); - } else { - // Cache is nullptr, we need to do something - weakPtr = recomputeCache(...); - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\end{advanced} - -\begin{frame}[fragile] - \frametitlecpp[11]{Quiz: \texttt{std::shared\_ptr} in use} - \begin{exampleblockGB}{What is the output of this code?}{https://godbolt.org/z/vM35Y6qEW}{\texttt{shared\_ptr} quiz} - \small - \begin{cppcode*}{} - auto shared = std::make_shared(100); - auto print = [shared](){ - std::cout << "Use: " << shared.use_count() << " " - << "value: " << *shared << "\n"; - }; - print(); - { - auto ptr{ shared }; - (*ptr)++; - print(); - } - print(); - \end{cppcode*} - \end{exampleblockGB} - \pause - \begin{block}{} - \small - \begin{minted}{bash} - Use: 2 value: 100 - Use: 3 value: 101 - Use: 2 value: 101 - \end{minted} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Quiz: \texttt{std::shared\_ptr} in use} - \begin{exampleblock}{What is the output of this code?} - \small - % escapeinside seems to break gobble, so need to un-indent manually - \begin{cppcode*}{escapeinside=@@} -auto shared = std::make_shared(100); -auto print = [@\textcolor{red}{&}@shared](){ - std::cout << "Use: " << shared.use_count() << " " - << "value: " << *shared << "\n"; -}; -print(); -{ - auto ptr{ shared }; - (*ptr)++; - print(); -} -print(); - \end{cppcode*} - \end{exampleblock} - \begin{block}{} - \small - \begin{minted}{bash} - Use: 1 value: 100 - Use: 2 value: 101 - Use: 1 value: 101 - \end{minted} - \end{block} -\end{frame} - -\begin{advanced} - -\begin{frame}[fragile] - \frametitlecpp[11]{Quiz: \texttt{shared\_ptr} and \texttt{weak\_ptr} in use} - \begin{exampleblockGB}{What is the output of this code?}{https://godbolt.org}{\texttt{shared/weak\_ptr}} - \small - \begin{cppcode*}{} - auto shared = std::make_shared(100); - std::weak_ptr weak{ shared }; - print(); // with print as before - - auto ptr = weak.lock(); - (*ptr)++; print(); - - ptr = nullptr; print(); - - function(weak); print(); - \end{cppcode*} - \end{exampleblockGB} - \pause - \begin{block}{} - \small - \begin{minted}{bash} - Use: 1 value: 100 - Use: 2 value: 101 - Use: 1 value: 101 - Use: 1 (or more) value: ??? - \end{minted} - \end{block} -\end{frame} - -\end{advanced} - -\begin{frame}[fragile] - \frametitlecpp[11]{Rule of zero} - \begin{goodpractice}[Single responsibility principle]{Single responsibility principle (SRP)} - Every class should have only one responsibility. - \end{goodpractice} - \begin{goodpractice}{Rule of zero} - \begin{itemize} - \item If your class has any special member functions (except ctor.) - \begin{itemize} - \item Your class probably deals with a resource, use RAII - \item Your class should only deal with this resource (SRP) - \item Apply rule of 3/5: write/default/delete all special members - \end{itemize} - \item Otherwise: do not declare any special members (rule of zero) - \begin{itemize} - \item A constructor is fine, if you need some setup - \item If your class holds a resource as data member:\\ - wrap it in a smart pointer, container, or any other RAII class - \end{itemize} - \end{itemize} - \end{goodpractice} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{smart pointers} - \begin{exercise}{Smart pointers} - \begin{itemize} - \item go to \texttt{exercises/smartPointers} - \item compile and run the program. It doesn't generate any output. - \item Run with valgrind if possible to check for leaks - { \scriptsize - \begin{minted}{shell-session} - $ valgrind --leak-check=full --track-origins=yes ./smartPointers - \end{minted} - } - \item In the \emph{essentials course}, go through {\ttfamily problem1()} and {\ttfamily problem2()} and fix the leaks using smart pointers. - \item In the \emph{advanced course}, go through {\ttfamily problem1()} to {\ttfamily problem4()} and fix the leaks using smart pointers. - \item {\ttfamily problem4()} is the most difficult. Skip if not enough time. - \end{itemize} - \end{exercise} -\end{frame} diff --git a/talk/morelanguage/random.tex b/talk/morelanguage/random.tex deleted file mode 100644 index 71fd7787..00000000 --- a/talk/morelanguage/random.tex +++ /dev/null @@ -1,122 +0,0 @@ -%\subsection[rnd]{Random} - -\begin{frame}[fragile] - \frametitlecpp[11]{Pseudo-random number generators (PRNG)} - \begin{block}{Concept} - \begin{itemize} - \item For generating pseudo-random numbers the STL offers: - \begin{itemize} - \item engines and engine adaptors to generate pseudo random bits - \item distributions to shape these into numbers - \item access to (potential) hardware entropy - \end{itemize} - \item All found in header \cppinline{} - \end{itemize} - \end{block} - \begin{exampleblock}{Example} - \begin{cppcode} - #include - std::random_device rd; - std::default_random_engine engine{rd()}; - std::normal_distribution dist(5.0, 1.5); // µ, σ - double r = dist(engine); - \end{cppcode} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Engines} - \begin{block}{Engines} - \begin{itemize} - \item Generate random bits (as integers), depending on algorithm - \item Can be seeded via constructor or \cppinline{seed()} - \item Algorithms: - {\footnotesize \cppinline{linear_congruential_engine}, \cppinline{mersenne_twister_engine}, \cppinline{subtract_with_carry_engine}} - \item Adaptors: - {\footnotesize \cppinline{discard_block_engine}, \cppinline{independent_bits_engine}, \cppinline{shuffle_order_engine}} - \item Aliases: - {\footnotesize \cppinline{minstd_rand0}, \cppinline{minstd_rand}, \cppinline{mt19937}, \cppinline{mt19937_64}, \cppinline{ranlux24}, \cppinline{ranlux48}, \cppinline{knuth_b}} (use these) - \item \cppinline{std::default_random_engine} aliases one of the above - \end{itemize} - \end{block} - \begin{exampleblock}{Engine creation with seed} - \begin{cppcode} - std::default_random_engine engine{42}; // or empty - auto i = engine(); // operator(): random integer - \end{cppcode} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Determinism and random device} - \begin{block}{Engines / PRNGs} - \begin{itemize} - \item Are \emph{deterministic} - \item Will produce the same number sequence for the same seed - \item May be useful for reproducibility - \end{itemize} - \end{block} - \begin{block}{\texttt{std::random\_device}} - \begin{itemize} - \item Provides \emph{non-deterministic} random numbers - \item Uses hardware provided entropy, if available - \item May become slow when called too often,\\e.g.\ when hardware entropy pool is exhausted - \item Use only to seed engine, if \emph{non-deterministic} numbers needed - \end{itemize} - \end{block} - \begin{exampleblock}{Non-deterministic engine seeding} - \begin{cppcode} - std::random_device rd; - std::default_random_engine engine{rd()}; - \end{cppcode} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Distributions} - \begin{block}{Distributions} - \begin{itemize} - \item Take random bits from engines and shape them into numbers - \item Standard library provides a lot of them - \begin{itemize} - \item Uniform, bernoulli, poisson, normal and sampling distributions - \item See \href{https://en.cppreference.com/w/cpp/numeric/random}{cppreference} for the full list - \end{itemize} - \end{itemize} - \end{block} - \begin{exampleblock}{Distributions sharing a non-deterministic engine} - \begin{cppcode*}{} - std::random_device rd; - std::default_random_engine engine{rd()}; - std::uniform_int_distribution dist(2,7);//min,max - const int size = dist(engine); // gen. random number - std::vector v(size); - std::normal_distribution norm(5.0, 1.5); //µ,σ - std::generate(begin(v), end(v), - [&]{ return norm(engine); }); - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{C random library} - \begin{block}{C random library} - \begin{itemize} - \item The C library (\cppinline{}) offers a primitive PRNG: - \item \cppinline{rand()} returns random int between 0 and \cppinline{RAND_MAX} (incl.) - \item \cppinline{srand(seed)} sets the global seed - \end{itemize} - \end{block} - \begin{alertblock}{Disadvantages} - \begin{itemize} - \item Seeding is not thread-safe; \cppinline{rand()} may be. - \item Returned numbers have small, implementation-defined range - \item No guarantee on quality - \item Mapping a random number to a custom range is hard - \item E.g.: \cppinline{rand() % 10} yields biased numbers and is wrong! - \end{itemize} - \end{alertblock} - \begin{goodpractice}[C random library]{Strongly avoid the C random library} - Use the \cpp11 facilities from the \cppinline{} header - \end{goodpractice} -\end{frame} diff --git a/talk/morelanguage/ranges.tex b/talk/morelanguage/ranges.tex deleted file mode 100644 index 8d3672a0..00000000 --- a/talk/morelanguage/ranges.tex +++ /dev/null @@ -1,85 +0,0 @@ -\subsection[range]{Ranges} - -\begin{frame}[fragile] - \frametitlecpp[20]{Ranges} - \begin{block}{The range concept} - \begin{itemize} - \item A range is a sequence of items that you can iterate over - \item It must provide iterators to its beginning and end, obtainable via \cppinline{std::range::begin} and \cppinline{std::range::end} - \item Range concepts are located in \cppinline{std::ranges} namespace - \item All STL containers are ranges - \end{itemize} - \end{block} - \begin{exampleblock}{Variations on ranges} - There are actually different types of ranges - \begin{itemize} - \item \cppinline{input_range}, \cppinline{output_range}, \cppinline{forward_range}, \cppinline{bidirectional_range}, \cppinline{random_access_range}, \cppinline{contiguous_range} - \item corresponding to the different iterator categories - \end{itemize} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Views} - \begin{block}{The view concept} - \begin{itemize} - \item A \cppinline{view} is a non-owning object built from a range or another view after applying some range adaptor(s) - \item The time complexity to copy, move, assign is constant - \item Range adaptors can be applied/chained with \cppinline{|} and are lazy - \item They live in the \cppinline{std::views} namespace - \item They introduce easy functional programming to the STL - \end{itemize} - \end{block} - \begin{exampleblockGB}{Example}{https://godbolt.org/z/d1vTv4TMa}{Views} - { \small - \begin{cppcode*}{} - auto const numbers = std::views::iota(0, 6); - auto even = [](int i) { return 0 == i % 2; }; - auto square = [](int i) { return i * i; }; - auto results = numbers | std::views::filter(even) - | std::views::transform(square); - for (auto a : results) { ... } // 0, 4, 16 - \end{cppcode*} - } - \end{exampleblockGB} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Many range adaptors are provided by the STL} - \begin{block}{Useful subset} - \begin{description}[keys/values] - \item[all] a view on all elements - \item[filter] applies a filter - \item[transform] applies a transformation - \item[take] takes only first n elements - \item[drop] skips first n elements - \item[join/split] joins ranges or splits into subranges - \item[reverse] reverses view order - \item[elements] for tuple views, extract nth elements of each tuple - \item[keys/values] for pair like views, takes 1st/2nd element of each pair - \end{description} - \end{block} - Remember you can combine them via (\cppinline{|}) -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[23]{Back to laziness} - \begin{block}{Views are lazy} - \begin{itemize} - \item Computation is only triggered when iterating - \item And can be stopped by e.g. \cppinline{take} - \item Here, the minimal number of iterations is performed - \end{itemize} - \end{block} - \begin{exampleblockGB}{Example}{https://godbolt.org/z/bWe6W69oE}{Lazy view} - \begin{cppcode*}{} - // print first 20 prime numbers above 1000000 - for (int i: std::views::iota(1000000) - | std::views::filter(odd) - | std::views::filter(isPrime) - | std::views::take(20)) { - std::cout << i << " "; - } - \end{cppcode*} - \end{exampleblockGB} -\end{frame} diff --git a/talk/morelanguage/stl.tex b/talk/morelanguage/stl.tex deleted file mode 100644 index ea8a3af4..00000000 --- a/talk/morelanguage/stl.tex +++ /dev/null @@ -1,408 +0,0 @@ -\subsection[STL]{The STL} - -\begin{frame}[fragile] - \frametitlecpp[98]{The Standard Template Library} - \begin{block}{What it is} - \begin{itemize} - \item A library of standard templates - \item Has almost everything you need - \begin{itemize} - \item strings, containers, iterators - \item algorithms, functions, sorters - \item functors, allocators - \item ... - \end{itemize} - \item Portable - \item Reusable - \item Efficient - \end{itemize} - \end{block} - \pause - \begin{exampleblock}{Use it} - and adapt it to your needs, thanks to templates - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[14]{STL in practice} - \begin{exampleblockGB}{STL example}{https://godbolt.org/z/n8ahEr5f6}{STL} - \begin{cppcode*}{} - #include - #include - #include // `import std;` in C++23 - #include - #include - - std::vector in{5, 3, 4}; // initializer list - std::vector out(3); // constructor taking size - std::transform(in.begin(), in.end(), // input range - out.begin(), // start result - std::negate{}); // function obj - std::copy(out.begin(), out.end(), // -5 -3 -4 - std::ostream_iterator{std::cout, " "}); - \end{cppcode*} - \end{exampleblockGB} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{STL's concepts} - \begin{block}{containers} - \small - \begin{itemize} - \setlength\itemsep{0em} - \setlength{\parskip}{0pt} - \setlength{\parsep}{0pt} - \item data structures for managing a range of elements, irrespective of: - \begin{itemize} - \setlength\itemsep{0em} - \setlength{\parskip}{0pt} - \setlength{\parsep}{0pt} - \item the data itself (templated) - \item the memory allocation of the structure (templated) - \item the algorithms that may use the structure (iterators) - \end{itemize} - \end{itemize} - \end{block} - \begin{exampleblock}{Examples ($\rightarrow$ \href{https://en.cppreference.com/w/cpp/string/basic_string}{\color{blue!50!white}{string}} and \href{https://en.cppreference.com/w/cpp/container}{\color{blue!50!white}{container library}} on cppreference)} - \small - \begin{itemize} - \setlength\itemsep{0em} - \item string, string\_view (\cpp17) - \item list, forward\_list (\cpp11), vector, deque, array (\cpp11) - \item {[}multi]map, [multi]set (\cpp23: flat\_[multi]map, flat\_[multi]set) - \item unordered\_[multi]map (\cpp11), unordered\_[multi]set (\cpp11) - \item stack, queue, priority\_queue - \item span (\cpp20) - \item non-containers: bitset, pair, tuple (\cpp11), optional (\cpp17), variant (\cpp17), any (\cpp17), expected (\cpp23) - \end{itemize} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Containers: std::vector} - \begin{cppcode*}{} - #include - std::vector v{5, 3, 4}; // 3 Ts, 5, 3, 4 - std::vector v(100); // 100 default constr. Ts - std::vector v(100, 42); // 100 Ts with value 42 - std::vector v2 = v; // copy - std::vector v2 = std::move(v); // move, v is empty - - std::size_t s = v.size(); - bool empty = v.empty(); - - v[2] = 17; // write element 2 - T& t = v[1000]; // access element 1000, bug! - T& t = v.at(1000); // throws std::out_of_range - T& f = v.front(); // access first element - v.back() = 0; // write to last element - T* p = v.data(); // pointer to underlying storage - \end{cppcode*} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Containers: std::vector} - \begin{cppcode*}{} - std::vector v = ...; - auto b = v.begin(); // iterator to first element - auto e = v.end(); // iterator to one past last element - // all following operations, except reserve, invalidate - // all iterators (b and e) and references to elements - - v.resize(100); // size changes, grows: new T{}s appended - // shrinks: Ts at end destroyed - v.reserve(1000); // size remains, memory increased - for (T i = 0; i < 900; i++) - v.push_back(i); // add to the end - v.insert(v.begin()+3, T{}); // insert after 3rd position - - v.pop_back(); // removes last element - v.erase(v.end() - 3); // removes 3rd-last element - v.clear(); // removes all elements - \end{cppcode*} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Containers: \texttt{std::unordered\_map}} - \begin{block}{} - Conceptually a container of \cppinline{std::pair} - \end{block} - \begin{cppcode*}{} - #include - std::unordered_map m; - m["hello"] = 1; // inserts new key, def. constr. value - m["hello"] = 2; // finds existing key - auto [it, isNewKey] = m.insert({"hello", 0}); // no effect - // ^ C++17: "Structured binding" - int val = m["world"]; // inserts new key (val == 0) - int val = m.at("monde"); // throws std::out_of_range - - if (auto it = m.find("hello"); it != m.end()) // C++17 - m.erase(it); // remove by iterator (fast) - if (m.contains("hello")) // C++20 - m.erase("hello"); // remove by key, 2. lookup, bad - for (auto const& [k, v] : m) // iterate k/v pairs (C++17) - std::cout << k << ": " << v << '\n'; - \end{cppcode*} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{\texttt{std::hash}} - \begin{block}{} - \begin{itemize} - \item The standard utility to create hash codes - \item Used by \cppinline{std::unordered_map} and others - \item Can be customized for your types via template specialization - \end{itemize} - \end{block} - \begin{cppcode*}{} - #include - std::hash h; - std::cout << h("hello"); // 2762169579135187400 - std::cout << h("world"); // 8751027807033337960 - - class MyClass { int a, b; ... }; - template<> struct std::hash { - std::size_t operator()(MyClass const& c) { - std::hash h; - return h(c.a) ^ h(c.b); // xor to combine hashes - } - }; - \end{cppcode*} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{STL's concepts} - \begin{block}{iterators} - \begin{itemize} - \item generalization of pointers - \item allow iteration over some data, irrespective of: - \begin{itemize} - \item the container used (templated) - \item the data itself (container is templated) - \item the consumer of the data (templated algorithm) - \end{itemize} - \item examples - \begin{itemize} - \item \cppinline{std::reverse_iterator}, \cppinline{std::back_insert_iterator}, ... - \end{itemize} - \end{itemize} - \end{block} - \begin{exampleblockGB}{Iterator example}{https://godbolt.org/z/jv1qTo5xz}{Iterator example} - \begin{cppcode*}{} - std::vector const v = {1,2,3,4,5,6,7,8,9}; - auto const end = v.rend() - 3; // arithmetic - for (auto it = v.rbegin(); - it != end; // compare positions - it += 2) // jump 2 positions - std::cout << *it; // dereference, prints: 975 - \end{cppcode*} - \end{exampleblockGB} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{STL's concepts} - \begin{block}{algorithms} - \begin{itemize} - \item implementation of an algorithm working on data - \item with a well defined behavior (defined complexity) - \item irrespective of - \begin{itemize} - \item the data handled - \item the container where the data live - \item the iterator used to go through data (almost) - \end{itemize} - \item examples - \begin{itemize} - \item for\_each, find, find\_if, count, count\_if, search - \item copy, swap, transform, replace, fill, generate - \item remove, remove\_if - \item unique, reverse, rotate, shuffle, partition - \item sort, partial\_sort, merge, make\_heap, min, max - \item lexicographical\_compare, iota, reduce, partial\_sum - \end{itemize} - \item see also \href{https://www.youtube.com/watch?v=2olsGf6JIkU}{105 STL Algorithms in Less Than an Hour} and the \href{https://en.cppreference.com/w/cpp/algorithm}{algorithms library} on cppreference - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{STL's concepts} - \begin{block}{functors / function objects} - \begin{itemize} - \item generic utility functions - \item as structs with \cppinline{operator()} - \item mostly useful to be passed to STL algorithms - \item implemented independently of - \begin{itemize} - \item the data handled (templated) - \item the context (algorithm) calling it - \end{itemize} - \item examples - \begin{itemize} - \item plus, minus, multiplies, divides, modulus, negate - \item equal\_to, less, greater, less\_equal, ... - \item logical\_and, logical\_or, logical\_not - \item bit\_and, bit\_or, bit\_xor, bit\_not - \item identity, not\_fn - \item bind, bind\_front - \end{itemize} - \item see also documentation on \href{https://en.cppreference.com/w/cpp/utility/functional}{cppreference} - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Functors / function objects} - \begin{block}{Example} - \begin{cppcode*}{} - struct Incrementer { - int m_inc; - Incrementer(int inc) : m_inc(inc) {} - - int operator()(int value) const { - return value + m_inc; - } - }; - std::vector v{1, 2, 3}; - const auto inc = 42; - std::transform(v.begin(), v.end(), v.begin(), - Incrementer{inc}); - \end{cppcode*} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Prefer lambdas over functors} - \begin{exampleblock}{With lambdas} - \begin{cppcode*}{} - std::vector v{1, 2, 3}; - const auto inc = 42; - std::transform(begin(v), end(v), begin(v), - [inc](int value) { - return value + inc; - }); - \end{cppcode*} - \end{exampleblock} - \pause - \begin{goodpractice}[STL and lambdas]{Use STL algorithms with lambdas} - \begin{itemize} - \item Prefer lambdas over functors when using the STL - \item Avoid binders like \cppinline{std::bind2nd}, \cppinline{std::ptr_fun}, etc. - \end{itemize} - \end{goodpractice} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Range-based for loops with STL containers} - \begin{block}{Iterator-based loop (since \cpp98)} - \begin{cppcode*}{} - std::vector v = ...; - int sum = 0; - for (std::vector::iterator it = v.begin(); - it != v.end(); it++) - sum += *it; - \end{cppcode*} - \end{block} - \pause - \begin{block}{Range-based for loop (since \cpp11)} - \begin{cppcode*}{firstnumber=6} - std::vector v = ...; - int sum = 0; - for (auto a : v) { sum += a; } - \end{cppcode*} - \end{block} - \pause - \begin{exampleblock}{STL way (since \cpp98)} - \begin{cppcode*}{firstnumber=9} - std::vector v = ...; - int sum = std::accumulate(v.begin(), v.end(), 0); - // std::reduce(v.begin(), v.end()); // C++17 - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{More examples} - \begin{cppcode} - std::list l = ...; - - // Finds the first element in a list between 1 and 10. - const auto it = std::find_if(l.begin(), l.end(), - [](int i) { return i >= 1 && i <= 10; }); - if (it != l.end()) { - int element = *it; ... - } - - // Computes sin(x)/(x + DBL_MIN) for elements of a range. - std::vector r(l.size()); - std::transform(l.begin(), l.end(), r.begin(), - [](auto x) { return std::sin(x)/(x + DBL_MIN); }); - - // reduce/fold (using addition) - const auto sum = std::reduce(v.begin(), v.end()); - \end{cppcode} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{More examples} - \begin{cppcode} - std::vector v = ...; - - // remove duplicates - std::sort(v.begin(), v.end()); - auto newEndIt = std::unique(v.begin(), v.end()); - v.erase(newEndIt, v.end()); - - // remove by predicate - auto p = [](int i) { return i > 42; }; - auto newEndIt = std::remove_if(v.begin(), v.end(), p); - v.erase(newEndIt, v.end()); - - // remove by predicate (C++20) - std::erase_if(v, p); - \end{cppcode} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Welcome to lego programming!} - \begin{block}{} - \pgfdeclareimage[height=0.5cm]{AtlasLego}{morelanguage/AtlasLego.jpg} - \includegraphics[width=\linewidth]{morelanguage/AtlasLego} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Using the STL} - \begin{exercise}{STL} - \begin{itemize} - \item go to \texttt{exercises/stl} - \item look at the non STL code in randomize.nostl.cpp - \begin{itemize} - \item it creates a vector of ints at regular intervals - \item it randomizes them - \item it computes differences between consecutive ints - \item and the mean and variance of it - \end{itemize} - \item open randomize.cpp and complete the ``translation'' to STL - \item see how easy it is to reuse the code with complex numbers - \end{itemize} - \end{exercise} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Using the STL} - \begin{exampleblock}{Be brave and persistent!} - \begin{itemize} - \item you may find the STL quite difficult to use - \item template syntax is really tough - \item it is hard to get right, compilers spit out long error novels - \begin{itemize} - \item but, compilers are getting better with error messages - \end{itemize} - \item \cpp20 will help with concepts and ranges - \item the STL is extremely powerful and flexible - \item it will be worth your time! - \end{itemize} - \end{exampleblock} -\end{frame} diff --git a/talk/morelanguage/templates.tex b/talk/morelanguage/templates.tex deleted file mode 100644 index 81c132a4..00000000 --- a/talk/morelanguage/templates.tex +++ /dev/null @@ -1,504 +0,0 @@ -\subsection[\textless{}T\textgreater]{Templates} - -\begin{frame}[fragile] - \frametitlecpp[17]{Templates} - \begin{block}{Concept} - \begin{itemize} - \item The \cpp way to write reusable code - \begin{itemize} - \item like macros, but fully integrated into the type system - \end{itemize} - \item Applicable to functions, classes and variables - \end{itemize} - \end{block} - \begin{cppcode} - template - const T & max(const T &a, const T &b) { - return b < a ? a : b; - } - template - struct Vector { - int m_len; - T* m_data; - }; - template - std::size_t size = sizeof(T); - \end{cppcode} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Templates} - \begin{block}{Notes on templates} - \begin{itemize} - \item they are compiled for each instantiation - \item they need to be defined before used - \begin{itemize} - \item so all template code must typically be in headers - \item or declared to be available externally (\cppinline{extern template}) - \end{itemize} - \item this may lead to longer compilation times and bigger binaries - \end{itemize} - \end{block} - \newsavebox{\codepiece} - \begin{lrbox}{\codepiece} - \begin{minipage}{.35\linewidth} - \small - \begin{cppcode*}{} - template - T func(T a) { - return a; - } - \end{cppcode*} - \end{minipage} - \end{lrbox} - \newsavebox{\codepiecea} - \begin{lrbox}{\codepiecea} - \begin{minipage}{.4\linewidth} - \small - \begin{cppcode*}{linenos=false} - int func(int a) { - return a; - } - \end{cppcode*} - \end{minipage} - \end{lrbox} - \newsavebox{\codepieceb} - \begin{lrbox}{\codepieceb} - \begin{minipage}{.4\linewidth} - \small - \begin{cppcode*}{linenos=false} - double func(double a) { - return a; - } - \end{cppcode*} - \end{minipage} - \end{lrbox} - \begin{tikzpicture}[rectangle,rounded corners] - \draw node (template) [draw] {\usebox{\codepiece}} - node (templatea) [draw] at (6cm,+1cm) {\usebox{\codepiecea}} - node (templateb) [draw] at (6cm,-1cm) {\usebox{\codepieceb}}; - \draw[->,thick] (template) -- (templatea) node [above,midway,sloped] {\small func(3)}; - \draw[->,thick] (template) -- (templateb) node [below,midway,sloped] {\small func(5.2)}; - \end{tikzpicture} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Templates} - \begin{block}{Template parameters} - \begin{itemize} - \item can be types, values or other templates - \item you can have several - \item default values allowed starting at the last parameter - \end{itemize} - \end{block} - \begin{cppcode*}{} - template - struct Map { - void set(const KeyType &key, ValueType value); - ValueType get(const KeyType &key); - ... - }; - - Map m1; - Map m2; // Map - Map<> m3; // Map - Map m4; // Map, C++17 - \end{cppcode*} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Template parameters} - \begin{block}{\texttt{typename} vs.\ \texttt{class} keyword} - \begin{itemize} - \item for declaring a template type parameter, - the \cppinline{typename} and \cppinline{class} keyword are semantically equivalent - \item template template parameters require \cpp17 for \cppinline{typename} - \end{itemize} - \end{block} - \small - \begin{cppcode*}{} - template - T func(T a); // equivalent to: - template - T func(T a); - - template class C> - C func(C a); // equivalent to: - template class C> - C func(C a); // equivalent to: - template typename C> // C++17 - C func(C a); - \end{cppcode*} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Template implementation} - \begin{cppcode*}{} - template - struct Map { - // declaration and inline definition - void set(const KeyType &key, ValueType value) { - ... - } - // just declaration - ValueType get(const KeyType &key); - }; - - // out-of-line definition - template - ValueType Map::get - (const KeyType &key) { - ... - } - \end{cppcode*} -\end{frame} - -\begin{advanced} - -\begin{frame}[fragile] - \frametitlecpp[98]{Nested templates} - \begin{exampleblockGB}{Nested templates}{https://godbolt.org/z/a9nPnK9jx}{Nested templates} - \small - \begin{cppcode*}{} - template - struct Map { - template - void set(const KeyType &key, OtherValueType value) { - ... - } - template - ValueType get(const OtherKeyType &key); - }; - - template //for class - template //for member function - ValueType Map::get - (const OtherKeyType &key) { ... } - \end{cppcode*} - \end{exampleblockGB} -\end{frame} - -\end{advanced} - -\begin{frame}[fragile] - \frametitle{Non-type template parameter \hfill \cpp98 / \cpp17 / \cpp20} - \begin{block}{template parameters can also be values} - \begin{itemize} - \item integral types, pointer, enums in \cpp98 - \item \cppinline{auto} in \cpp17 - \item literal types (includes floating points) in \cpp20 - \end{itemize} - \end{block} - \begin{cppcode*}{} - template - struct Polygon { - float perimeter() { - return 2 * N * std::sin(PI / N) * radius; - } - float radius; - }; - - Polygon<19> nonadecagon{3.3f}; - \end{cppcode*} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Template specialization} - \begin{block}{Specialization} - Templates can be specialized for given values of their parameter - \end{block} - \small - \begin{cppcode*}{} - template - struct Polygon { ... }; // primary template - - template // partial specialization - struct Polygon { - F perimeter() { return 6 * radius; } - F radius; - }; - template<> // full specialization - struct Polygon { - int perimeter() { return 6 * radius; } - int radius; - }; - \end{cppcode*} -\end{frame} - -\begin{advanced} - -\begin{frame}[fragile] - \frametitlecpp[98]{Template argument deduction} - \begin{block}{Template argument deduction} - \begin{itemize} - \item Template arguments deduced from (function) arguments - \item Template arguments can always be specified explicitly - \item Only for function templates (Before \cpp14) - \end{itemize} - \end{block} - \begin{cppcode*}{} - template - void f(T t, U u) { ... } - - f(42, true); // deduces T=int, U=bool - // calls f(42, true); - f(42, true); // sets T=float, deduces U=bool - // calls f(42, true); - // 42 converted to float before call - \end{cppcode*} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Template argument deduction} - \begin{block}{Deduced contexts} - \begin{itemize} - \item Compiler can even deduce template arguments inside certain expressions (pattern matching) - \item See \href{https://en.cppreference.com/w/cpp/language/template_argument_deduction}{cppreference} for details - \end{itemize} - \end{block} - \begin{cppcode*}{} - template - void f(T* p) { ... } - - const int * ip = ...; - f(ip); // deduces T=const int - - template - void g(std::array a) { ... } - - std::array aip = ...; - g(aip); // deduces T=int, N=3 - \end{cppcode*} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Template argument deduction} - \begin{block}{Non-deduced contexts} - \begin{itemize} - \item Deduction from certain expressions is impossible/forbidden - \end{itemize} - \end{block} - \begin{overprint} - \onslide<1> - \begin{alertblock}{} - \footnotesize - \begin{cppcode*}{} - template - void f(typename C::value_type v) { ... } - f(std::vector{...}); // cannot deduce C - // from a dependent type - template - void g(std::array a) { ... } - g(std::array{...}); // deduces T=int, - // cannot deduce N from expression - template - void h(std::vector v) { ... } - h({1, 2, 3}); // error, braced-initializer list has no type - h(std::vector{1, 2, 3}); // ok, T=int - \end{cppcode*} - \end{alertblock} - \onslide<2> - \begin{alertblock}{} - \footnotesize - \begin{cppcode*}{} - template - void reduce(const C& cont, const F& f = std::plus{}); - reduce(std::vector{...}); // error: cannot deduce F - // would need: - - template - const T & max(const T &a, const T &b) { ... } - int i = 3; - max(i, 3.14f); // deduces T=int and T=float, error - // either: max(i, 3.14f); - // or: max(static_cast(i), 3.14f); - \end{cppcode*} - \end{alertblock} - \end{overprint} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Template argument deduction} - \begin{block}{Deduction in partial specializations} - \begin{itemize} - \item Partial specializations also deduce template arguments - \begin{itemize} - \item with similar rules as for function templates - \item but some more restrictions (cf.\ \href{https://en.cppreference.com/w/cpp/language/partial_specialization}{cppreference}) - \end{itemize} - \end{itemize} - \end{block} - \small - \begin{cppcode*}{} - template - struct S { ... }; // primary template - - template - struct S { ... }; // specialization 1 - - template - struct S> { ... }; // specialization 2 - - S s1; // prim. tmpl. (T=int) ok, spec. 1/2 invalid - S s2; // prim. tmpl. (T=int*) and spec. 1 (T=int) ok - // spec. 1 is more specialized, will be used - \end{cppcode*} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Template argument deduction} - \begin{block}{Specialization vs.\ overloading} - \begin{itemize} - \item For function templates we can choose between specialization and overloading - \item Partial specialization of function templates is forbidden - \end{itemize} - \end{block} - \small - \begin{multicols}{2} - \begin{cppcode*}{} - template - void f(T t) { ... } - - - void f(int* t) { ... } - - - template - void f(T* t) { ... } - \end{cppcode*} - \columnbreak - \begin{cppcode*}{firstnumber=10} - template - void f(T t) { ... } - - template <> - void f(int* t) { ... } - - // part. spec. forbidden: - template - void f(T* t) {...} - \end{cppcode*} - \end{multicols} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Template argument deduction} - \begin{block}{Disadvantages of specialization vs.\ overloading} - \begin{itemize} - \item Specialization always needs a primary template - \begin{itemize} - \item Sometimes this does not make sense - \end{itemize} - \item Partial specializations of function templates is forbidden - \begin{itemize} - \item So we need SFINAE workarounds or concepts - \end{itemize} - \end{itemize} - \end{block} - \small - \begin{block}{Could you express this with specializations?} - \begin{cppcode} - template - void f(T* p) { ... } - - template - void f(std::unique_ptr p) { ... } - \end{cppcode} - \end{block} - \begin{goodpractice}{Specialization vs.\ overloading} - Prefer overloading function templates over template specialization - \end{goodpractice} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{Class Template Argument Deduction (CTAD)} - \begin{block}{CTAD} - \begin{itemize} - \item Deduce the template arguments for a class template - \item Based on construction arguments - \item Only when no template arguments provided - \item Since \cpp20: CTAD for aggregates (no constructor needed) - \end{itemize} - \end{block} - \begin{exampleblockGB}{Practically}{https://godbolt.org/z/eYhsMcGsW}{CTAD} - \small - \begin{cppcode*}{} - template - struct Triple { - Triple(A a, B b, C c) : a(a), b(b), c(c) {} - A a; B b; C c; - }; - Triple t{42, true, 3.14}; // Triple - Triple t2{42, true, 3.14}; // compilation error - Triple t3{42, true, 3.14}; // not CTAD - \end{cppcode*} - \end{exampleblockGB} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{Class Template Argument Deduction (CTAD)} - \begin{block}{Deduction guides} - \begin{itemize} - \item Describe how constructor argument types are mapped to class template arguments - \end{itemize} - \end{block} - \begin{cppcode} - template - struct Pair { - Pair(A a, B b) : a(a), b(b) {} - A a; B b; - }; - \end{cppcode} - \begin{overprint}[\columnwidth] - \onslide<1> - \begin{cppcode*}{firstnumber=6} - - - - Pair p{42, "hello"}; // Pair - \end{cppcode*} - \onslide<2> - \begin{cppcode*}{firstnumber=6} - template - Pair(A, const char*) -> Pair; - - Pair p{42, "hello"}; // Pair - \end{cppcode*} - \end{overprint} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[17]{Class Template Argument Deduction (CTAD)} - \begin{block}{Standard library examples} - \begin{cppcode*}{} - std::pair p{1.2, true}; // std::pair - std::tuple t{1.2, true, 32}; - // std::tuple - std::vector v{1, 2, 3}; // std::vector - std::list l{v.begin(), v.end()}; // std::list - std::array a{1, 2, 3}; // std::array - - std::mutex m; - std::lock_guard l{m}; // std::lock_guard - \end{cppcode*} - \end{block} -\end{frame} - -\end{advanced} - -\begin{frame}[fragile] - \frametitlecpp[98]{The full power of templates} - \begin{exercise}{Templates} - \begin{itemize} - \item go to \texttt{exercises/templates} - \item look at the OrderedVector code - \item compile and run playwithsort.cpp. See the ordering - \item modify playwithsort.cpp and reuse OrderedVector with Complex - \item improve OrderedVector to template the ordering - \item test reverse ordering of strings (from the last letter) - \item test order based on {\color{blue} \href{https://en.wikipedia.org/wiki/Taxicab_geometry}{Manhattan distance}} with complex type - \item check the implementation of Complex - \item try ordering complex of complex - \end{itemize} - \end{exercise} -\end{frame} diff --git a/talk/objectorientation/adl.tex b/talk/objectorientation/adl.tex deleted file mode 100644 index 7c12eda0..00000000 --- a/talk/objectorientation/adl.tex +++ /dev/null @@ -1,238 +0,0 @@ -\subsection[ADL]{Name Lookups} - -\begin{frame}[fragile] - \frametitlecpp[98]{Basics of name lookup} - \begin{exampleblock}{Example code} - \begin{cppcode} - std::cout << std::endl; - \end{cppcode} - \end{exampleblock} - \begin{block}{How to find the declaration of a name?} - Mainly 2 cases : - \begin{itemize} - \item qualified lookup, for names preceded by `::' - \begin{itemize} - \item here \cppinline{cout} and \cppinline{endl} - \item name is only looked for in given class/namespace/enum class - \end{itemize} - \item unqualified lookup - \begin{itemize} - \item here for \cppinline{std} and \cppinline{operator<<} - \item name is looked for in a sequence of scopes until found - \begin{itemize} - \item remaining scopes are not examined - \end{itemize} - \item in parallel Argument Dependent Loopkup (ADL) may happen - \end{itemize} - \end{itemize} - \end{block} -\end{frame} - -\begin{frame} - \frametitlecpp[98]{Unqualified name lookup and ADL} - \begin{block}{Ordered list of scopes (simplified)} - \begin{itemize} - \item file (only for global level usage) - \item current namespace/block, enclosing namespaces/blocks, etc... - \item current class if any, base classes if any, etc... - \end{itemize} - \end{block} - \begin{exampleblock}{Argument Dependent Lookup (simplified)} - Only for call expression - \begin{itemize} - \item e.g.\ \cppinline{f(a, b)} or \cppinline{a + b} - \end{itemize} - The compiler also examines arguments one by one and searches: - \begin{itemize} - \item class, if any - \item direct and indirect base classes, if any - \item enclosing namespace - \end{itemize} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{ADL consequences (1)} - \begin{block}{Use standalone/non-member functions} - When a method is not accessing the private part of a class, make it a function in the same namespace - \vspace{-1mm} - \begin{columns}[T] - \begin{column}{.35\textwidth} - Don't write : - \vspace{-1mm} - \begin{cppcode*}{} - namespace MyNS { - struct A { - T func(...); - }; - } - \end{cppcode*} - \end{column} - \begin{column}{.35\textwidth} - Prefer : - \vspace{-1mm} - \begin{cppcode*}{firstnumber=6} - namespace MyNS { - struct A { ... }; - T func(const A&, ..); - } - \end{cppcode*} - \end{column} - \end{columns} - \vspace{.2cm} - Advantages : - \begin{itemize} - \item minimal change in user code, \cppinline{func} still feels part of class \cppinline{A} - \item makes sure \cppinline{func} does not touch internal state of \cppinline{A} - \end{itemize} - Notes : - \begin{itemize} - \item non-member \cppinline{func} has to be in same namespace as \cppinline{A} - \item please avoid global namespace - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{ADL consequences (2)} - \begin{block}{Customization points and \texttt{using}} - \begin{columns}[t] - \begin{column}{.35\textwidth} - Don't write : - \begin{cppcode*}{} - N::A a,b; - std::swap(a, b); - \end{cppcode*} - \end{column} - \begin{column}{.35\textwidth} - Prefer : - \begin{cppcode*}{firstnumber=3} - N::A a,b; - using std::swap; - swap(a, b); - \end{cppcode*} - \end{column} - \end{columns} - \vspace{.2cm} - Advantages : - \begin{itemize} - \item allows to use \cppinline{std::swap} by default - \item but benefits from any dedicated overload - \end{itemize} - \begin{columns} - \begin{column}{.7\textwidth} - \begin{cppcode*}{firstnumber=6} - namespace N { - class A { ... }; - // optimized swap for A - void swap(A&, A&); - } - \end{cppcode*} - \end{column} - \end{columns} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Hidden Friends} - \begin{block}{Hidden friends} - \begin{itemize} - \item Friend functions \emph{defined} in class scope are ``hidden friends'' - \begin{itemize} - \item Without any declaration outside the class - \end{itemize} - \item They are \emph{not} member functions (no access to \cppinline{this}) - \end{itemize} - \end{block} - \begin{exampleblock}{\texttt{operator<<} as hidden friend} - \small - \begin{cppcode*}{} - class Complex { - float m_real, m_imag; - public: - Complex(float, float) { ... } - friend - std::ostream & operator<<(std::ostream & os, - Complex const & c) { - return os << c.m_real << " + " << c.m_imag << "i"; - } - }; - std::cout << Complex{2.f, 3.f}; // Prints 2 + 3i - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Hidden Friends and ADL} - \begin{block}{Advantages of hidden friends} - \begin{itemize} - \item Are \emph{only} found via ADL, e.g.\ \cppinline{std::cout << complex;} - \item Compiler needs to consider less functions during ordinary name lookup (faster compilation) - \item Avoid accidental implicit conversions - \end{itemize} - \end{block} - \begin{alertblock}{Accidental conversions - two counterexamples} - \footnotesize - \begin{overprint} - \onslide<1> - \begin{cppcode*}{} - std::ostream & operator<< // out-of-class definition - (std::ostream & os, Complex const & c) { ... } - struct Fraction { - int num, denom; - operator Complex() const { ... } // conversion op - }; - - std::cout << Fraction{2,4}; // Prints 0.5 + 0i - //calls operator<<(std::cout, Fraction{2,4}.operator Complex()); - \end{cppcode*} - - \onslide<2> - \begin{cppcode*}{} - std::ostream & operator<< // out-of-class definition - (std::ostream & os, Complex const & c) { ... } - struct Fraction { - int num, denom; - }; - - Complex::Complex(Fraction f); // converting ctor - - std::cout << Fraction{2,4}; // Prints 0.5 + 0i - //calls operator<<(std::cout, Complex(Fraction{2, 3})); - \end{cppcode*} - \end{overprint} - \end{alertblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Good practice for operator overloading} - \begin{goodpractice}{Operator overloading} - \begin{itemize} - \item Must declare in-class, as member operators: - \begin{itemize} - \item \cppinline{operator=}, \cppinline{operator()}, \cppinline{operator[]}, \cppinline{operator->} - \end{itemize} - \item Prefer in-class declaration, as member operators: - \begin{itemize} - \item compound assignment operators, e.g.\ \cppinline{operator+=} - \item unary operators - \begin{itemize} - \item e.g.\ \cppinline{operator++}, \cppinline{operator--}, \cppinline{operator!}, unary \cppinline{operator-} (negate), dereference operator \cppinline{operator*} - \end{itemize} - \end{itemize} - \item Prefer definition in-class as hidden friends: - \begin{itemize} - \item binary arithmetic operators, e.g.\ \cppinline{operator+}, \cppinline{operator|} - \item binary logical operators, e.g.\ \cppinline{operator<} - \item stream operators, e.g.\ \cppinline{operator<<} - \end{itemize} - \item Avoid overloading: - \begin{itemize} - \item Address-of \cppinline{operator&} - \item Boolean logic operators, e.g.\ \cppinline{operator||} - \item Comma operator \cppinline{operator,} - \item Member dereference operators \cppinline{operator->*} - \end{itemize} - \end{itemize} - \end{goodpractice} -\end{frame} diff --git a/talk/objectorientation/advancedoo.tex b/talk/objectorientation/advancedoo.tex deleted file mode 100644 index 420fcd59..00000000 --- a/talk/objectorientation/advancedoo.tex +++ /dev/null @@ -1,600 +0,0 @@ -\subsection[advOO]{Advanced OO} - -\begin{frame}[fragile] - \frametitlecpp[98]{\texttt{this} keyword} - \begin{block}{How to know an object's address?} - \begin{itemize} - \item Sometimes we need the address of the current object - \item Or we need to pass our address / a reference to a different entity - (for example to implement operators, see later) - \item All class methods can use the keyword \cppinline{this} - \begin{itemize} - \item It returns the address of the current object - \item Its type is \cppinline{T*} in the methods of a class {\ttfamily T} - \end{itemize} - \end{itemize} - \end{block} - \begin{minipage}{0.7\textwidth} - \begin{cppcode} - struct S { - int a,b; - // these two are the same: - int getB() { return b; } // 5 - int getB() { return this->b; } // 5 - void testAddress() { - S* addr = this; // 0x3000 - } - } s{2,5}; - \end{cppcode} - \end{minipage}% - \hfil% - \begin{minipage}{0.3\textwidth} - \begin{tikzpicture} - \memorystack[size x=2cm,word size=1,block size=4,nb blocks=4] - \memorypush{a = 2} - \memorypush{b = 5} - \memorystruct{1}{2}{\tiny s} - \draw[-Triangle,thick] (\stacksizex-1*\stacksizey,-1*\stacksizey) node[left] {\footnotesize \cppinline{this} pointer} -- (\stacksizex,-0.1*\stacksizey); - \end{tikzpicture} - \end{minipage} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Polymorphism} - \begin{block}{the concept} - \begin{itemize} - \item objects actually have multiple types simultaneously - \item and can be used as any of them - \end{itemize} - \end{block} - \begin{multicols}{2} - \begin{cppcode*}{} - Polygon p; - - int f(Drawable & d) {...} - f(p); //ok - - try { - throw p; - } catch (Shape & e) { - // will be caught - } - \end{cppcode*} - \columnbreak - \center - \begin{overprint} - \onslide<1> - \begin{tikzpicture}[node distance=1.5cm] - \classbox{Drawable}{} - \classbox[below of=Drawable]{Shape}{} - \classbox[below of=Shape]{Polygon}{} - \draw[very thick,-Triangle] (Polygon) -- (Shape); - \draw[very thick,-Triangle] (Shape) -- (Drawable); - \end{tikzpicture} - \onslide<2-> - \begin{tikzpicture} - \memorystack[size x=3cm,word size=1,block size=4,nb blocks=9] - \memorypush{Drawable.a} - \memorypush{Drawable.b} - \memorypush{...} - \memorypush{Shape.a} - \memorypush{Shape.b} - \memorypush{...} - \memorypush{Polygon.nLines} - \onslide<2>{\memorystruct{1}{7}{\tiny Polygon}} - \onslide<3>{\memorystruct{1}{3}{\tiny Drawable}} - \onslide<4>{\memorystruct{1}{6}{\tiny Shape}} - \end{tikzpicture} - \end{overprint} - \end{multicols} -\end{frame} - - -\begin{frame}[fragile] - \frametitlecpp[98]{Inheritance privacy and polymorphism} - \begin{block}{Only public base classes are visible to outside code} - \begin{itemize} - \item private and protected bases are not - \item this may restrict usage of polymorphism - \end{itemize} - \end{block} - \begin{multicols}{2} - \begin{cppcode*}{} - Polygon p; - - int f(Drawable & d) {...} - f(p); // Not ok anymore - - try { - throw p; - } catch (Shape & e) { - // ok, will be caught - } - \end{cppcode*} - \columnbreak - \center - \begin{tikzpicture}[node distance=1.5cm] - \classbox{Drawable}{} - \classbox[below of=Drawable]{Shape}{} - \classbox[below of=Shape]{Polygon}{} - \draw[very thick,-Triangle] (Polygon) -- (Shape) node[midway,right] {public}; - \draw[very thick,-Triangle] (Shape) -- (Drawable) node[midway,right] {private}; - \end{tikzpicture} - \end{multicols} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Method overriding} - \begin{block}{the idea} - \begin{itemize} - \item a method of the parent class can be replaced in a derived class - \item but which one is called? - \end{itemize} - \end{block} - \begin{multicols}{2} - \begin{cppcode*}{} - Polygon p; - p.draw(); // ? - - Shape & s = p; - s.draw(); // ? - \end{cppcode*} - \columnbreak - \center - \begin{tikzpicture}[node distance=1.5cm] - \classbox{Drawable}{ - void draw(); - } - \classbox[below of=Drawable]{Shape}{} - \classbox[below of=Shape]{Polygon}{ - void draw(); - } - \draw[very thick,-Triangle] (Polygon) -- (Shape); - \draw[very thick,-Triangle] (Shape) -- (Drawable); - \end{tikzpicture} - \end{multicols} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Virtual methods} - \begin{block}{the concept} - \begin{itemize} - \item methods can be declared \cppinline{virtual} - \item for these, the most derived object's implementation is used - (i.e.\ the dynamic type behind a pointer/reference) - \item for non-virtual methods, the static type of the variable decides - \end{itemize} - \end{block} - \begin{overprint} - \onslide<2> - \begin{multicols}{2} - \begin{cppcode*}{} - Polygon p; - p.draw(); // Polygon.draw - - Shape & s = p; - s.draw(); // Drawable.draw - \end{cppcode*} - \columnbreak - \center - \begin{tikzpicture}[node distance=1.5cm] - \classbox{Drawable}{ - \cppinline{void draw();} - } - \classbox[below of=Drawable]{Shape}{} - \classbox[below of=Shape]{Polygon}{ - \cppinline{void draw();} - } - \draw[very thick,-Triangle] (Polygon) -- (Shape); - \draw[very thick,-Triangle] (Shape) -- (Drawable); - \end{tikzpicture} - \end{multicols} - - \onslide<3> - \begin{multicols}{2} - \begin{cppcode*}{highlightlines=5} - Polygon p; - p.draw(); // Polygon.draw - - Shape & s = p; - s.draw(); // Polygon.draw - \end{cppcode*} - \columnbreak - \center - \begin{tikzpicture}[node distance=1.5cm] - \classbox{Drawable}{ - \cppinline{virtual void draw();} - } - \classbox[below of=Drawable]{Shape}{} - \classbox[below of=Shape]{Polygon}{ - \cppinline{void draw();} - } - \draw[very thick,-Triangle] (Polygon) -- (Shape); - \draw[very thick,-Triangle] (Shape) -- (Drawable); - \end{tikzpicture} - \end{multicols} - \end{overprint} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Virtual methods - implications} - \begin{block}{Mechanics} - \begin{itemize} - \item virtual methods are dispatched at run time - \begin{itemize} - \item while non-virtual methods are bound at compile time - \end{itemize} - \item they also imply extra storage and an extra indirection - \begin{itemize} - \item practically, the object stores a pointer to the correct method - \item in a so-called ``virtual table'' (``vtable'') - \end{itemize} - \end{itemize} - \end{block} - \begin{alertblock}{Consequences} - \begin{itemize} - \item virtual methods are ``slower'' than standard ones - \item and they can rarely be inlined - \item templates are an alternative for performance-critical cases - \end{itemize} - \end{alertblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{{\texttt override} keyword} - \begin{block}{Principle} - \begin{itemize} - \item when overriding a virtual method, the \cppinline|override| keyword should be used - \item the \cppinline|virtual| keyword is then optional - \end{itemize} - \end{block} - \begin{exampleblock}{Practically} - \begin{cppcode} - struct Base { - virtual void some_func(float); - }; - struct Derived : Base { - void some_func(float) override; - }; - \end{cppcode} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Why was {\texttt override} keyword introduced?} - To detect the mistake in the following code : - \begin{block}{Without {\texttt override} (\cpp98)} - \begin{cppcode} - struct Base { - virtual void some_func(float); - }; - struct Derived : Base { - void some_func(double); // oops ! - }; - \end{cppcode} - \end{block} - \begin{itemize} - \item with \cppinline|override|, you would get a compiler error - \item if you forget \cppinline|override| when you should have it, you get a compiler warning - \end{itemize} -\end{frame} - -\begin{advanced} -\begin{frame}[fragile] - \frametitlecpp[11]{{\texttt final} keyword} - \begin{block}{Idea} - \begin{itemize} - \item make sure you cannot further override a given virtual method - \item by declaring it final - \end{itemize} - \end{block} - \begin{exampleblock}{Practically} - \begin{cppcode} - struct Base { - virtual void some_func(float); - }; - struct Intermediate : Base { - void some_func(float) final; - }; - struct Derived : Intermediate { - void some_func(float) override; // error - }; - \end{cppcode} - \end{exampleblock} -\end{frame} -\end{advanced} - -\begin{frame}[fragile] - \frametitlecpp[11]{Pure Virtual methods} - \begin{block}{Concept} - \begin{itemize} - \item unimplemented methods that must be overridden - \item marked by \cppinline{= 0} in the declaration - \item makes their class abstract - \item only non-abstract classes can be instantiated - \end{itemize} - \end{block} - \pause - \begin{multicols}{2} - \begin{cppcode*}{} - // Error : abstract class - Shape s; - - // ok, draw has been implemented - Polygon p; - - // Shape type still usable - Shape & s = p; - s.draw(); - \end{cppcode*} - \columnbreak - \begin{tikzpicture}[node distance=1.5cm] - \classbox{Drawable}{ - \cppinline{virtual void draw() = 0;} - } - \classbox[below of=Drawable]{Shape}{} - \classbox[below of=Shape]{Polygon}{ - \cppinline{void draw() override;} - } - \draw[very thick,-Triangle] (Polygon) -- (Shape); - \draw[very thick,-Triangle] (Shape) -- (Drawable); - \end{tikzpicture} - \end{multicols} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Polymorphism and destruction} - \begin{block}{Owning base pointers} - We sometimes need to maintain owning pointers to base classes: - \end{block} - \begin{overprint} - \onslide<1> - \begin{cppcode} - struct Drawable { - virtual void draw() = 0; - }; - Drawable* getImpl(); - - Drawable* p = getImpl(); - p->draw(); - delete p; - \end{cppcode} - \onslide<2> - \begin{cppcode} - struct Drawable { - virtual void draw() = 0; - }; - std::unique_ptr getImpl(); // better API - - auto p = getImpl(); - p->draw(); - \end{cppcode} - \end{overprint} - \begin{block}{} - \begin{itemize} - \item What happens when \cppinline{p} is deleted? - \item What if a class deriving from \cppinline{Drawable} has a destructor? - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Polymorphism and destruction} - \begin{block}{Virtual destructors} - \begin{itemize} - \item We can mark a destructor as \cppinline{virtual} - \item This selects the right destructor based on the runtime type - \end{itemize} - \end{block} - \begin{cppcode} - struct Drawable { - virtual ~Drawable() = default; - virtual void draw() = 0; - }; - Drawable* p = getImpl(); // returns derived obj. - p->draw(); - delete p; // dynamic dispatch to right destructor - \end{cppcode} - \begin{goodpractice}{Virtual destructors} - If you expect users to inherit from your class and override methods (i.e.\ use your class polymorphically), declare its destructor \cppinline{virtual} - \end{goodpractice} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Pure Abstract Class aka Interface} - \begin{block}{Definition of pure abstract class} - \begin{itemize} - \item a class that has - \begin{itemize} - \item no data members - \item all its methods pure virtual - \item a \cppinline{virtual} destructor - \end{itemize} - \item the equivalent of an Interface in Java - \end{itemize} - \end{block} - \begin{multicols}{2} - \begin{cppcode*}{} - struct Drawable { - virtual ~Drawable() - = default; - virtual void draw() = 0; - } - \end{cppcode*} - \columnbreak - \center - \begin{tikzpicture}[node distance=1.5cm] - \classbox{Drawable}{ - virtual void draw() = 0; - } - \end{tikzpicture} - \end{multicols} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Overriding overloaded methods} - \begin{block}{Concept} - \begin{itemize} - \item overriding an overloaded method will hide the others - \item unless you inherit them using \cppinline{using} - \end{itemize} - \end{block} - \begin{cppcode*}{} - struct BaseClass { - virtual int foo(std::string); - virtual int foo(int); - }; - struct DerivedClass : BaseClass { - using BaseClass::foo; - int foo(std::string) override; - }; - DerivedClass dc; - dc.foo(4); // error if no using - \end{cppcode*} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Polymorphism} - \begin{exercise}{Polymorphism} - \begin{itemize} - \item go to \texttt{exercises/polymorphism} - \item look at the code - \item open trypoly.cpp - \item create a Pentagon, call its perimeter method - \item create a Hexagon, call its perimeter method - \item create a Hexagon, call its parent's perimeter method - \item retry with virtual methods - \end{itemize} - \end{exercise} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Multiple Inheritance} - \begin{block}{Concept} - \begin{itemize} - \item one class can inherit from multiple parents - \end{itemize} - \end{block} - \begin{multicols}{2} - \begin{tikzpicture}[] - \classbox[]{Polygon}{} - \classbox[below of=Polygon,node distance=1.5cm]{Rectangle}{} - \classbox[right of=Rectangle,node distance=3cm]{Text}{} - \classbox[below right of=Rectangle,node distance=2cm]{TextBox}{} - \draw[very thick,Triangle-] (Polygon) -- (Rectangle); - \draw[very thick,Triangle-] (Rectangle) -- (TextBox); - \draw[very thick,Triangle-] (Text) -- (TextBox); - \end{tikzpicture} - \columnbreak - \vspace{2cm} - \begin{cppcode*}{} - class TextBox : - public Rectangle, Text { - // inherits from both - // publicly from Rectangle - // privately from Text - } - \end{cppcode*} - \end{multicols} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{The diamond shape} - \begin{block}{Definition} - \begin{itemize} - \item situation when one class inherits several times from a given grand parent - \end{itemize} - \end{block} - \begin{alertblock}{Problem} - \begin{itemize} - \item are the members of the grand parent replicated? - \end{itemize} - \end{alertblock} - \vfill - \hspace{2.5cm} - \begin{tikzpicture}[] - \classbox[]{Drawable}{} - \classbox[below left of=Drawable,node distance=2cm]{Rectangle}{} - \classbox[right of=Rectangle,node distance=3cm]{Text}{} - \classbox[below right of=Rectangle,node distance=2cm]{TextBox}{} - \draw[very thick,Triangle-] (Drawable) -- (Rectangle); - \draw[very thick,Triangle-] (Drawable) -- (Text); - \draw[very thick,Triangle-] (Rectangle) -- (TextBox); - \draw[very thick,Triangle-] (Text) -- (TextBox); - \end{tikzpicture} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Virtual inheritance} - \begin{block}{Solution} - \begin{itemize} - \item inheritance can be \cppinline{virtual} or not - \begin{itemize} - \item \cppinline{virtual} inheritance will ``share'' parents - \item standard inheritance will replicate them - \end{itemize} - \item most derived class will call the virtual base class's constructor - \end{itemize} - \begin{cppcode} - class Text : public virtual Drawable {...}; - class Rectangle : public virtual Drawable {...}; - \end{cppcode} - \end{block} - \begin{multicols}{2} - \begin{tikzpicture}[] - \classbox{Drawable}{} - \classbox[below left of=Drawable,node distance=2cm]{Rectangle}{} - \classbox[right of=Rectangle,node distance=3cm]{Text}{} - \classbox[below right of=Rectangle,node distance=2cm]{TextBox}{} - \draw[very thick,Triangle-] (Drawable) -- node[below,pos=0.35,sloped] {\scriptsize virtual} (Rectangle); - \draw[very thick,Triangle-] (Drawable) -- node[below,pos=0.45,sloped] {\scriptsize virtual} (Text); - \draw[very thick,Triangle-] (Rectangle) -- (TextBox); - \draw[very thick,Triangle-] (Text) -- (TextBox); - \end{tikzpicture} - \columnbreak - \begin{tikzpicture}[] - \classbox[]{Drawable1}{} - \classbox[below of=Drawable1,node distance=1.5cm]{Rectangle}{} - \draw[very thick,Triangle-] (Drawable1) -- (Rectangle); - \classbox[right of=Drawable1,node distance=3cm]{Drawable2}{} - \classbox[below of=Drawable2,node distance=1.5cm]{Text}{} - \draw[very thick,Triangle-] (Drawable2) -- (Text); - \classbox[below right of=Rectangle,node distance=2cm]{TextBox}{} - \draw[very thick,Triangle-] (Rectangle) -- (TextBox); - \draw[very thick,Triangle-] (Text) -- (TextBox); - \end{tikzpicture} - \end{multicols} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Multiple inheritance advice} - \begin{goodpractice}{Avoid multiple inheritance} - \begin{itemize} - \item Except for inheriting from interfaces (=no data members) - \item And for rare special cases - \end{itemize} - - \hspace*{0.05\textwidth}\begin{minipage}{0.9\textwidth} - \begin{alertblock}{Absolutely avoid diamond-shape inheritance} - \begin{itemize} - \item This is a sign that your architecture is not correct - \item In case you are tempted, think twice and change your mind - \end{itemize} - \end{alertblock} - \end{minipage} - \end{goodpractice} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Virtual inheritance} - \begin{exerciseWithShortcut}{Virtual inheritance}{Virtual OO} - \begin{itemize} - \item go to \texttt{exercisescode/virtual\_inheritance} - \item look at the code - \item open trymultiherit.cpp - \item create a TextBox and call draw - \item Fix the code to call both draws by using types - \item retry with virtual inheritance - \end{itemize} - \end{exerciseWithShortcut} -\end{frame} diff --git a/talk/objectorientation/allocations.tex b/talk/objectorientation/allocations.tex deleted file mode 100644 index 94d267ca..00000000 --- a/talk/objectorientation/allocations.tex +++ /dev/null @@ -1,131 +0,0 @@ -\subsection[new]{Allocating objects} - -\begin{frame}[fragile] - \frametitlecpp[98]{Process memory organization} - \begin{block}{4 main areas} - \begin{description} - \item[the code segment] for the machine code of the executable - \item[the data segment] for global variables - \item[the heap] for dynamically allocated variables - \item[the stack] for parameters of functions and local variables - \end{description} - \end{block} - \hspace{2.5cm} - \begin{tikzpicture} - \memorystack[size x=5cm,word size=1,nb blocks=6,addresses=0] - \memorypush{code segment} - \memorypush{data segment} - \memorypush{stack} - \memorypush{...} - \memorypush{...} - \memorypush{heap} - \draw[->] (stack3-1.north) ++(-1cm,0) -- +(0,.3cm); - \draw[->] (stack3-1.north) ++(1cm,0) -- +(0,.3cm); - \draw[->] (stack6-1.south) ++(-1cm,0) -- +(0,-.3cm); - \draw[->] (stack6-1.south) ++(1cm,0) -- +(0,-.3cm); - \end{tikzpicture} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{The Stack} - \begin{block}{Main characteristics} - \begin{itemize} - \item allocation on the stack stays valid for the duration of the current scope. - It is destroyed when it is popped off the stack. - \item memory allocated on the stack is known at compile time and can thus be accessed through a variable. - \item the stack is relatively small, it is not a good idea to allocate large arrays, structures or classes - \item each thread in a process has its own stack - \begin{itemize} - \item allocations on the stack are thus ``thread private'' - \item and do not introduce any thread-safety issues - \end{itemize} - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Object allocation on the stack} - \begin{block}{On the stack} - \begin{itemize} - \item objects are created on variable definition (constructor called) - \item objects are destructed when out of scope (destructor is called) - \end{itemize} - \end{block} - \begin{cppcode} - int f() { - MyFirstClass a{3}; // constructor called - ... - } // destructor called - - int g() { - MyFirstClass a; // default constructor called - ... - } // destructor called - \end{cppcode} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{The Heap} - \begin{block}{Main characteristics} - \begin{itemize} - \item Allocated memory stays allocated until it is specifically deallocated - \begin{itemize} - \item beware memory leaks - \end{itemize} - \item Dynamically allocated memory must be accessed through pointers - \item large arrays, structures, or classes should be allocated here - \item there is a single, shared heap per process - \begin{itemize} - \item allows to share data between threads - \item introduces race conditions and thread-safety issues! - \end{itemize} - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Object allocation on the heap} - \begin{block}{On the heap} - \begin{itemize} - \item objects are created by calling \cppinline{new} (constructor is called) - \item objects are destructed by calling \cppinline{delete} (destructor is called) - \end{itemize} - \end{block} - \begin{cppcode} - int f() { - // default constructor called - MyFirstClass *a = new MyFirstClass; - delete a; // destructor is called - } - int g() { - // constructor called - MyFirstClass *a = new MyFirstClass{3}; - } // memory leak !!! - \end{cppcode} - \begin{goodpractice}[Prefer smart pointer]{Prefer smart pointers over new/delete} - Prefer smart pointers to manage objects (discussed later) - \end{goodpractice} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Array allocation on the heap} - \begin{block}{Arrays on the heap} - \begin{itemize} - \item arrays of objects are created by calling \cppinline{new[]} \\ - default constructor is called for each object of the array - \item arrays of object are destructed by calling \cppinline{delete[]} \\ - destructor is called for each object of the array - \end{itemize} - \end{block} - \begin{cppcode} - int f() { - // default constructor called 10 times - MyFirstClass *a = new MyFirstClass[10]; - ... - delete[] a; // destructor called 10 times - } - \end{cppcode} - \begin{goodpractice}[Prefer containers]{Prefer containers over new-ed arrays} - Prefer containers to manage collections of objects (discussed later) - \end{goodpractice} -\end{frame} diff --git a/talk/objectorientation/constructors.tex b/talk/objectorientation/constructors.tex deleted file mode 100644 index ef990ecc..00000000 --- a/talk/objectorientation/constructors.tex +++ /dev/null @@ -1,339 +0,0 @@ -\subsection[construct]{Constructors/destructors} - -\begin{frame}[fragile] - \frametitlecpp[98]{Class constructors and destructors} - \begin{block}{Concept} - \begin{itemize} - \item special functions called when building/destroying an object - \item a class can have several constructors, but only one destructor - \item the constructors have the same name as the class - \item same for the destructor with a leading \cppinline{~} - \end{itemize} - \end{block} - \begin{multicols}{2} - \begin{cppcode*}{} - class C { - public: - C(); - C(int a); - ~C(); - ... - protected: - int a; - }; - \end{cppcode*} - \columnbreak - \begin{cppcode*}{firstnumber=10} - // note: special notation for - // initialization of members - C::C() : a(0) {} - - C::C(int a) : a(a) {} - - C::~C() {} - \end{cppcode*} - \end{multicols} -\end{frame} - - -\begin{frame}[fragile] - \frametitlecpp[98]{Class constructors and destructors} - \begin{cppcode} - class Vector { - public: - Vector(int n); - ~Vector(); - void setN(int n, int value); - int getN(int n); - private: - int len; - int* data; - }; - Vector::Vector(int n) : len(n) { - data = new int[n]; - } - Vector::~Vector() { - delete[] data; - } - \end{cppcode} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Constructors and inheritance} - \begin{cppcode} - struct First { - int a; - First() {} // leaves a uninitialized - First(int a) : a(a) {} - }; - struct Second : First { - int b; - Second(); - Second(int b); - Second(int a, int b); - }; - Second::Second() : First(), b(0) {} - Second::Second(int b) : b(b) {} // First() implicitly - Second::Second(int a, int b) : First(a), b(b) {} - \end{cppcode} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Copy constructor} - \begin{block}{Concept} - \begin{itemize} - \item special constructor called for replicating an object - \item takes a single parameter of type \cppinline{const &} to class - \item provided by the compiler if not declared by the user - \item in order to forbid copy, use \cppinline{= delete} (see next slides) - \begin{itemize} - \item or private copy constructor with no implementation in \cpp98 - \end{itemize} - \end{itemize} - \end{block} - \pause - \begin{cppcode} - struct C { - C(); - C(const C &other); - }; - \end{cppcode} - \pause - \begin{goodpractice}[Rule of 3/5]{The rule of 3/5 (\cpp98/11) - \href{https://en.cppreference.com/w/cpp/language/rule_of_three}{cppreference}} - if a class needs a custom destructor, a copy/move constructor or a copy/move assignment operator, it should have all three/five. - \end{goodpractice} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Class Constructors and Destructors} - \begin{overprint} - \onslide<1> - \begin{cppcode} - class Vector { - public: - Vector(int n); - Vector(const Vector &other); - ~Vector(); - private: - int len; int* data; - }; - Vector::Vector(int n) : len(n) { - data = new int[n]; - } - - - - - Vector::~Vector() { delete[] data; } - \end{cppcode} - \onslide<2> - \begin{cppcode} - class Vector { - public: - Vector(int n); - Vector(const Vector &other); - ~Vector(); - private: - int len; int* data; - }; - Vector::Vector(int n) : len(n) { - data = new int[n]; - } - Vector::Vector(const Vector &other) : len(other.len) { - data = new int[len]; - std::copy(other.data, other.data + len, data); - } - Vector::~Vector() { delete[] data; } - \end{cppcode} - - \end{overprint} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Explicit unary constructor} - \begin{block}{Concept} - \begin{itemize} - \item A constructor with a single non-default parameter can be used by the compiler for an implicit conversion. - \end{itemize} - \end{block} - \begin{exampleblockGB}{Example}{https://godbolt.org/z/TvqT185fz}{Unary constructor} - \begin{cppcode} - void print(const Vector & v) { - std::cout << "printing v elements...\n"; - } - - int main { - // calls Vector::Vector(int n) to construct a Vector - // then calls print with that Vector - print(3); - }; - \end{cppcode} - \end{exampleblockGB} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Explicit unary constructor} - \begin{block}{Concept} - \begin{itemize} - \item The keyword \cppinline{explicit} forbids such implicit conversions. - \item It is recommended to use it systematically, except in special cases. - \end{itemize} - \end{block} - \begin{cppcode} - class Vector { - public: - explicit Vector(int n); - Vector(const Vector &other); - ~Vector(); - ... - }; - \end{cppcode} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Defaulted Constructor} - \begin{block}{Idea} - \begin{itemize} - \item avoid empty default constructors like \cppinline{ClassName() {}} - \item declare them as \cppinline{= default} - \end{itemize} - \end{block} - \begin{block}{Details} - \begin{itemize} - \item without a user-defined constructor, a default one is provided - \item any user-defined constructor disables the default one - \item but the default one can be requested explicitly - \item rule can be more subtle depending on data members - \end{itemize} - \end{block} - \begin{exampleblock}{Practically} - \begin{cppcode} - Class() = default; // provide default if possible - Class() = delete; // disable default constructor - \end{cppcode} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Delegating constructor} - \begin{block}{Idea} - \begin{itemize} - \item avoid replication of code in several constructors - \item by delegating to another constructor, in the initialization list - \end{itemize} - \end{block} - \begin{exampleblock}{Practically} - \begin{cppcode} - struct Delegate { - int m_i; - explicit Delegate(int i) : m_i(i) { - ... complex initialization ... - } - Delegate() : Delegate(42) {} - }; - \end{cppcode} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Constructor inheritance} - \begin{block}{Idea} - \begin{itemize} - \item avoid having to redeclare parent's constructors - \item by stating that we inherit all parent constructors - \item derived class can add more constructors - \end{itemize} - \end{block} - \begin{exampleblock}{Practically} - \begin{cppcode} - struct Base { - explicit Base(int a); // ctor 1 - }; - struct Derived : Base { - using Base::Base; - Derived(int a, int b); // ctor 2 - }; - Derived d{5}; // calls ctor 1 - Derived d{5, 6}; // calls ctor 2 - \end{cppcode} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Member initialization} - \begin{block}{Idea} - \begin{itemize} - \item avoid redefining same default value for members n times - \item by defining it once at member declaration time - \end{itemize} - \end{block} - \begin{exampleblock}{Practically} - \begin{cppcode} - struct Base { - int a{5}; // or: int a = 5; - Base() = default; - explicit Base(int _a) : a(_a) {} - }; - struct Derived : Base { - int b{6}; - using Base::Base; - }; - Derived d1; // a = 5, b = 6 - Derived d2{7}; // a = 7, b = 6 - \end{cppcode} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Calling constructors} - \begin{block}{After object declaration, arguments within \{\}} - \begin{cppcode*}{} - struct A { - int i; - float f; - A(); - A(int); - A(int, int); - }; - - A a{1,2}; // A::A(int, int) - A a{1}; // A::A(int) - A a{}; // A::A() - A a; // A::A() - A a = {1,2}; // A::A(int, int) - \end{cppcode*} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Calling constructors the old way} - \begin{block}{Arguments are given within (), aka \cpp98 nightmare} - \begin{cppcode*}{} - struct A { - int i; - float f; - A(); - A(int); - A(int, int); - }; - - A a(1,2); // A::A(int, int) - A a(1); // A::A(int) - A a(); // declaration of a function! - A a; // A::A() - A a = (1,2); // A::A(int), comma operator! - A a = {1,2}; // not allowed - \end{cppcode*} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[11]{Constructing arrays and vectors} - \begin{exampleblock}{List of items given within \{\}} - \begin{cppcode*}{firstnumber=10} - int ip[3]{1,2,3}; - int* ip = new int[3]{1,2,3}; // not allowed in C++98 - std::vector v{1,2,3}; // same - \end{cppcode*} - \end{exampleblock} -\end{frame} diff --git a/talk/objectorientation/functors.tex b/talk/objectorientation/functors.tex deleted file mode 100644 index b5b1d115..00000000 --- a/talk/objectorientation/functors.tex +++ /dev/null @@ -1,48 +0,0 @@ -\subsection[()]{Function objects} - -\begin{frame}[fragile] - \frametitlecpp[98]{Function objects} - \begin{block}{Concept} - \begin{itemize} - \item also known as functors (no relation to functors in math) - \item a class that implements \cppinline{operator()} - \item allows to use objects in place of functions - \item with constructors and data members - \end{itemize} - \end{block} - \begin{cppcode} - struct Adder { - int m_increment; - Adder(int increment) : m_increment(increment) {} - int operator()(int a) { return a + m_increment; } - }; - Adder inc1{1}, inc10{10}; - int i = 3; - int j = inc1(i); // 4 - int k = inc10(i); // 13 - int l = Adder{25}(i); // 28 - \end{cppcode} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[20]{Function objects} - \begin{exampleblockGB}{Function objects as function arguments}{https://godbolt.org/z/zxqYG6xzT}{function objects} - \begin{cppcode} - int count_if(const auto& range, auto predicate) { - int count = 0; // ↑ template (later) - for (const auto& e : range) - if (predicate(e)) count++; - return count; - } - struct IsBetween { - int lower, upper; - bool operator()(int value) const { - return lower < value && value < upper; - } - }; - int arr[]{1, 2, 3, 4, 5, 6, 7}; - std::cout << count_if(arr, IsBetween{2, 6}); // 3 - // prefer: std::ranges::count_if - \end{cppcode} - \end{exampleblockGB} -\end{frame} diff --git a/talk/objectorientation/inheritance.tex b/talk/objectorientation/inheritance.tex deleted file mode 100644 index 086909d5..00000000 --- a/talk/objectorientation/inheritance.tex +++ /dev/null @@ -1,291 +0,0 @@ -\subsection[inherit]{Inheritance} - -\begin{frame}[fragile] - \frametitlecpp[98]{First inheritance} - \begin{multicols}{2} - \begin{cppcode*}{} - struct MyFirstClass { - int a; - void squareA() { a *= a; } - }; - struct MySecondClass : - MyFirstClass { - int b; - int sum() { return a + b; } - }; - - MySecondClass myObj2; - myObj2.a = 2; - myObj2.b = 5; - myObj2.squareA(); - int i = myObj2.sum(); // i = 9 - \end{cppcode*} - \columnbreak - \raggedleft - \null \vfill - \begin{overprint}[0.8\columnwidth] - \onslide<1> - \begin{tikzpicture}[node distance=2.5cm] - \classbox{MyFirstClass}{ - int a; \\ - void squareA(); - } - \classbox[below of=MyFirstClass]{MySecondClass}{ - int b; \\ - int sum(); - } - \draw[very thick,-Triangle] (MySecondClass)--(MyFirstClass); - \end{tikzpicture} - \onslide<2> - \begin{tikzpicture} - \memorystack[size x=3cm,word size=1,block size=4,nb blocks=4] - \memorypush{a = 2} - \memorypush{b = 5} - \memorystruct{1}{2}{\tiny myobj2} - \end{tikzpicture} - \end{overprint} - \vfill \null - \end{multicols} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Managing access to class members} - \begin{block}{\texttt{public} / \texttt{private} keywords} - \begin{description} - \item[\texttt{private}] allows access only within the class - \item[\texttt{public}] allows access from anywhere - \end{description} - \begin{itemize} - \item The default for \texttt{class} is \cppinline{private} - \item The default for \texttt{struct} is \cppinline{public} - \end{itemize} - \end{block} - \begin{multicols}{2} - \begin{cppcode*}{} - class MyFirstClass { - public: - void setA(int x); - int getA(); - void squareA(); - private: - int a; - }; - \end{cppcode*} - \columnbreak - \begin{cppcode*}{firstnumber=9} - MyFirstClass obj; - obj.a = 5; // error ! - obj.setA(5); // ok - obj.squareA(); - int b = obj.getA(); - \end{cppcode*} - \pause - \begin{tcolorbox}[left=0mm,right=0mm,top=0mm,bottom=0mm,colback=red!5!white,colframe=red!75!black] - This breaks MySecondClass ! - \end{tcolorbox} - \end{multicols} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Managing access to class members(2)} - \begin{block}{Solution is \texttt{protected} keyword} - Gives access to classes inheriting from base class - \end{block} - \begin{multicols}{2} - \begin{cppcode*}{} - class MyFirstClass { - public: - void setA(int a); - int getA(); - void squareA(); - protected: - int a; - }; - \end{cppcode*} - \columnbreak - \begin{cppcode*}{firstnumber=13} - class MySecondClass : - public MyFirstClass { - public: - int sum() { - return a + b; - } - private: - int b; - }; - \end{cppcode*} - \end{multicols} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Managing inheritance privacy} - \begin{block}{Inheritance can be public, protected or private} - It influences the privacy of inherited members for external code.\\ - The code of the class itself is not affected - \begin{description} - \item[\texttt{public}] privacy of inherited members remains unchanged - \item[\texttt{protected}] inherited public members are seen as protected - \item[\texttt{private}] all inherited members are seen as private \\ - this is the default for classes if nothing is specified - \end{description} - \end{block} - \pause - \begin{block}{Net result for external code} - \begin{itemize} - \item only public members of public inheritance are accessible - \end{itemize} - \end{block} - \begin{block}{Net result for code in derived classes} - \begin{itemize} - \item only public and protected members of public and protected parents are accessible - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Managing inheritance privacy - public} - \begin{multicols}{2} - \begin{tikzpicture}[node distance=3cm] - \classbox{MyFirstClass}{ - private: \\ - \hspace{0.4cm}int priv; \\ - protected: \\ - \hspace{0.4cm}int prot; \\ - public: \\ - \hspace{0.4cm}int pub; - } - \classbox[below of=MyFirstClass]{MySecondClass}{ - void funcSecond(); - } - \classbox[below of=MySecondClass,node distance=1.75cm]{MyThirdClass}{ - void funcThird(); - } - \draw[very thick,-Triangle] (MySecondClass)--(MyFirstClass) node[midway,right] {public}; - \draw[very thick,-Triangle] (MyThirdClass)--(MySecondClass) node[midway,right] {public}; - \end{tikzpicture} - \columnbreak - \begin{cppcode*}{} - void funcSecond() { - int a = priv; // Error - int b = prot; // OK - int c = pub; // OK - } - void funcThird() { - int a = priv; // Error - int b = prot; // OK - int c = pub; // OK - } - void extFunc(MyThirdClass t) { - int a = t.priv; // Error - int b = t.prot; // Error - int c = t.pub; // OK - } - \end{cppcode*} - \end{multicols} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Managing inheritance privacy - protected} - \begin{multicols}{2} - \begin{tikzpicture}[node distance=3cm] - \classbox{MyFirstClass}{ - private: \\ - \hspace{0.4cm}int priv; \\ - protected: \\ - \hspace{0.4cm}int prot; \\ - public: \\ - \hspace{0.4cm}int pub; - } - \classbox[below of=MyFirstClass]{MySecondClass}{ - void funcSecond(); - } - \classbox[below of=MySecondClass,node distance=1.75cm]{MyThirdClass}{ - void funcThird(); - } - \draw[very thick,-Triangle] (MySecondClass)--(MyFirstClass) node[midway,right] {protected}; - \draw[very thick,-Triangle] (MyThirdClass)--(MySecondClass) node[midway,right] {public}; - \end{tikzpicture} - \columnbreak - \begin{cppcode*}{highlightlines=14} - void funcSecond() { - int a = priv; // Error - int b = prot; // OK - int c = pub; // OK - } - void funcThird() { - int a = priv; // Error - int b = prot; // OK - int c = pub; // OK - } - void extFunc(MyThirdClass t) { - int a = t.priv; // Error - int b = t.prot; // Error - int c = t.pub; // Error - } - \end{cppcode*} - \end{multicols} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Managing inheritance privacy - private} - \begin{multicols}{2} - \begin{tikzpicture}[node distance=3cm] - \classbox{MyFirstClass}{ - private: \\ - \hspace{0.4cm}int priv; \\ - protected: \\ - \hspace{0.4cm}int prot; \\ - public: \\ - \hspace{0.4cm}int pub; - } - \classbox[below of=MyFirstClass]{MySecondClass}{ - void funcSecond(); - } - \classbox[below of=MySecondClass,node distance=1.75cm]{MyThirdClass}{ - void funcThird(); - } - \draw[very thick,-Triangle] (MySecondClass)--(MyFirstClass) node[midway,right] {private}; - \draw[very thick,-Triangle] (MyThirdClass)--(MySecondClass) node[midway,right] {public}; - \end{tikzpicture} - \columnbreak - \begin{cppcode*}{highlightlines=8-9} - void funcSecond() { - int a = priv; // Error - int b = prot; // OK - int c = pub; // OK - } - void funcThird() { - int a = priv; // Error - int b = prot; // Error - int c = pub; // Error - } - void extFunc(MyThirdClass t) { - int a = t.priv; // Error - int b = t.prot; // Error - int c = t.pub; // Error - } - \end{cppcode*} - \end{multicols} -\end{frame} - -\begin{advanced} -\begin{frame}[fragile] - \frametitlecpp[11]{Final class} - \begin{block}{Idea} - \begin{itemize} - \item make sure you cannot inherit from a given class - \item by declaring it final - \end{itemize} - \end{block} - \begin{exampleblock}{Practically} - \begin{cppcode} - struct Base final { - ... - }; - struct Derived : Base { // compiler error - ... - }; - \end{cppcode} - \end{exampleblock} -\end{frame} -\end{advanced} diff --git a/talk/objectorientation/objectsclasses.tex b/talk/objectorientation/objectsclasses.tex deleted file mode 100644 index 5ab314d7..00000000 --- a/talk/objectorientation/objectsclasses.tex +++ /dev/null @@ -1,156 +0,0 @@ -\subsection[OO]{Objects and Classes} - -\begin{frame}[fragile] - \frametitlecpp[98]{What are classes and objects} - \begin{block}{Classes (or ``user-defined types'')} - C structs on steroids - \begin{itemize} - \item with inheritance - \item with access control - \item including methods (aka.\ member functions) - \end{itemize} - \end{block} - \begin{block}{Objects} - \begin{itemize} - \item instances of classes - \end{itemize} - \end{block} - \begin{block}{A class encapsulates state and behavior of ``something''} - \begin{itemize} - \item shows an interface - \item provides its implementation - \begin{itemize} - \item status, properties - \item possible interactions - \item construction and destruction - \end{itemize} - \end{itemize} - \end{block} -\end{frame} - - -\begin{frame}[fragile] - \frametitlecpp[98]{My first class} - \begin{multicols}{2} - \begin{cppcode*}{} - struct MyFirstClass { - int a; - void squareA() { - a *= a; - } - int sum(int b) { - return a + b; - } - }; - - MyFirstClass myObj; - myObj.a = 2; - - // let's square a - myObj.squareA(); - \end{cppcode*} - \columnbreak - \center - \null \vfill - \begin{tikzpicture} - \classbox{MyFirstClass}{ - int a; \\ - void squareA(); \\ - int sum(int b); - } - \end{tikzpicture} - \vfill \null - \end{multicols} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Separating the interface} - \begin{columns}[t] - \begin{column}{.45\textwidth} - \begin{block}{Header: MyClass.hpp} - \begin{cppcode*}{} - #pragma once - struct MyClass { - int a; - void squareA(); - }; - \end{cppcode*} - \end{block} - \begin{block}{Implementation: MyClass.cpp} - \begin{cppcode*}{} - #include "MyClass.hpp" - void MyClass::squareA() { - a *= a; - } - \end{cppcode*} - \end{block} - \end{column} - \begin{column}{.45\textwidth} - \begin{block}{User 1: main.cpp} - \begin{cppcode*}{} - #include "MyClass.hpp" - int main() { - MyClass mc; - ... - } - \end{cppcode*} - \end{block} - \begin{block}{User 2: fun.cpp} - \begin{cppcode*}{} - #include "MyClass.hpp" - void f(MyClass& mc) { - mc.squareA(); - } - \end{cppcode*} - \end{block} - \end{column} - \end{columns} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Implementing methods} - \begin{goodpractice}{Implementing methods} - \begin{itemize} - \item usually in .cpp, outside of class declaration - \item using the class name as ``namespace'' - \item short member functions can be in the header - \item some functions (templates, \cppinline{constexpr}) must be in the header - \end{itemize} - \end{goodpractice} - \begin{block}{} - \begin{cppcode} - #include "MyFirstClass.hpp" - - void MyFirstClass::squareA() { - a *= a; - } - int MyFirstClass::sum(int b) { - return a + b; - } - \end{cppcode} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Method overloading} - \begin{block}{The rules in \cpp} - \begin{itemize} - \item overloading is authorized and welcome - \item signature is part of the method identity - \item but not the return type - \end{itemize} - \end{block} - \begin{cppcode} - struct MyFirstClass { - int a; - int sum(int b); - int sum(int b, int c); - }; - - int MyFirstClass::sum(int b) { return a + b; } - - int MyFirstClass::sum(int b, int c) { - return a + b + c; - } - \end{cppcode} -\end{frame} diff --git a/talk/objectorientation/operators.tex b/talk/objectorientation/operators.tex deleted file mode 100644 index 0ea892b8..00000000 --- a/talk/objectorientation/operators.tex +++ /dev/null @@ -1,157 +0,0 @@ -\subsection[Op]{Operator overloading} - -\begin{frame}[fragile] - \frametitlecpp[98]{Operator overloading example} - \begin{cppcode} - struct Complex { - float m_real, m_imaginary; - Complex(float real, float imaginary); - Complex operator+(const Complex& other) { - return Complex{m_real + other.m_real, - m_imaginary + other.m_imaginary}; - } - }; - - Complex c1{2, 3}, c2{4, 5}; - Complex c3 = c1 + c2; // (6, 8) - \end{cppcode} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Operator overloading} - \begin{block}{Defining operators for a class} - \begin{itemize} - \item implemented as a regular method - \begin{itemize} - \item \small either inside the class, as a member function - \item or outside the class (not all) - \end{itemize} - \item with a special name (replace @ by operators from below)\small - \end{itemize} - \begin{tabular}{llll} - Expression & As member & As non-member \\ - \hline - @a & (a).operator@() & operator@(a) \\ - a@b & (a).operator@(b) & operator@(a,b) \\ - a=b & (a).operator=(b) & cannot be non-member \\ - a(b...) & (a).operator()(b...) & cannot be non-member \\ - a[b] & (a).operator[](b) & cannot be non-member \\ - a-\textgreater & (a).operator-\textgreater() & cannot be non-member \\ - a@ & (a).operator@(0) & operator@(a,0) \\ - \hline - \end{tabular} - - \small - \begin{cppcode*}{linenos=false} - possible operators: + - * / % ^ & | ~ ! = < > - += -= *= /= %= ^= &= |= << >> >>= <<= - == != <= >= <=> && || ++ -- , ->* -> () [] - \end{cppcode*} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Why have non-member operators?} - \begin{block}{Symmetry} - \begin{cppcode} - struct Complex { - float m_real, m_imaginary; - Complex operator+(float other) { - return Complex{m_real + other, m_imaginary}; - } - }; - Complex c1{2.f, 3.f}; - Complex c2 = c1 + 4.f; // ok - Complex c3 = 4.f + c1; // not ok !! - \end{cppcode} - \pause - \begin{cppcode*}{firstnumber=10} - Complex operator+(float a, const Complex& obj) { - return Complex{a + obj.m_real, obj.m_imaginary}; - } - \end{cppcode*} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Other reason to have non-member operators?} - \begin{block}{Extending existing classes} - \begin{cppcode} - struct Complex { - float m_real, m_imaginary; - Complex(float real, float imaginary); - }; - - std::ostream& operator<<(std::ostream& os, - const Complex& obj) { - os << "(" << obj.m_real << ", " - << obj.m_imaginary << ")"; - return os; - } - Complex c1{2.f, 3.f}; - std::cout << c1 << std::endl; // Prints '(2, 3)' - \end{cppcode} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Chaining operators} - \begin{block}{In general, return a reference to the left value} - \begin{cppcode} - struct Complex { - float m_real, m_imaginary; - Complex& operator=( const Complex& other ) { - m_real = other.m_real; - m_imaginary = other.m_imaginary; - return *this; - } - }; - Complex c1{2.f, 3.f}; - Complex c2, c3; - // right to left associativity - c3 = c2 = c1; - // left to right associativity - std::cout << c1 << c2 << c3 << std::endl; - \end{cppcode} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Friend declarations} - \begin{block}{Concept} - \begin{itemize} - \item Functions/classes can be declared \cppinline{friend} within a class scope - \item They gain access to all private/protected members - \item Useful for operators such as \cppinline{a + b} - \item Don't abuse friends to go around a wrongly designed interface - \item Avoid unexpected modifications of class state in a friend! - \end{itemize} - \end{block} - \begin{exampleblock}{\texttt{operator+} as a friend} - \footnotesize - \begin{cppcode*}{} - class Complex { - float m_r, m_i; - friend Complex operator+(Complex const & a, Complex const & b); - public: - Complex ( float r, float i ) : m_r(r), m_i(i) {} - }; - Complex operator+(Complex const & a, Complex const & b) { - return Complex{ a.m_r+b.m_r, a.m_i+b.m_i }; - } - \end{cppcode*} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Operators} - \begin{exercise}{Operators} - Write a simple class representing a fraction and pass all tests - \begin{itemize} - \item go to \texttt{exercises/operators} - \item look at \texttt{operators.cpp} - \item inspect \cppinline{main} and complete the implementation of \cppinline{class Fraction} step by step - \item you can comment out parts of \cppinline{main} to test in between - \end{itemize} - \end{exercise} -\end{frame} diff --git a/talk/objectorientation/static.tex b/talk/objectorientation/static.tex deleted file mode 100644 index dcc0dd51..00000000 --- a/talk/objectorientation/static.tex +++ /dev/null @@ -1,43 +0,0 @@ -\subsection[static]{Static members} - -\begin{frame}[fragile] - \frametitlecpp[98]{Static members} - \begin{block}{Concept} - \begin{itemize} - \item members attached to a class rather than to an object - \item usable with or without an instance of the class - \item identified by the \cppinline{static} keyword - \end{itemize} - \end{block} - - \vspace{-1\baselineskip} - \begin{overprint} - \onslide<1> - \begin{exampleblock}{Static.hpp} - \begin{cppcode} - class Text { - public: - static std::string upper(std::string); - private: - static int callsToUpper; // add `inline` in C++17 - }; - \end{cppcode} - \end{exampleblock} - - \onslide<2> - \begin{exampleblock}{Static.cpp} - \begin{cppcode} - #include "Static.hpp" - int Text::callsToUpper = 0; // required before C++17 - - std::string Text::upper(std::string lower) { - callsToUpper++; - // convert lower to upper case - // return ...; - } - std::string uppers = Text::upper("my text"); - // now Text::callsToUpper is 1 - \end{cppcode} - \end{exampleblock} - \end{overprint} -\end{frame} diff --git a/talk/objectorientation/typecasting.tex b/talk/objectorientation/typecasting.tex deleted file mode 100644 index 924dba0e..00000000 --- a/talk/objectorientation/typecasting.tex +++ /dev/null @@ -1,80 +0,0 @@ -\subsection[cast]{Type casting} - -\begin{frame} - \frametitlecpp[98]{Type casting} - \begin{block}{5 types of casts in \cpp\ - These 2 should be used} - \begin{itemize} - \item \mintinline{c++}{static_cast(arg)} - \begin{itemize} - \item converts type if the static types allow it - \item including using implicit conversion - \item essentially compile time - \end{itemize} - \item \mintinline{c++}{dynamic_cast(arg)} - \begin{itemize} - \item checks if object at address of ``\mintinline{c++}{arg}'' is convertible to \mintinline{c++}{Target} - \item throws \mintinline{c++}{std::bad_cast} or returns \mintinline{c++}{nullptr} if it's not - \item essentially run time - \end{itemize} - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Type casting example} - \small - \begin{exampleblockGB}{Practically}{https://godbolt.org/z/16faqc64s}{\texttt{casting}} - \begin{cppcode*}{} - struct A{ virtual ~A()=default; } a; - struct B : A {} b; - - A& c = static_cast(b); // OK. b is also an A - B& d = static_cast(a); // UB: a is not a B - B& e = static_cast(c); // OK. c is a B - - B& f = dynamic_cast(c); // OK, c is a B - B& g = dynamic_cast(a); // throws std::bad_cast - B& foo(A& h) { return dynamic_cast(h); } - B& i = foo(c); // OK, c is a B - - B* j = dynamic_cast(&a); // nullptr. a not a B. - if (j != nullptr) { - // Will not reach this - } - \end{cppcode*} - \end{exampleblockGB} -\end{frame} - -\begin{frame}[fragile] - \frametitlecpp[98]{Type casting} - \begin{block}{5 types of casts in \cpp - These 3 should be avoided} - \begin{itemize} - \item \mintinline{c++}{const_cast(arg)} - \begin{itemize} - \item removes (or adds) constness from a type - \item if you think you need this, rather improve your design! - \end{itemize} - \item \mintinline{c++}{reinterpret_cast(arg)} - \begin{itemize} - \item changes type irrespective of what `arg` is - \item almost never a good idea! - \end{itemize} - \item C-style: \mintinline{c++}{(Target)arg} - \begin{itemize} - \item Force-changes type in C-style. No checks. Don't use. - \end{itemize} - \end{itemize} - \end{block} - \begin{alertblock}{Casts to avoid} - \scriptsize - \begin{cppcode*}{} - void func(A const & a) { - A& ra = a; // Error: not const - A& ra = const_cast(a); // Compiles. Bad design! - // Evil! Don't do this: - B* b = reinterpret_cast(&a); - B* b = (B*)&a; - } - \end{cppcode*} - \end{alertblock} -\end{frame} diff --git a/talk/python/cppyy.png b/talk/python/cppyy.png deleted file mode 100644 index a8a88163..00000000 Binary files a/talk/python/cppyy.png and /dev/null differ diff --git a/talk/python/cppyy.tex b/talk/python/cppyy.tex deleted file mode 100644 index 3de064c0..00000000 --- a/talk/python/cppyy.tex +++ /dev/null @@ -1,33 +0,0 @@ -\subsection[cppyy]{The cppyy project} - -\begin{frame} - \frametitle{Automatic Python-C++ bindings} - \begin{block}{The {\color{blue!50!white} \href{https://cppyy.readthedocs.io}{cppyy}} project} - \begin{itemize} - \item originated from the ROOT project - \item still young, version 1.0 from Mid 2018 - \item but very active, current version 2.1.0 - \item extremely powerful for interfacing \cpp and python - \end{itemize} - \end{block} - \begin{block}{How it works} - \begin{itemize} - \item uses Just in Time compilation through {\color{blue!50!black} \href{https://github.com/vgvassilev/cling}{cling}} - \begin{itemize} - \item an interactive \cpp interpreter - \end{itemize} - \end{itemize} - \end{block} -\end{frame} - -\begin{frame} - \frametitle{cppyy crash course(1)} - Shamelessly copied from the cppyy documentation - \includegraphics[width=.8\textwidth]{python/cppyy2.png} - \includegraphics[trim={0 3.2cm 0 0},clip,width=\textwidth]{python/cppyy.png} -\end{frame} - -\begin{frame} - \frametitle{cppyy crash course(1)} - \includegraphics[trim={0 0 0 2.45cm},clip,width=\textwidth]{python/cppyy.png} -\end{frame} diff --git a/talk/python/cppyy2.png b/talk/python/cppyy2.png deleted file mode 100644 index b2e6817a..00000000 Binary files a/talk/python/cppyy2.png and /dev/null differ diff --git a/talk/python/ctypes.tex b/talk/python/ctypes.tex deleted file mode 100644 index 296f956b..00000000 --- a/talk/python/ctypes.tex +++ /dev/null @@ -1,55 +0,0 @@ -\subsection[ctypes]{The ctypes module} - -\begin{frame}[fragile] - \frametitle{The ctypes python module} - \begin{block}{From the documentation} - \begin{itemize} - \item provides C compatible data types - \item allows calling functions in DLLs or shared libraries - \item can be used to wrap these libraries in pure Python - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitle{ctypes: usage example} - \begin{block}{\cpp code : mandel.hpp} - \begin{cppcode*}{} - int mandel(Complex const & a); - \end{cppcode*} - \end{block} - \begin{block}{``C'' code : mandel\_cwrapper.hpp} - \begin{cppcode*}{} - extern "C" { - int mandel(float r, float i) { - return mandel(Complex(r, i)); - }; - } - \end{cppcode*} - \end{block} - \begin{exampleblock}{calling the mandel library} - \begin{minted}{python} - from ctypes import * - libmandel = CDLL('libmandelc.so') - v = libmandel.mandel(c_float(0.3), c_float(1.2)) - \end{minted} - \end{exampleblock} -\end{frame} - -\begin{frame} - \frametitle{Marrying \cpp and python} - \begin{exercise}{\cpp and python} - \begin{itemize} - \item go to \texttt{exercises/python} - \item look at the original python code mandel.py - \item time it (`time python3 mandel.py`) - \item look at the code in mandel.hpp/cpp - \item look at the python module mandel\_module.cpp - \item compile and modify mandel.py to use it - \item see the gain in time - \item look at the C wrapper in mandel\_cwrapper.cpp - \item modify mandel.py to use libmandelc directly with ctypes - \end{itemize} - \end{exercise} - \tiny Note : you may have to add '.' to LD\_LIBRARY\_PATH and PYTHONPATH -\end{frame} diff --git a/talk/python/marryingcandcpp.tex b/talk/python/marryingcandcpp.tex deleted file mode 100644 index c27bf7a1..00000000 --- a/talk/python/marryingcandcpp.tex +++ /dev/null @@ -1,80 +0,0 @@ -\subsection[C]{Marrying \cpp and C} - -\begin{frame}[fragile] - \frametitle{A question of mangling} - \begin{block}{Mangling} - the act of converting the name of variable or function to a symbol name in the binary code - \end{block} - \begin{block}{C versus \cpp symbol names} - \begin{itemize} - \item C uses bare function name - \item \cpp allows overloading of functions by taking the signature into account - \item so \cpp mangling has to contain signature - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitle{C mangling} - \begin{exampleblock}{Source : file.c} - \begin{cppcode*}{} - float sum(float a, float b); - int square(int a); - // won't compile : conflicting types for ‘square’ - // float square(float a); - \end{cppcode*} - \end{exampleblock} - \begin{block}{Binary symbols : file.o} - \begin{minted}{shell} - # nm file.o - 000000000000001a T square - 0000000000000000 T sum - \end{minted} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitle{\cpp mangling} - \begin{exampleblock}{Source : file.cpp} - \begin{cppcode*}{} - float sum(float a, float b); - int square(int a); - // ok, signature is different - float square(float a); - \end{cppcode*} - \end{exampleblock} - \begin{block}{Binary symbols : file.o} - \begin{minted}{shell} - # nm file.o - 0000000000000000 T _Z3sumff - 000000000000002a T _Z6squaref - 000000000000001a T _Z6squarei - \end{minted} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Forcing C mangling in \cpp} - \begin{block}{extern ``C''} - These functions will use C mangling : - \begin{cppcode*}{} - extern "C" { - float sum(float a, float b); - int square(int a); - } - \end{cppcode*} - \end{block} - \pause - You can now call these \cpp functions from C code - \pause - \begin{alertblock}{Limitations} - \begin{itemize} - \item no \cpp types should go out - \item no exceptions either (use \cppinline{noexcept} here) - \item member functions cannot be used - \begin{itemize} - \item they need to be wrapped one by one - \end{itemize} - \end{itemize} - \end{alertblock} -\end{frame} diff --git a/talk/python/modulewriting.tex b/talk/python/modulewriting.tex deleted file mode 100644 index 1b78fcd8..00000000 --- a/talk/python/modulewriting.tex +++ /dev/null @@ -1,69 +0,0 @@ -\subsection[module]{Writing a module} - -\begin{frame}[fragile] - \frametitle{How to build a python 3 module around \cpp code} - \begin{block}{\cpp code : mandel.hpp} - \begin{cppcode*}{} - int mandel(Complex const & a); - \end{cppcode*} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Basic Module(1): wrap your method} - \begin{block}{mandelModule.cpp - see exercises/python exercise} - \begin{cppcode*}{} - #include - #include "mandel.hpp" - PyObject * mandel_wrapper(PyObject * self, - PyObject * args) { - // Parse Input - float r, i; - if (!PyArg_ParseTuple(args, "ff", &r, &i)) - return nullptr; - // Call C++ function - int result = mandel(Complex(r, i)); - // Build returned objects - return PyLong_FromLong(result); - } - \end{cppcode*} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Basic Module(2): create the python module} - \begin{block}{mandelModule.cpp - see exercises/python exercise} - \begin{cppcode*}{} - // declare the modules' methods - PyMethodDef mandelMethods[] = { - {"mandel", mandel_wrapper, METH_VARARGS, - "computes nb of iterations for mandelbrot set"}, - {nullptr, nullptr, 0, nullptr} - }; - // declare the module - struct PyModuleDef mandelModule = { - PyModuleDef_HEAD_INIT, - "mandel", nullptr, -1, mandelMethods - }; - PyMODINIT_FUNC PyInit_mandel() { - return PyModule_Create(&mandelModule); - } - \end{cppcode*} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Basic Module(3): use it} - \begin{block}{First compile the module} - \begin{itemize} - \item as a regular shared library - \item with '\mintinline{bash}{-I \$(PYTHON\_INCLUDE)}' - \end{itemize} - \end{block} - \begin{block}{mandel.py - see exercises/python exercise} - \begin{minted}{python} - from mandel import mandel - v = mandel(0.7, 1.2) - \end{minted} - \end{block} -\end{frame} diff --git a/talk/setup.tex b/talk/setup.tex deleted file mode 100644 index 3e1e918c..00000000 --- a/talk/setup.tex +++ /dev/null @@ -1,434 +0,0 @@ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% Improvement on the default split theme : added line numbers % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%%%%%%%%%%%%%%% -% Main colors % -%%%%%%%%%%%%%%% - -\setbeamercolor{frametitle}{fg=white} -\setbeamercolor{frametitle right}{fg=white} -\setbeamercolor{structure}{fg=beamer@blendedblue} % this should be the default anyway, but make sure, since we change it between basic/advanced slides -\setbeamercolor{goodpractice head}{fg=white,bg=orange!85!black} -\setbeamercolor{goodpractice body}{fg=black,bg=orange!25} - -%%%%%%%%%%%%%%%%%%%%%%%%% -% headline and footline % -%%%%%%%%%%%%%%%%%%%%%%%%% - -\defbeamertemplate*{footline}{mysplit theme} -{% - \leavevmode% - \hbox{\begin{beamercolorbox}[wd=.5\paperwidth,ht=2.5ex,dp=1.125ex,leftskip=.3cm plus1fill,rightskip=.3cm]{author in head/foot}% - \usebeamerfont{author in head/foot}\insertshortauthor% - \end{beamercolorbox}% - \begin{beamercolorbox}[wd=.4\paperwidth,ht=2.5ex,dp=1.125ex,leftskip=.3cm,rightskip=.3cm plus1fil]{title in head/foot}% - \usebeamerfont{title in head/foot}\insertshorttitle% - \end{beamercolorbox}}% - \begin{beamercolorbox}[wd=.1\paperwidth,ht=2.5ex,dp=1.125ex,leftskip=.1cm plus1fill,rightskip=.1cm]{date in head/foot}% - \usebeamerfont{date in head/foot} \insertframenumber{} / \inserttotalframenumber% - \end{beamercolorbox}% - \vskip0pt% -} - -\defbeamertemplate*{headline}{mysplit theme} -{% - \leavevmode% - \begin{beamercolorbox}[wd=.4\paperwidth,ht=2.5ex,dp=1.125ex]{section in head/foot}% - \insertsectionnavigationhorizontal{.4\paperwidth}{\hskip0pt plus1filll}{}% - \end{beamercolorbox}% - \begin{beamercolorbox}[wd=.6\paperwidth,ht=2.5ex,dp=1.125ex]{subsection in head/foot}% - \insertsubsectionnavigationhorizontal{.6\paperwidth}{}{\hskip0pt plus1filll}% - \end{beamercolorbox}% -} - -%%%%%%%%%%%% -% packages % -%%%%%%%%%%%% - -\usepackage{morewrites} -\usepackage[utf8]{inputenc} -\usepackage{newunicodechar} -\usepackage{minted} -\newminted{tex}{linenos,gobble=4} -\newminted{cpp}{autogobble,linenos} -\newminted{shell-session}{autogobble} -\newminted[makefile]{shell-session}{autogobble} -\newminted{python}{linenos=true,autogobble} -\newmintinline[cppinline]{cpp}{} - -\usepackage{fancyvrb} -\newcommand*{\fvtextcolor}[2]{\textcolor{#1}{#2}} - -\usepackage{pgf} -\usepackage{pgffor} -\usepackage{tikz} -\usetikzlibrary{arrows,arrows.meta,automata,positioning,snakes,shapes} - -\usepackage{tcolorbox} - -\usepackage[framemethod=TikZ]{mdframed} -\mdfdefinestyle{simplebox}{roundcorner=4pt,linewidth=0,backgroundcolor=blue!50!black,fontcolor=white} - -\usepackage{multicol} -\usepackage{tikz-uml} - -\usepackage{booktabs} -\usepackage{comment} -\usepackage{totcount} -\usepackage{xspace} - -% Use C++Course.cut for output so it's cleaned by latexmk -\def\DefaultCutFileName{\def\CommentCutFile{\jobname.cut}} -\DefaultCutFileName - -%%%%%%%%%%%%%%%%%%% -% useful commands % -%%%%%%%%%%%%%%%%%%% -\newcommand{\cpp}{C$^{++}$\xspace} -\newcommand{\deprecated}{\textcolor{red}{\bf Deprecated}} -\newcommand{\removed}{\textcolor{red}{\bf Removed}} - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% boxes with good practices % -% Use \begin{goodpractice}{Title} to create one % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\makeatletter -\newcommand\listofgoodpractices{% - \addtocontents{lgp}{\end{enumerate}} - \scriptsize - \begin{multicols}{2} - \@starttoc{lgp}% - \end{multicols} -} -\AtBeginDocument{ \addtocontents{lgp}{\begin{enumerate} } } - -\newcounter{gp@counter} -\def\gp@lasttitle{None} - -\newenvironment{goodpracticeWithShortcut}[2] -{% - % Generate an entry in the index of good practices. In case of slide overlays, we only generate - % an entry for the first slide of the overlay set by saving the last title of the - % good practice box. - \ifthenelse{\equal{\gp@lasttitle}{#1}}{}{% - \hypertarget<1>{goodpractice.\thegp@counter}{} - \addtocontents{lgp}{\protect\item \protect\hyperlink{goodpractice.\thegp@counter}{#2\protect\hfill\insertframenumber}} - \stepcounter{gp@counter} - \gdef\gp@lasttitle{#1} - } - % The box that shows up on the slide - \begin{beamerboxesrounded}[upper=goodpractice head,lower=goodpractice body,shadow=true]{Good practice: #1} -}% -{% - \end{beamerboxesrounded} -} -\newenvironment{goodpractice}[2][] -{% - \ifthenelse{\equal{#1}{}}% - { \begin{goodpracticeWithShortcut}{#2}{#2} } - { \begin{goodpracticeWithShortcut}{#2}{#1} } -}% -{% - \end{goodpracticeWithShortcut} -} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% boxes with exercises % -% Use \begin{exercise}{Title} to create one % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\newcommand\listofexercises{% - \addtocontents{lex}{\end{enumerate}} - \scriptsize - \begin{multicols}{3} - \@starttoc{lex}% - \end{multicols} -} -\AtBeginDocument{ \addtocontents{lex}{\begin{enumerate} } } - -\newcounter{ex@counter} -\regtotcounter{ex@counter} - -\newenvironment{exerciseWithShortcut}[2] -{% - \hypertarget<1>{exercise.\theex@counter}{} - \addtocontents{lex}{\protect\item \protect\hyperlink{exercise.\theex@counter}{#2\protect\hfill\insertframenumber}} - \stepcounter{ex@counter} - % The box that shows up on the slide - \begin{alertblock}{Exercise: #1} -}% -{% - \end{alertblock} -} -\newenvironment{exercise}[1] -{% - \begin{exerciseWithShortcut}{#1}{#1} -}% -{% - \end{exerciseWithShortcut} -} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% frametitle with C++ version % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% Switch designs for advanced and essentials course: -\newif\ifisAdvancedSlide\isAdvancedSlidefalse -% Use as \frametitlecpp[14]{Title} -\newcommand\frametitlecpp[2][98]{ - \ifisAdvancedSlide - \frametitle{#2 \hfill \cpp#1 \small Adv} - \else - \frametitle{#2 \hfill \cpp#1} - \fi -} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% easy links to godbolt and cppinsight % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\newcommand\listofgodbolt{% - \addtocontents{lgb}{\end{enumerate}} - \scriptsize - \begin{multicols}{2} - \@starttoc{lgb}% - \end{multicols} -} -\AtBeginDocument{ \addtocontents{lgb}{\begin{enumerate} } } - -\newcounter{gb@counter} -\regtotcounter{gb@counter} -\resetcounteronoverlays{gb@counter} -\newcommand*{\overlaynumber}{\number\beamer@slideinframe} - -% Use as \godboltLink{url} -\newcommand\godboltLink[2]{% - \href{#1}{\color{blue!50!white} godbolt}% - \ifnum \overlaynumber=1% - \hypertarget<1>{godbolt.\thegb@counter}{} - \addtocontents{lgb}{\protect\item \protect\hyperlink{godbolt.\thegb@counter}{#2 - \href{#1}{godbolt}\protect\hfill\insertframenumber}}% - \stepcounter{gb@counter}% - \fi -} - -% Use as \begin{exampleblockGB}{}{<godbolt link>}{<title in index>} -\newenvironment{exampleblockGB}[3] -{% - \begin{exampleblock}{#1 - \godboltLink{#2}{#3}} -}% -{% - \end{exampleblock} -} - -% Use as \cppinsightLink{url} -\newcommand\cppinsightLink[1]{% - \href{#1}{\color{blue!50!white} cppinsight}% -} -% Use as \cppinsightLink{url} -\newcommand\cpprefLink[1]{% - \href{#1}{\color{blue!50!white} cppreference}% -} - -% Use as \youtubechannel{channelname} -\newcommand\youtubechannel[1]{% - \mbox{\href{https://www.youtube.com/c/#1}{\color{red!10!black}\raisebox{-0.1em}{\includegraphics[height=0.8em]{youtube}}\ #1}}% -} - -% Use as \youtubeuser{username} -\newcommand\youtubeuser[1]{% - \mbox{\href{https://www.youtube.com/user/#1}{\color{red!10!black}\raisebox{-0.1em}{\includegraphics[height=0.8em]{youtube}}\ #1}}% -} - -\makeatother - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% easy class diagrams in tikz % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\newcommand\classbox[3][]{ - \def\temp{#3} - \ifx\temp\empty - \draw[thick] node (#2) [#1] - [rectangle,rounded corners,draw] {#2}; - \else - \draw[thick] node (#2) [#1] - [rectangle,rounded corners,draw] { - \begin{tabular}{l} - \multicolumn{1}{c}{#2} \\ - \hline - #3 - \end{tabular} - }; - \fi -} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% easy memory stack diagrams in tikz % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\newcounter{memorystackindex} - -\pgfkeys{ - memorystack/.is family, - memorystack, - size x/.initial=4cm, - size y/.initial=.5cm, - word size/.initial=4, - block size/.initial=1, - nb blocks/.initial=8, - base address/.initial=12288, - color/.initial=black, - addresses/.initial=1 -} - -\makeatletter - -\newcommand\memorystackset[1]{\pgfkeys{memorystack,#1}} -\newcommand\memorystack[1][]{ - \memorystackset{#1, - size x/.get=\stacksizex, - size y/.get=\stacksizey, - word size/.get=\stackwordsize, - block size/.get=\blocksize, - nb blocks/.get=\stacknbblocks, - base address/.get=\stackbaseaddr, - color/.get=\stackcolor, - addresses/.get=\displayaddrs - } - \draw[thick,\stackcolor,text=white] node (title) - at (\stacksizex/2, \stacknbblocks*\stacksizey+.5cm) - [rectangle,rounded corners,fill=blue!50!black] {Memory layout}; - \setcounter{memorystackindex}{1} - \draw[thick,\stackcolor] (0,0) rectangle (\stacksizex,\stacknbblocks*\stacksizey); - \pgfmathsetmacro{\nbbars}{\stacknbblocks-1} - \pgfmathtruncatemacro\nbbarstrunc{\nbbars} - \ifnum\nbbarstrunc>0 - \foreach \n in {1,...,\nbbarstrunc} { - \draw[\stackcolor!70] (0,\n*\stacksizey) -- +(\stacksizex,0); - } - \fi - \foreach \n in {1,...,\stacknbblocks} { - \foreach \p in {1,...,\stackwordsize} { - \draw node (stack\n-\p) - at (\stacksizex/\stackwordsize*\p-\stacksizex/\stackwordsize/2,\n*\stacksizey-\stacksizey/2) - [rectangle,minimum width=\stacksizex,minimum height=\stacksizey] {}; - } - \ifnum1=\displayaddrs\relax - \pgfmathparse{(\n-1)*\blocksize*\stackwordsize+\stackbaseaddr} - \pgfmathtruncatemacro\addressdec{\pgfmathresult} - \pgfmathdectoBase\hexversion{\addressdec}{16} - \draw node at (\stacksizex,\n*\stacksizey-\stacksizey/2) [right=2pt] - {0x\hexversion}; - \fi - } - \pgfmathsetmacro{\nbseps}{\stackwordsize-1} - \pgfmathtruncatemacro\nbsepstrunc{\nbseps} - \ifnum\nbsepstrunc>0 - \foreach \n in {1,...,\nbsepstrunc} { - \draw[\stackcolor!10] (\stacksizex/\stackwordsize*\n,0) -- +(0,\stacknbblocks*\stacksizey); - } - \fi -} - -\newcommand\memorypushvalue[3]{ - \draw node at (stack#1-#2) {#3}; -} - -\newcommand\memorypushwidevalue[1]{ - \memorystackset{ - size x/.get=\stacksizex, - size y/.get=\stacksizey, - } - \draw node (content) at (\stacksizex/2,\value{memorystackindex}*\stacksizey-\stacksizey/2) {#1}; - \draw[\stackcolor!80,->] (content) -- (.2cm,\value{memorystackindex}*\stacksizey-\stacksizey/2); - \draw[\stackcolor!80,->] (content) -- (\stacksizex-.2cm,\value{memorystackindex}*\stacksizey-\stacksizey/2); - \addtocounter{memorystackindex}{1} -} - -\newcommand\memorypushhalfvalue[1]{ - \memorystackset{ - size x/.get=\stacksizex, - size y/.get=\stacksizey, - } - \draw node (content) at (\stacksizex/4,\value{memorystackindex}*\stacksizey-\stacksizey/2) {#1}; - \draw[\stackcolor!80,->] (content) -- (.2cm,\value{memorystackindex}*\stacksizey-\stacksizey/2); - \draw[\stackcolor!80,->] (content) -- (\stacksizex/2-.2cm,\value{memorystackindex}*\stacksizey-\stacksizey/2); - \addtocounter{memorystackindex}{1} -} - -\newcounter{localcount} -\newcommand\memorypush[1]{ - \memorystackset{ - word size/.get=\stackwordsize, - nb blocks/.get=\stacknbblocks - } - \count@=0 - \setcounter{localcount}{1} - \@for\v:=#1\do{ - \ifnum\count@<\stackwordsize - \advance\count@ 1 - \memorypushvalue{\arabic{memorystackindex}}{\arabic{localcount}}{\v} - \fi - \addtocounter{localcount}{1} - } - \addtocounter{memorystackindex}{1} -} - -\newcommand\memorypushpointer[2][]{ - \memorystackset{ - word size/.get=\stackwordsize, - base address/.get=\stackbaseaddr, - block size/.get=\blocksize, - } - \pgfmathparse{(#2-1)*\stackwordsize*\blocksize+\stackbaseaddr} - \pgfmathtruncatemacro\addressdec{\pgfmathresult} - \pgfmathdectoBase\hexaddress{\addressdec}{16} - \memorypushvalue{\arabic{memorystackindex}}{1}{#1 0x\hexaddress} - \draw[\stackcolor!80,->] (stack\arabic{memorystackindex}-1.west) .. controls +(left:1) and +(left:1) .. (stack#2-1.west); - \addtocounter{memorystackindex}{1} -} - -\newcommand\memorystruct[3]{ - \memorystackset{ - size y/.get=\stacksizey - } - \draw[snake=brace,thick] (-2pt,#1*\stacksizey-\stacksizey+2pt) -- (-2pt,#2*\stacksizey-2pt) - node [midway, above, sloped] {#3}; -} - -\newcommand\memorygoto[1]{ - \setcounter{memorystackindex}{#1} -} -\makeatother - -%%%%%%%%%%%%%%%%%% -% Document setup % -%%%%%%%%%%%%%%%%%% - -\title{HEP \cpp course} -\author[D. Chamont, B. Gruber, S. Hageboeck, S. Ponce]{D.Chamont, B. Gruber, S. Hageboeck, S. Ponce \\ \texttt{sebastien.ponce@cern.ch}} -\institute{CERN} -\date{\today} -\pgfdeclareimage[height=0.5cm]{cernlogo}{CERN-logo.jpg} -\logo{\pgfuseimage{cernlogo}} - -\AtBeginSection[] { - \begin{frame}<beamer> - \frametitle{\insertsection} - \begin{multicols}{2} - \tableofcontents[sectionstyle=show/shaded,subsectionstyle=show/show/hide] - \end{multicols} - \end{frame} -} - -\AtBeginSubsection[] { - \begin{frame}<beamer> - \frametitle{\insertsubsection} - \tableofcontents[sectionstyle=show/hide,subsectionstyle=show/shaded/hide] - \end{frame} -} - -\hypersetup{ - colorlinks=true, - allcolors=., - urlcolor={blue!80!white} -} diff --git a/talk/tikz-uml.sty b/talk/tikz-uml.sty deleted file mode 100644 index 2ea87dfd..00000000 --- a/talk/tikz-uml.sty +++ /dev/null @@ -1,4429 +0,0 @@ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% Start of tikz-uml.sty -% -% Some macros for UML Diagrams. -% Home page of project : -% Author: Nicolas Kielbasiewicz -% Style from : -% Fixed by Nicolas Kielbasiewicz (nicolas.kielbasiewicz@ensta-paristech.fr) in dec 2010 to compile with pgf 2.00 -%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\NeedsTeXFormat{LaTeX2e}[1995/12/01]% -\ProvidesPackage{tikz-uml}[2011/01/26]% - -\RequirePackage{ifthen}% -\RequirePackage{tikz}% -\RequirePackage{xstring}% -\RequirePackage{calc}% -\RequirePackage{pgfopts}% -\usetikzlibrary{backgrounds,arrows,shapes,fit,shadows,decorations.markings}% - -\def\tikzumlPackageLayersNum{3}% -\pgfkeys{/tikzuml/options/.cd, packageLayers/.initial=3}% -\pgfkeys{/tikzuml/options/.cd, packageLayers/.store in=\tikzumlPackageLayersNum}% -\def\tikzumlStateLayersNum{3}% -\pgfkeys{/tikzuml/options/.cd, stateLayers/.initial=3}% -\pgfkeys{/tikzuml/options/.cd, stateLayers/.store in=\tikzumlStateLayersNum}% -\def\tikzumlFragmentLayersNum{3}% -\pgfkeys{/tikzuml/options/.cd, fragmentLayers/.initial=3}% -\pgfkeys{/tikzuml/options/.cd, fragmentLayers/.store in=\tikzumlFragmentLayersNum}% -\def\tikzumlComponentLayersNum{3}% -\pgfkeys{/tikzuml/options/.cd, componentLayers/.initial=3}% -\pgfkeys{/tikzuml/options/.cd, componentLayers/.store in=\tikzumlComponentLayersNum}% - -\ProcessPgfOptions{/tikzuml/options}% - -\def\pgfsetlayersArg{background}% -\pgfdeclarelayer{background}% -\newcounter{tikzumlPackageLayers}% -\loop \pgfdeclarelayer{package\thetikzumlPackageLayers}% - \xdef\pgfsetlayersArg{\pgfsetlayersArg,package\thetikzumlPackageLayers}% - \ifnum\tikzumlPackageLayersNum>\thetikzumlPackageLayers% - \stepcounter{tikzumlPackageLayers}% -\repeat% -% -\newcounter{tikzumlFragmentLayers}% -\loop \pgfdeclarelayer{fragment\thetikzumlFragmentLayers}% - \xdef\pgfsetlayersArg{\pgfsetlayersArg,fragment\thetikzumlFragmentLayers}% - \ifnum\tikzumlFragmentLayersNum>\thetikzumlFragmentLayers% - \stepcounter{tikzumlFragmentLayers}% -\repeat% -% -\newcounter{tikzumlStateLayers}% -\loop \pgfdeclarelayer{state\thetikzumlStateLayers}% - \xdef\pgfsetlayersArg{\pgfsetlayersArg,state\thetikzumlStateLayers}% - \ifnum\tikzumlStateLayersNum>\thetikzumlStateLayers% - \stepcounter{tikzumlStateLayers}% -\repeat% -% -\newcounter{tikzumlComponentLayers}% -\loop \pgfdeclarelayer{component\thetikzumlComponentLayers}% - \xdef\pgfsetlayersArg{\pgfsetlayersArg,component\thetikzumlComponentLayers}% - \ifnum\tikzumlComponentLayersNum>\thetikzumlComponentLayers% - \stepcounter{tikzumlComponentLayers}% -\repeat% -% -\pgfdeclarelayer{lifelines}% -\pgfdeclarelayer{activity}% -\pgfdeclarelayer{connections}% -\xdef\pgfsetlayersArg{\pgfsetlayersArg,lifelines,activity,connections,main}% -\pgfsetlayers{\pgfsetlayersArg}% - -\pgfkeys{/tikzuml/.cd,% - text/.initial=black, draw/.initial=black, font/.initial=\small,% - fill class/.initial=yellow!20, fill template/.initial=yellow!2,% - fill package/.initial=blue!20, fill note/.initial=green!20,% - fill usecase/.initial=blue!20, fill system/.initial=white,% - fill state/.initial=yellow!20, fill object/.initial=yellow!20,% - fill call/.initial=white, fill fragment/.initial= none,% - fill component/.initial= yellow!20, fill port/.initial= yellow!20,% - fill assembly connector/.initial= white,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \errmessage{TIKZUML ERROR : in tikzuml global, invalid option \keyname}% - }}% -\pgfkeys{/tikzuml/.cd,% - text/.get=\tikzumltextcolor, draw/.get=\tikzumldrawcolor, font/.get=\tikzumlfont,% - fill class/.get=\tikzumlfillclasscolor,% - fill template/.get=\tikzumlfilltemplatecolor,% - fill package/.get=\tikzumlfillpackagecolor, fill note/.get=\tikzumlfillnotecolor,% - fill usecase/.get=\tikzumlfillusecasecolor,% - fill system/.get=\tikzumlfillsystemcolor,% - fill state/.get=\tikzumlfillstatecolor, fill object/.get=\tikzumlfillobjectcolor,% - fill call/.get=\tikzumlfillcallcolor,% - fill fragment/.get=\tikzumlfillfragmentcolor,% - fill component/.get=\tikzumlfillcomponentcolor,% - fill port/.get=\tikzumlfillportcolor,% - fill assembly connector/.get=\tikzumlfillassemblyconnectorcolor}% - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% class diagrams % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\pgfkeys{/tikzuml/relation/.cd,% - attr1/.style args={#1|#2}{arg1=#1, mult1=#2},% - attr2/.style args={#1|#2}{arg2=#1, mult2=#2},% - attr/.style args={#1|#2}{arg=#1, mult=#2},% - recursive/.style args={#1|#2|#3}{angle1=#1, angle2=#2, loopsize=#3},% - anchors/.style args={#1 and #2}{anchor1=#1, anchor2=#2},% - recursive direction/.style args={#1 to #2}{recursive direction start=#1, recursive direction end=#2}}% -\pgfkeys{/tikzuml/note/.cd,% - anchors/.style args={#1 and #2}{anchor1=#1, anchor2=#2}}% - -\tikzstyle{tikzuml simpleclass style}=[rectangle, minimum height=2em, node distance=2em]% -\tikzstyle{tikzuml class style}=[rectangle split, rectangle split parts=3, rectangle split part align={center, left, left}, minimum height=2em, node distance=2em]% -\tikzstyle{tikzuml narynode style}=[diamond]% -\tikzstyle{tikzuml template style}=[dashed, inner ysep=0.5em, inner xsep=1ex]% -\tikzstyle{tikzuml control nodes style}=[fill=black, inner sep=1.5pt, circle]% -% -\tikzstyle{tikzuml association style}=[color=\tikzumldrawcolor, -]% -\tikzstyle{tikzuml bidirectional association style}=[color=\tikzumldrawcolor, angle45-angle45]% -\tikzstyle{tikzuml unidirectional association style}=[color=\tikzumldrawcolor, -angle 45]% -\tikzstyle{tikzuml aggregation style}=[color=\tikzumldrawcolor, open diamond-]% -\tikzstyle{tikzuml unidirectional aggregation style}=[color=\tikzumldrawcolor, open diamond-angle 45]% -\tikzstyle{tikzuml composition style}=[color=\tikzumldrawcolor, diamond-]% -\tikzstyle{tikzuml unidirectional composition style}=[color=\tikzumldrawcolor, diamond-angle 45]% -\tikzstyle{tikzuml dependency style}=[color=\tikzumldrawcolor, -angle 45, dashed]% -\tikzstyle{tikzuml import style}=[color=\tikzumldrawcolor, -angle 45, dashed]% -\tikzstyle{tikzuml inherit style}=[color=\tikzumldrawcolor, -open triangle 45]% -\tikzstyle{tikzuml implements style}=[color=\tikzumldrawcolor, -open triangle 45, dashed]% - -\pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, anchors/.style args={#1 and #2}{anchor1=#1, anchor2=#2}}% - -\newcounter{tikzumlPackageClassNum}% -\newcounter{tikzumlPackageSubPackageNum}% -\newcounter{tikzumlRelationNum}% -\setcounter{tikzumlRelationNum}{1}% -\newcounter{tikzumlNoteNum}% -\setcounter{tikzumlNoteNum}{1}% - -\newcounter{pos}% -\newcounter{posT}% -\newcounter{posStereo}% - -\newcounter{tikzumlPackageLevel}% -\setcounter{tikzumlPackageLevel}{0}% - -\newif\ifumlclassSimpleStyle% - -% utility : change default colors -\newcommand{\tikzumlset}[1]{% - \pgfkeys{/tikzuml/.cd,#1}% - \pgfkeys{/tikzuml/.cd,% - text/.get=\tikzumltextcolor, draw/.get=\tikzumldrawcolor,% - font/.get=\tikzumlfont,% - fill class/.get=\tikzumlfillclasscolor,% - fill template/.get=\tikzumlfilltemplatecolor,% - fill package/.get=\tikzumlfillpackagecolor,% - fill note/.get=\tikzumlfillnotecolor,% - fill usecase/.get=\tikzumlfillusecasecolor,% - fill system/.get=\tikzumlfillsystemcolor,% - fill state/.get=\tikzumlfillstatecolor,% - fill object/.get=\tikzumlfillobjectcolor,% - fill call/.get=\tikzumlfillcallcolor,% - fill fragment/.get=\tikzumlfillfragmentcolor,% - fill component/.get=\tikzumlfillcomponentcolor,% - fill port/.get=\tikzumlfillportcolor,% - fill assembly connector/.get=\tikzumlfillassemblyconnectorcolor}% -}% - -% define a point -% arg : node/coordinates of the point -\newcommand{\umlpoint}[1]{% - \begin{pgfonlayer}{connections}% - \node[tikzuml control nodes style] at (#1) {};% - \end{pgfonlayer}% -}% - -\newcommand{\tikzumlskipescape}[3][_]{% -\begingroup% - \def\_{#1}\edef\x{\endgroup% - \def\noexpand\csname #3\endcsname{#2}}\x% -}% - -% define a uml package -% arg : package name -% optional : x, y coordinates of the package -% draw, fill, text colors -\newenvironment{umlpackage}[2][]{% - \pgfkeys{/tikzuml/package/.cd,% - x/.initial=0, y/.initial=0,% - name/.initial=tikzumlEmpty, draw/.initial=\tikzumldrawcolor,% - fill/.initial=\tikzumlfillpackagecolor, text/.initial=\tikzumltextcolor,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \errmessage{TIKZUML ERROR : in umlpackage, invalid option \keyname}% - }}% - \pgfkeys{/tikzuml/package/.cd, #1}% - \pgfkeys{/tikzuml/package/.cd,% - x/.get=\xshift, y/.get=\yshift, name/.get=\tikzumlpackagename,% - draw/.get=\tikzumlpackagedraw, fill/.get=\tikzumlpackagefill,% - text/.get=\tikzumlpackagetext}% - % - \ifnum\thetikzumlPackageLevel>0% - \let\tikzumlPackage@nameold\tikzumlPackage@fitname% - \def\tikzumlPackage@name{#2}% - \begingroup% - \def\_{@}\edef\x{\endgroup% - \def\noexpand\tikzumlPackage@fitname{\tikzumlPackage@name}}\x% - \let\tikzumlPackage@parentold\tikzumlPackage@parent% - \edef\tikzumlPackage@parent{\tikzumlPackage@parentold @@\tikzumlPackage@nameold}% - \else% - \def\tikzumlPackage@parent{}% - \def\tikzumlPackage@name{#2}% - \begingroup% - \def\_{@}\edef\x{\endgroup% - \def\noexpand\tikzumlPackage@fitname{\tikzumlPackage@name}}\x% - \fi% - % - \let\tikzumlPackage@nodeNameold\tikzumlPackage@nodeName% - % - \begingroup% - \def\_{_}\edef\x{\endgroup% - \def\noexpand\tikzumlPackage@nodeName{\tikzumlPackage@name}}\x% - % - \ifthenelse{\equal{\tikzumlpackagename}{tikzumlEmpty}}{}{% - \def\tikzumlPackage@nodeName{\tikzumlpackagename}% - }% - % - \StrSubstitute{\tikzumlPackage@nodeName}{.}{@POINT@}{\tikzumlPackage@nodeName}% - % - \expandafter\gdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{}% - % - \setcounter{tikzumlPackageClassNum}{0}% - \setcounter{tikzumlPackageSubPackageNum}{0}% - \stepcounter{tikzumlPackageLevel}% - % - \begin{scope}[xshift=\xshift cm, yshift=\yshift cm]% -}{% - \addtocounter{tikzumlPackageLevel}{-1}% - \begin{pgfonlayer}{package\thetikzumlPackageLevel}% - % - % if contains no class, one define a fictive node to enable the fit option - \ifnum\c@tikzumlPackageClassNum=0% - \ifnum\c@tikzumlPackageSubPackageNum=0% - \node[inner sep=1.5ex] (\tikzumlPackage@nodeName-root) at (0,0) {\phantom{\tikzumlPackage@nodeName}};% - \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{(\tikzumlPackage@nodeName-root)}% - % - \fi% - \fi% - % - \ifnum\c@tikzumlPackageLevel>0% - \def\tikzumlPackageFitTmp{\csname tikzumlPackageFit\tikzumlPackage@parent\endcsname}% - \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent\endcsname{\tikzumlPackageFitTmp (\tikzumlPackage@nodeName) (\tikzumlPackage@nodeName-caption)}% - \stepcounter{tikzumlPackageSubPackageNum}% - \fi% - % - \node[draw=\tikzumlpackagedraw, fill=\tikzumlpackagefill, text=\tikzumlpackagetext, font=\tikzumlfont, inner sep=1.5ex, fit = \csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname] (\tikzumlPackage@nodeName) {};% - \node[draw=\tikzumlpackagedraw, fill=\tikzumlpackagefill, text=\tikzumlpackagetext, font=\tikzumlfont, minimum height=1.5em, outer ysep=-0.3, anchor=south west] (\tikzumlPackage@nodeName-caption) at (\tikzumlPackage@nodeName.north west) {\tikzumlPackage@name};% - \end{pgfonlayer}% - \end{scope}% -}% - -% shortcut to define an empty package -\newcommand{\umlemptypackage}[2][]{\begin{umlpackage}[#1]{#2} \end{umlpackage}}% - -% define a uml class -% args : name of the class -% attributes of the class -% operations of the class -% optional : x,y coordinates of the class -% width of the class node -% type of class (class, interface, typedef, enum) -% template parameters -% draw, fill, text colors -\newcommand{\umlclass}[4][]{% - \pgfkeys{/tikzuml/class/.cd,% - x/.initial=0, y/.initial=0, width/.initial=10ex, type/.initial=class,% - tags/.initial={}, simple/.is if=umlclassSimpleStyle,% - template/.initial={}, name/.initial={tikzumlEmpty},% - draw/.initial=\tikzumldrawcolor,% - fill template/.initial=\tikzumlfilltemplatecolor,% - fill/.initial=\tikzumlfillclasscolor,% - text/.initial=\tikzumltextcolor,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \errmessage{TIKZUML ERROR : in umlclass, invalid option \keyname}% - }}% - \pgfkeys{/tikzuml/class/.cd,#1}% - \pgfkeys{/tikzuml/class/.cd,% - x/.get=\umlclassX, y/.get=\umlclassY, width/.get=\umlclassMinimumWidth,% - type/.get=\umlclassType, tags/.get=\umlclasstags, template/.get=\umlclassTemplateParam,% - name/.get=\umlclassName,% - draw/.get=\tikzumlclassdraw, fill/.get=\tikzumlclassfill,% - text/.get=\tikzumlclasstext, fill template/.get=\tikzumlclasstemplate}% - % - \ifthenelse{\equal{\umlclassType}{class}\OR\equal{\umlclassType}{abstract}}{% - \def\tikzumlClassType{}% - }{% - \def\tikzumlClassType{\guillemotleft\umlclassType\guillemotright \\}% - }% - % - \ifthenelse{\equal{\umlclasstags}{}}{% - \def\tikzumlClassTags{}% - }{% - \def\tikzumlClassTags{\\ \{\umlclasstags\}}% - }% - % - \ifthenelse{\equal{\umlclassTemplateParam}{}}{% - \def\tikzumlClassVPadding{}% - \def\tikzumlClassHPadding{}% - }{% - \def\tikzumlClassVPadding{\vspace{0.1em} \\}% - \def\tikzumlClassHPadding{\hspace{0.5ex} $ $}% - }% - % - \def\tikzumlClassName{#2}% - % - \begingroup% - \def\_{_}\edef\x{\endgroup% - \def\noexpand\tikzumlClassNodeName{\tikzumlClassName}}\x% - % - \ifthenelse{\equal{\umlclassName}{tikzumlEmpty}}{}{% - \def\tikzumlClassNodeName{\umlclassName}% - }% - % - \StrSubstitute{\tikzumlClassNodeName}{:}{@COLON@}[\tikzumlClassNodeName] - % - \ifthenelse{\equal{\umlclassType}{abstract}}{% - \let\tikzumlClassNameOld\tikzumlClassName% - \def\tikzumlClassName{{\it \tikzumlClassNameOld}}% - }{}% - % - \def\tikzumlClassPos{\umlclassX,\umlclassY}% - \def\tikzumlClassAttributes{#3}% - \def\tikzumlClassOperations{#4}% - % - \ifumlclassSimpleStyle% - \node[tikzuml simpleclass style, draw=\tikzumlclassdraw, fill=\tikzumlclassfill, text=\tikzumlclasstext, font=\tikzumlfont, minimum width=\umlclassMinimumWidth] (\tikzumlClassNodeName) at (\tikzumlClassPos) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}% - };% - \else% - \node[tikzuml class style, draw=\tikzumlclassdraw, fill=\tikzumlclassfill, text=\tikzumlclasstext, font=\tikzumlfont, minimum width=\umlclassMinimumWidth] (\tikzumlClassNodeName) at (\tikzumlClassPos) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}% - \nodepart{second}% - \begin{tabular}{l}% - \tikzumlClassAttributes% - \end{tabular}% - \nodepart{third}% - \begin{tabular}{l}% - \tikzumlClassOperations% - \end{tabular}% - };% - \fi% - % - \ifthenelse{\equal{\umlclassTemplateParam}{}}{}{% - \draw (\tikzumlClassNodeName.north east) node[tikzuml template style, name=\tikzumlClassNodeName-template, draw=\tikzumlclassdraw, fill=\tikzumlclasstemplate, text=\tikzumlclasstext, font=\tikzumlfont] {\umlclassTemplateParam};% - }% - % - % add to fit - \ifnum\c@tikzumlPackageLevel>0% - \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}% - \ifthenelse{\equal{\umlclassTemplateParam}{}}{% - \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlClassNodeName)}% - }{% - \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlClassNodeName) (\tikzumlClassNodeName-template)}% - }% - \stepcounter{tikzumlPackageClassNum}% - \fi% - \ifnum\c@tikzumlComponentLevel>0% - \message{class \tikzumlComponent@parent{} @@@@ \tikzumlComponent@fitname} - \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname}% - \ifthenelse{\equal{\umlclassTemplateParam}{}}{% - \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlClassNodeName)}% - }{% - \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlClassNodeName) (\tikzumlClassNodeName-template)}% - }% - \stepcounter{tikzumlComponentSubComponentNum}% - \fi% -}% - -% shortcuts for interface, enum and typedef environments -\newcommand{\umlabstract}[4][]{\umlclass[type=abstract,#1]{#2}{#3}{#4}}% -\newcommand{\umlinterface}[4][]{\umlclass[type=interface,#1]{#2}{#3}{#4}}% -\newcommand{\umltypedef}[4][]{\umlclass[type=typedef,#1]{#2}{#3}{#4}}% -\newcommand{\umlenum}[4][]{\umlclass[type=enum,#1]{#2}{#3}{#4}}% - -% shortcut to define an empty class -\newcommand{\umlemptyclass}[2][]{\umlclass[#1]{#2}{}{}}% -\newcommand{\umlsimpleclass}[2][]{% - \pgfkeys{/tikzuml/friendrelation/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR : in umlCNfriend, forbidden option stereo}% - }{}% - }}% - \pgfkeys{/tikzuml/friendrelation/.cd, #1}% - \umlemptyclass[simple, #1]{#2}% -}% - -% underline the text for static arg -\newcommand{\umlstatic}[1]{\underline{#1}}% -\newcommand{\umlvirt}[1]{\textit{#1}}% - -% define node for n-ary association -\newcommand{\umlNarynode}[2][]{% - \def\tikzumlNaryNodeAnchor{.north} - \def\tikzumlNaryNodeLabelPos{above} - \pgfkeys{/tikzuml/narynode/.cd,% - x/.initial=0, y/.initial=0, width/.initial=6ex, name/.initial={tikzumlEmpty},% - draw/.initial=\tikzumldrawcolor, fill/.initial=\tikzumlfillclasscolor,% - text/.initial=\tikzumltextcolor,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{above}}{% - \def\tikzumlNaryNodeAnchor{.north}% - \def\tikzumlNaryNodeLabelPos{above}% - }{% - \ifthenelse{\equal{\keyname}{above left}}{% - \def\tikzumlNaryNodeAnchor{.north west}% - \def\tikzumlNaryNodeLabelPos{above left}% - }{% - \ifthenelse{\equal{\keyname}{left}}{% - \def\tikzumlNaryNodeAnchor{.west}% - \def\tikzumlNaryNodeLabelPos{left}% - }{% - \ifthenelse{\equal{\keyname}{below left}}{% - \def\tikzumlNaryNodeAnchor{.south west}% - \def\tikzumlNaryNodeLabelPos{below left}% - }{% - \ifthenelse{\equal{\keyname}{below}}{% - \def\tikzumlNaryNodeAnchor{.south}% - \def\tikzumlNaryNodeLabelPos{below}% - }{% - \ifthenelse{\equal{\keyname}{below right}}{% - \def\tikzumlNaryNodeAnchor{.south east}% - \def\tikzumlNaryNodeLabelPos{below right}% - }{% - \ifthenelse{\equal{\keyname}{right}}{% - \def\tikzumlNaryNodeAnchor{.east}% - \def\tikzumlNaryNodeLabelPos{right}% - }{% - \ifthenelse{\equal{\keyname}{above right}}{% - \def\tikzumlNaryNodeAnchor{.north east}% - \def\tikzumlNaryNodeLabelPos{above right}% - }{% - \errmessage{TIKZUML ERROR : in umlNarynode, invalid option \keyname}% - }% - }% - }% - }% - }% - }% - }% - }% - }}% - \pgfkeys{/tikzuml/narynode/.cd,#1}% - \pgfkeys{/tikzuml/narynode/.cd,% - x/.get=\umlnarynodeX, y/.get=\umlnarynodeY, width/.get=\umlnarynodeMinimumWidth,% - name/.get=\umlnaryName,% - draw/.get=\tikzumlnarynodedraw, fill/.get=\tikzumlnarynodefill,% - text/.get=\tikzumlnarynodetext}% - % - \def\tikzumlNaryName{#2}% - % - \begingroup% - \def\_{_}\edef\x{\endgroup% - \def\noexpand\tikzumlNaryNodeName{\tikzumlNaryName}}\x% - % - \ifthenelse{\equal{\umlnaryName}{tikzumlEmpty}}{}{% - \def\tikzumlNaryNodeName{\umlnaryName}% - }% - % - \StrSubstitute{\tikzumlNaryNodeName}{:}{@COLON@}[\tikzumlNaryNodeName] - % - \def\tikzumlNarynodePos{\umlnarynodeX,\umlnarynodeY}% - % - \node[tikzuml narynode style, draw=\tikzumlnarynodedraw, fill=\tikzumlnarynodefill, text=\tikzumlnarynodetext, font=\tikzumlfont, minimum width=\umlnarynodeMinimumWidth, minimum height=\umlnarynodeMinimumWidth] (\tikzumlNaryNodeName) at (\tikzumlNarynodePos) {};% - \draw (\tikzumlNaryNodeName\tikzumlNaryNodeAnchor) node[\tikzumlNaryNodeLabelPos] {\tikzumlNaryName}; - % - % add to fit - \ifnum\c@tikzumlPackageLevel>0% - \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}% - \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlNaryNodeName)}% - \stepcounter{tikzumlPackageClassNum}% - \fi% -}% - -% main command to define a relation between two classes -% args : src class -% dest class -% optional : geometry of the line -% barycentric weight -% name of the src class type attribute defined by the relation -% multiplicity of the src class type attribute defined by the relation -% position on the relation -% text justification on the relation -% name of the dest class type attribute defined by the relation -% multiplicity of the dest class type attribute defined by the relation -% position on the relation -% anchors on linked classes -% text justification on the relation -% start angle, end angle and size of the relation (only if recursive) -% stereotype of the relation -% style of the relation (association, aggregation, composition, inherit, ...) -\newcommand{\umlrelation}[3][]{% - \pgfkeys{/tikzuml/relation/.cd,% - geometry/.initial=--, weight/.initial=0.5,% - arm1/.initial={auto}, arm2/.initial={auto},% - arg1/.initial={}, arg2/.initial={}, arg/.initial={},% - mult1/.initial={}, mult2/.initial={}, mult/.initial={},% - pos1/.initial=0.2, pos2/.initial=0.8, pos/.initial={tikzumlEmpty},% - align1/.initial={}, align2/.initial={}, align/.initial={},% - anchor1/.initial={tikzumlEmpty}, anchor2/.initial={tikzumlEmpty},% - angle1/.initial=-30, angle2/.initial=30, loopsize/.initial=3em,% - stereo/.initial={}, pos stereo/.initial=0.5,% - style/.initial=->, name/.initial=relation-\thetikzumlRelationNum,% - recursive mode/.initial=default, recursive direction start/.initial=right,% - recursive direction end/.initial=bottom,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{with port}% - \OR\equal{\keyname}{interface}% - \OR\equal{\keyname}{padding}% - \OR\equal{\keyname}{width}% - \OR\equal{\keyname}{first arm}% - \OR\equal{\keyname}{second arm}% - \OR\equal{\keyname}{middle arm}% - \OR\equal{\keyname}{last arm}% - \OR\equal{\keyname}{distance}}{}{% - \errmessage{TIKZUML ERROR : in umlrelation, invalid option \keyname}% - }% - }}% - \pgfkeys{/tikzuml/relation/.cd,#1}% - \pgfkeys{/tikzuml/relation/.cd,% - geometry/.get=\geometry, weight/.get=\weight, arm1/.get=\armO, arm2/.get=\armT,% - arg1/.get=\attrName, arg2/.get=\attrNameTO, arg/.get=\attrNameTT,% - mult1/.get=\multiplicity, mult2/.get=\multiplicityTO, mult/.get=\multiplicityTT,% - pos1/.get=\position, pos2/.get=\positionTO, pos/.get=\positionTT,% - align1/.get=\align, align2/.get=\alignTO, align/.get=\alignTT,% - anchor1/.get=\tikzumlSrcAnchor, anchor2/.get=\tikzumlDestAnchor,% - angle1/.get=\startangle, angle2/.get=\endangle, loopsize/.get=\loopsize,% - stereo/.get=\stereo, pos stereo/.get=\positionStereotype,% - style/.get=\style, name/.get=\relationName,% - recursive mode/.get=\tikzumlrecmode,% - recursive direction start/.get=\tikzumlrecdirstart,% - recursive direction end/.get=\tikzumlrecdirend}% - % - \def\tikzumlSrcClassName{#2}% - % - % managing \_ in class names for node names - \begingroup% - \def\_{_}\edef\x{\endgroup% - \def\noexpand\tikzumlSrcClassNodeName{\tikzumlSrcClassName}}\x% - % - \StrSubstitute{\tikzumlSrcClassNodeName}{:}{@COLON@}[\tikzumlSrcClassNodeName] - % - \def\tikzumlDestClassName{#3}% - \begingroup% - \def\_{_}\edef\x{\endgroup% - \def\noexpand\tikzumlDestClassNodeName{\tikzumlDestClassName}}\x% - % - \StrSubstitute{\tikzumlDestClassNodeName}{:}{@COLON@}[\tikzumlDestClassNodeName] - % - % managing alias keys - \def\attrNameT{\attrNameTO\attrNameTT}% - \def\multiplicityT{\multiplicityTO\multiplicityTT}% - \def\alignT{\alignTO\alignTT}% - \def\posAttrName{}% - \def\posMultiplicity{}% - \def\posAttrNameT{}% - \def\posMultiplicityT{}% - % - \ifthenelse{\equal{\positionTT}{tikzumlEmpty}}{% - \def\positionT{\positionTO}% - }{% - \def\positionT{\positionTT}% - }% - % - \def\attrAlign{}% - \def\multAlign{}% - \def\attrAlignT{}% - \def\multAlignT{}% - % - \ifthenelse{\equal{\align}{left}}{% - \def\attrAlign{above right}% - \def\multAlign{below right}% - }{% - \ifthenelse{\equal{\align}{right}}{% - \def\attrAlign{above left}% - \def\multAlign{below left}% - }{}% - }% - % - \ifthenelse{\equal{\alignT}{left}}{% - \def\attrAlignT{above right}% - \def\multAlignT{below right}% - }{% - \ifthenelse{\equal{\alignT}{right}}{% - \def\attrAlignT{above left}% - \def\multAlignT{below left}% - }{}% - }% - % - % def stereotype - \ifthenelse{\equal{\stereo}{}}{% - \def\stereotype{}% - }{% - \def\stereotype{\guillemotleft\stereo\guillemotright}% - }% - - % def anchors macros - \ifthenelse{\equal{\tikzumlSrcAnchor}{tikzumlEmpty}}{% - \def\tikzumlSrcAnchor{}% - }{% - \let\tikzumlSrcAnchorold\tikzumlSrcAnchor% - \def\tikzumlSrcAnchor{.\tikzumlSrcAnchorold}% - }% - % - \ifthenelse{\equal{\tikzumlDestAnchor}{tikzumlEmpty}}{% - \def\tikzumlDestAnchor{}% - }{% - \let\tikzumlDestAnchorold\tikzumlDestAnchor% - \def\tikzumlDestAnchor{.\tikzumlDestAnchorold}% - }% - % - \setcounter{pos}{100*\real{\position}}% - \setcounter{posT}{100*\real{\positionT}}% - \setcounter{posStereo}{100*\real{\positionStereotype}}% - % - \pgfmathsetmacro{\weightT}{1-\real{\weight}}% - % - \def\tikzumlControlNodesNum{0}% - % - \def\pos{\position}% - \def\posT{\positionT}% - \def\posStereo{\positionStereotype}% - % - \node[inner sep=0] (\relationName-middle) at (barycentric cs:\tikzumlSrcClassNodeName=\weightT,\tikzumlDestClassNodeName=\weight) {};% - % - % straight line - \ifthenelse{\equal{\geometry}{--}}{% - \ifthenelse{\equal{\tikzumlSrcClassNodeName}{\tikzumlDestClassNodeName}}{% - \def\arcNum{1}% - \def\arcNumT{1}% - % - \ifthenelse{\equal{\tikzumlrecmode}{default}}{% - \xdef\tikzumlLastArc{node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% - node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity}% - node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% - node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT}% - node[pos=\positionStereotype, anchor=center] {\stereotype} }% - \xdef\tikzumlPath{(\tikzumlSrcClassNodeName) edge[in=\endangle, out=\startangle, distance=\loopsize] \tikzumlLastArc% - node[midway, inner sep=0, name=\relationName-1, anchor=center] {} (\tikzumlDestClassNodeName) }% - }{% - \ifthenelse{\equal{\tikzumlrecmode}{transition}}{% - \xdef\tikzumlFirstArc{node[midway, inner sep=0, name=\relationName-1, anchor=center] {}}% - \xdef\tikzumlMidOneArc{node[midway, inner sep=0, name=\relationName-3, anchor=center] {}}% - % - \ifthenelse{\equal{\tikzumlrecdirstart}{\tikzumlrecdirend}}{% - \def\numArcs{3}% - \xdef\tikzumlLastArc{node[midway, inner sep=0, name=\relationName-5, anchor=center] {}}% - % - \begin{pgfonlayer}{connections}% - \draw (\tikzumlSrcClassNodeName) edge[in=\endangle, out=\startangle, distance=\loopsize, draw=none] % - node[midway, inner sep=0, name=\relationName-tmp, anchor=center] {} (\tikzumlDestClassNodeName);% - \ifthenelse{\equal{\tikzumlrecdirstart}{right}\OR\equal{\tikzumlrecdirstart}{left}}{% - \node[inner sep=0, name=\relationName-2] at (\tikzumlSrcClassNodeName.\startangle -| \relationName-tmp) {};% - \node[inner sep=0, name=\relationName-4] at (\tikzumlDestClassNodeName.\endangle -| \relationName-tmp) {};% - }{% - \node[inner sep=0, name=\relationName-2] at (\tikzumlSrcClassNodeName.\startangle |- \relationName-tmp) {};% - \node[inner sep=0, name=\relationName-4] at (\tikzumlDestClassNodeName.\endangle |- \relationName-tmp) {};% - }% - \end{pgfonlayer}% - }{% - \def\numArcs{4}% - \xdef\tikzumlMidTwoArc{node[midway, inner sep=0, name=\relationName-5, anchor=center] {}}% - \xdef\tikzumlLastArc{node[midway, inner sep=0, name=\relationName-7, anchor=center] {}}% - % - \begin{pgfonlayer}{connections}% - \draw (\tikzumlSrcClassNodeName) edge[in=\endangle, out=\startangle, distance=\loopsize, draw=none] % - node[midway, name=\relationName-4, anchor=center] {} (\tikzumlDestClassNodeName);% - \ifthenelse{\equal{\tikzumlrecdirstart}{right}\OR\equal{\tikzumlrecdirstart}{left}}{% - \node[inner sep=0, name=\relationName-2] at (\tikzumlSrcClassNodeName.\startangle -| \relationName-4) {};% - \node[inner sep=0, name=\relationName-6] at (\tikzumlDestClassNodeName.\endangle |- \relationName-4) {};% - }{% - \node[inner sep=0, name=\relationName-2] at (\tikzumlSrcClassNodeName.\startangle |- \relationName-4) {};% - \node[inner sep=0, name=\relationName-6] at (\tikzumlDestClassNodeName.\endangle -| \relationName-4) {};% - }% - \end{pgfonlayer}% - }% - % - \ifnum\numArcs=4% - \ifnum\theposStereo>300% - \pgfmathsetmacro{\posStereo}{(\theposStereo-300)/100}% - \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\posStereo, anchor=center] {\stereotype}}% - \else% - \ifnum\theposStereo<100% - \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\posStereo, anchor=center] {\stereotype}}% - \else% - \ifnum\theposStereo>200% - \pgfmathsetmacro{\posStereo}{(\theposStereo-200)/100}% - \xdef\tikzumlMidTwoArc{\tikzumlMidTwoArc node[pos=\posStereo, anchor=center] {\stereotype}}% - \else% - \pgfmathsetmacro{\posStereo}{(\theposStereo-100)/100}% - \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\posStereo, anchor=center] {\stereotype}}% - \fi% - \fi% - \fi% - % - \ifthenelse{\thepos=300\OR\thepos=100}{% - \ifthenelse{\equal{\tikzumlrecdirstart}{right}}{% - \ifthenelse{\equal{\tikzumlrecdirend}{bottom}}{% - \def\posAttrName{above right}% - \def\posMultiplicity{below left}% - }{% - \def\posAttrName{above left}% - \def\posMultiplicity{below right}% - }% - }{% - \ifthenelse{\equal{\tikzumlrecdirstart}{left}}{% - \ifthenelse{\equal{\tikzumlrecdirend}{bottom}}{% - \def\posAttrName{above left}% - \def\posMultiplicity{below right}% - }{% - \def\posAttrName{above right}% - \def\posMultiplicity{below left}% - }% - }{% - \ifthenelse{\equal{\tikzumlrecdirstart}{top}}{% - \ifthenelse{\equal{\tikzumlrecdirend}{left}}{% - \def\posAttrName{above right}% - \def\posMultiplicity{below left}% - }{% - \def\posAttrName{above left}% - \def\posMultiplicity{below right}% - }% - }{% - \ifthenelse{\equal{\tikzumlrecdirend}{left}}{% - \def\posAttrName{above left}% - \def\posMultiplicity{below right}% - }{% - \def\posAttrName{above right}% - \def\posMultiplicity{below left}% - }% - }% - }% - }% - }{}% - % - \ifthenelse{\thepos=200}{% - \ifthenelse{\equal{\tikzumlrecdirstart}{right}}{% - \ifthenelse{\equal{\tikzumlrecdirend}{bottom}}{% - \def\posAttrName{above left}% - \def\posMultiplicity{below right}% - }{% - \def\posAttrName{above right}% - \def\posMultiplicity{below left}% - }% - }{% - \ifthenelse{\equal{\tikzumlrecdirstart}{left}}{% - \ifthenelse{\equal{\tikzumlrecdirend}{bottom}}{% - \def\posAttrName{above right}% - \def\posMultiplicity{below left}% - }{% - \def\posAttrName{above left}% - \def\posMultiplicity{below right}% - }% - }{% - \ifthenelse{\equal{\tikzumlrecdirstart}{top}}{% - \ifthenelse{\equal{\tikzumlrecdirend}{left}}{% - \def\posAttrName{above left}% - \def\posMultiplicity{below right}% - }{% - \def\posAttrName{above right}% - \def\posMultiplicity{below left}% - }% - }{% - \ifthenelse{\equal{\tikzumlrecdirend}{left}}{% - \def\posAttrName{above right}% - \def\posMultiplicity{below left}% - }{% - \def\posAttrName{above left}% - \def\posMultiplicity{below right}% - }% - }% - }% - }% - }{}% - % - \ifnum\thepos>300% - \pgfmathsetmacro{\pos}{(\thepos-300)/100}% - \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% - node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity}% - }% - \else% - \ifnum\thepos<100% - \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% - node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity}% - }% - \else% - \ifnum\thepos>200% - \pgfmathsetmacro{\pos}{(\thepos-200)/100}% - \xdef\tikzumlMidTwoArc{\tikzumlMidTwoArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% - node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity}% - }% - \else% - \pgfmathsetmacro{\pos}{(\thepos-100)/100}% - \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% - node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity}% - }% - \fi% - \fi% - \fi% - % - \ifthenelse{\theposT=300\OR\theposT=100}{% - \ifthenelse{\equal{\tikzumlrecdirstart}{right}}{% - \ifthenelse{\equal{\tikzumlrecdirend}{bottom}}{% - \def\posAttrNameT{above right}% - \def\posMultiplicityT{below left}% - }{% - \def\posAttrNameT{above left}% - \def\posMultiplicityT{below right}% - }% - }{% - \ifthenelse{\equal{\tikzumlrecdirstart}{left}}{% - \ifthenelse{\equal{\tikzumlrecdirend}{bottom}}{% - \def\posAttrNameT{above left}% - \def\posMultiplicityT{below right}% - }{% - \def\posAttrNameT{above right}% - \def\posMultiplicityT{below left}% - }% - }{% - \ifthenelse{\equal{\tikzumlrecdirstart}{top}}{% - \ifthenelse{\equal{\tikzumlrecdirend}{left}}{% - \def\posAttrNameT{above right}% - \def\posMultiplicityT{below left}% - }{% - \def\posAttrNameT{above left}% - \def\posMultiplicityT{below right}% - }% - }{% - \ifthenelse{\equal{\tikzumlrecdirend}{left}}{% - \def\posAttrNameT{above left}% - \def\posMultiplicityT{below right}% - }{% - \def\posAttrNameT{above right}% - \def\posMultiplicityT{below left}% - }% - }% - }% - }% - }{}% - \ifthenelse{\theposT=200}{% - \ifthenelse{\equal{\tikzumlrecdirstart}{right}}{% - \ifthenelse{\equal{\tikzumlrecdirend}{bottom}}{% - \def\posAttrNameT{above left}% - \def\posMultiplicity{below right}% - }{% - \def\posAttrNameT{above right}% - \def\posMultiplicityT{below left}% - }% - }{% - \ifthenelse{\equal{\tikzumlrecdirstart}{left}}{% - \ifthenelse{\equal{\tikzumlrecdirend}{bottom}}{% - \def\posAttrNameT{above right}% - \def\posMultiplicityT{below left}% - }{% - \def\posAttrNameT{above left}% - \def\posMultiplicityT{below right}% - }% - }{% - \ifthenelse{\equal{\tikzumlrecdirstart}{top}}{% - \ifthenelse{\equal{\tikzumlrecdirend}{left}}{% - \def\posAttrNameT{above left}% - \def\posMultiplicityT{below right}% - }{% - \def\posAttrNameT{above right}% - \def\posMultiplicityT{below left}% - }% - }{% - \ifthenelse{\equal{\tikzumlrecdirend}{left}}{% - \def\posAttrNameT{above right}% - \def\posMultiplicityT{below left}% - }{% - \def\posAttrNameT{above left}% - \def\posMultiplicityT{below right}% - }% - }% - }% - }% - }{}% - % - \ifnum\theposT>300% - \pgfmathsetmacro{\posT}{(\theposT-300)/100}% - \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% - node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT}% - }% - \else% - \ifnum\theposT<100% - \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% - node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT}% - }% - \else% - \ifnum\theposT>200% - \pgfmathsetmacro{\posT}{(\theposT-200)/100}% - \xdef\tikzumlMidTwoArc{\tikzumlMidTwoArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% - node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT}% - }% - \else% - \pgfmathsetmacro{\posT}{(\theposT-100)/100}% - \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% - node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT}% - }% - \fi% - \fi% - \fi% - \else% - \ifnum\theposStereo>200% - \pgfmathsetmacro{\posStereo}{(\theposStereo-200)/100}% - \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\posStereo, anchor=center] {\stereotype} }% - \else% - \ifnum\theposStereo<100% - \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\posStereo, anchor=center] {\stereotype} }% - \else% - \pgfmathsetmacro{\posStereo}{(\theposStereo-100)/100}% - \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\posStereo, anchor=center] {\stereotype} }% - \fi% - \fi% - % - \ifthenelse{\thepos=100}{% - \ifthenelse{\equal{\tikzumlrecdirstart}{right}}{% - \ifthenelse{\endangle<\startangle}{% - \def\posAttrName{above right}% - \def\posMultiplicity{below left}% - }{% - \def\posAttrName{above left}% - \def\posMultiplicity{below right}% - }% - }{% - \ifthenelse{\equal{\tikzumlrecdirstart}{left}}{% - \ifthenelse{\endangle<\startangle}{% - \def\posAttrName{above left}% - \def\posMultiplicity{below right}% - }{% - \def\posAttrName{above right}% - \def\posMultiplicity{below left}% - }% - }{% - \ifthenelse{\equal{\tikzumlrecdirstart}{top}}{% - \ifthenelse{\endangle<\startangle}{% - \def\posAttrName{above right}% - \def\posMultiplicity{below left}% - }{% - \def\posAttrName{above left}% - \def\posMultiplicity{below right}% - }% - }{% - \ifthenelse{\endangle<\startangle}{% - \def\posAttrName{above left}% - \def\posMultiplicity{below right}% - }{% - \def\posAttrName{above right}% - \def\posMultiplicity{below left}% - }% - }% - }% - }% - }{}% - % - \ifthenelse{\thepos=200}{% - \ifthenelse{\equal{\tikzumlrecdirstart}{right}}{% - \ifthenelse{\endangle<\startangle}{% - \def\posAttrName{above left}% - \def\posMultiplicity{below right}% - }{% - \def\posAttrName{above right}% - \def\posMultiplicity{below left}% - }% - }{% - \ifthenelse{\equal{\tikzumlrecdirstart}{left}}{% - \ifthenelse{\endangle<\startangle}{% - \def\posAttrName{above right}% - \def\posMultiplicity{below left}% - }{% - \def\posAttrName{above left}% - \def\posMultiplicity{below right}% - }% - }{% - \ifthenelse{\equal{\tikzumlrecdirstart}{top}}{% - \ifthenelse{\endangle<\startangle}{% - \def\posAttrName{above left}% - \def\posMultiplicity{below right}% - }{% - \def\posAttrName{above right}% - \def\posMultiplicity{below left}% - }% - }{% - \ifthenelse{\endangle<\startangle}{% - \def\posAttrName{above right}% - \def\posMultiplicity{below left}% - }{% - \def\posAttrName{above left}% - \def\posMultiplicity{below right}% - }% - }% - }% - }% - }{}% - % - \ifnum\thepos>200% - \pgfmathsetmacro{\pos}{(\thepos-200)/100}% - \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% - node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity}% - }% - \else% - \ifnum\thepos<100% - \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% - node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity}% - }% - \else% - \pgfmathsetmacro{\pos}{(\thepos-100)/100}% - \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% - node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity}% - }% - \fi% - \fi% - % - \ifthenelse{\theposT=100}{% - \ifthenelse{\equal{\tikzumlrecdirstart}{right}}{% - \ifthenelse{\endangle<\startangle}{% - \def\posAttrNameT{above right}% - \def\posMultiplicityT{below left}% - }{% - \def\posAttrNameT{above left}% - \def\posMultiplicityT{below right}% - }% - }{% - \ifthenelse{\equal{\tikzumlrecdirstart}{left}}{% - \ifthenelse{\endangle<\startangle}{% - \def\posAttrNameT{above left}% - \def\posMultiplicityT{below right}% - }{% - \def\posAttrNameT{above right}% - \def\posMultiplicityT{below left}% - }% - }{% - \ifthenelse{\equal{\tikzumlrecdirstart}{top}}{% - \ifthenelse{\endangle<\startangle}{% - \def\posAttrNameT{above right}% - \def\posMultiplicityT{below left}% - }{% - \def\posAttrNameT{above left}% - \def\posMultiplicityT{below right}% - }% - }{% - \ifthenelse{\endangle<\startangle}{% - \def\posAttrNameT{above left}% - \def\posMultiplicityT{below right}% - }{% - \def\posAttrNameT{above right}% - \def\posMultiplicityT{below left}% - }% - }% - }% - }% - }{}% - % - \ifthenelse{\theposT=200}{% - \ifthenelse{\equal{\tikzumlrecdirstart}{right}}{% - \ifthenelse{\endangle<\startangle}{% - \def\posAttrNameT{above left}% - \def\posMultiplicityT{below right}% - }{% - \def\posAttrNameT{above right}% - \def\posMultiplicityT{below left}% - }% - }{% - \ifthenelse{\equal{\tikzumlrecdirstart}{left}}{% - \ifthenelse{\endangle<\startangle}{% - \def\posAttrNameT{above right}% - \def\posMultiplicityT{below left}% - }{% - \def\posAttrNameT{above left}% - \def\posMultiplicityT{below right}% - }% - }{% - \ifthenelse{\equal{\tikzumlrecdirstart}{top}}{% - \ifthenelse{\endangle<\startangle}{% - \def\posAttrNameT{above left}% - \def\posMultiplicityT{below right}% - }{% - \def\posAttrNameT{above right}% - \def\posMultiplicityT{below left}% - }% - }{% - \ifthenelse{\endangle<\startangle}{% - \def\posAttrNameT{above right}% - \def\posMultiplicityT{below left}% - }{% - \def\posAttrNameT{above left}% - \def\posMultiplicityT{below right}% - }% - }% - }% - }% - }{}% - % - \ifnum\theposT>200% - \pgfmathsetmacro{\posT}{(\theposT-200)/100}% - \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% - node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT}% - }% - \else% - \ifnum\theposT<100% - \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% - node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT}% - }% - \else% - \pgfmathsetmacro{\posT}{(\theposT-100)/100}% - \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% - node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT}% - }% - \fi% - \fi% - \fi% - % - \ifthenelse{\equal{\tikzumlrecdirstart}{\tikzumlrecdirend}}{% - \xdef\tikzumlPath{(\tikzumlSrcClassNodeName.\startangle) -- \tikzumlFirstArc (\relationName-2.center) -- \tikzumlMidOneArc (\relationName-4.center) -- \tikzumlLastArc (\tikzumlDestClassNodeName.\endangle) }% - \ifnum\thetikzumlStateLevel>0% - \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% - \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\relationName-1) (\relationName-2) (\relationName-3) (\relationName-4) (\relationName-5)}% - \fi% - }{% - \xdef\tikzumlPath{(\tikzumlSrcClassNodeName.\startangle) -- \tikzumlFirstArc (\relationName-2.center) -- \tikzumlMidOneArc (\relationName-4.center) -- \tikzumlMidTwoArc (\relationName-6.center) -- \tikzumlLastArc (\tikzumlDestClassNodeName.\endangle) }% - \ifnum\thetikzumlStateLevel>0% - \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% - \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\relationName-1) (\relationName-2) (\relationName-3) (\relationName-4) (\relationName-5) (\relationName-6) (\relationName-7)}% - \fi% - }% - }{}% - }% - }{% - \def\arcNum{1}% - \def\arcNumT{1}% - % - \node[inner sep=0] (\relationName-1) at (\relationName-middle) {};% - \xdef\tikzumlLastArc{node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% - node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity}% - node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% - node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT}% - node[pos=\positionStereotype, anchor=center] {\stereotype} }% - \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlSrcAnchor) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlDestAnchor) }% - \ifnum\thetikzumlStateLevel>0% - \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% - \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\relationName-1) }% - \fi% - }% - }{% - % first vertical then horizontal line - \ifthenelse{\equal{\geometry}{|-}}% - {% - \def\tikzumlControlNodesNum{1}% - % - \def\tikzumlFirstArc{node[midway, inner sep=0, name=\relationName-1, anchor=center] {} }% - \def\tikzumlLastArc{node[midway, inner sep=0, name=\relationName-3, anchor=center]{} }% - % - \begin{pgfonlayer}{connections}% - \node[inner sep=0] (\relationName-2) at (\tikzumlSrcClassNodeName\tikzumlSrcAnchor |- \tikzumlDestClassNodeName\tikzumlDestAnchor) {};% - \end{pgfonlayer}% - % - \ifnum\theposStereo>100% - \pgfmathsetmacro{\posStereo}{(\theposStereo-100)/100}% - \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\posStereo, anchor=center] {\stereotype} }% - \else% - \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\posStereo, anchor=center] {\stereotype} }% - \fi% - % - \ifnum\thepos>100% - \pgfmathsetmacro{\pos}{(\thepos-100)/100}% - \def\arcNum{2}% - \else% - \def\arcNum{1}% - \ifnum\thepos=100% - \def\posAttrName{above left}% - \def\posMultiplicity{below right}% - \fi% - \fi% - % - \ifnum\arcNum=1% - \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% - node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity} }% - \fi% - \ifnum\arcNum=2% - \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% - node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity} }% - \fi% - % - \ifnum\theposT>100% - \pgfmathsetmacro{\posT}{(\theposT-100)/100}% - \def\arcNumT{2}% - \else% - \def\arcNumT{1}% - \ifnum\theposT=100% - \def\posAttrNameT{above left}% - \def\posMultiplicityT{below right}% - \fi% - \fi% - % - \ifnum\arcNumT=1% - \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% - node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT} }% - \fi% - \ifnum\arcNumT=2% - \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% - node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT} }% - \fi% - % - \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlSrcAnchor) -- \tikzumlFirstArc (\relationName-2.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlDestAnchor) }% - \ifnum\thetikzumlStateLevel>0% - \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% - \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\relationName-1) (\relationName-2) (\relationName-3) }% - \fi% - }{% - % first horizontal then vertical line - \ifthenelse{\equal{\geometry}{-|}}{% - \def\tikzumlControlNodesNum{1}% - % - \def\tikzumlFirstArc{node[midway, inner sep=0, name=\relationName-1, anchor=center]{} }% - \def\tikzumlLastArc{node[midway, inner sep=0, name=\relationName-3, anchor=center] {} }% - % - \begin{pgfonlayer}{connections}% - \node[inner sep=0] (\relationName-2) at (\tikzumlSrcClassNodeName\tikzumlSrcAnchor -| \tikzumlDestClassNodeName\tikzumlDestAnchor) {};% - \end{pgfonlayer}% - % - \ifnum\theposStereo>100% - \pgfmathsetmacro{\posStereo}{(\theposStereo-100)/100}% - \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\posStereo, anchor=center] {\stereotype} }% - \else% - \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\posStereo, anchor=center] {\stereotype} }% - \fi% - % - \ifnum\thepos>100% - \pgfmathsetmacro{\pos}{(\thepos-100)/100}% - \def\arcNum{2}% - \else% - \def\arcNum{1}% - \ifnum\thepos=100% - \def\posAttrName{above left}% - \def\posMultiplicity{below right}% - \fi% - \fi% - % - \ifnum\arcNum=1% - \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% - node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity} }% - \fi% - \ifnum\arcNum=2% - \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% - node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity} }% - \fi% - % - \ifnum\theposT>100% - \pgfmathsetmacro{\posT}{(\theposT-100)/100}% - \def\arcNumT{2}% - \else% - \def\arcNumT{1}% - \ifnum\theposT=100% - \def\posAttrNameT{above left}% - \def\posMultiplicityT{below right}% - \fi% - \fi% - % - \ifnum\arcNumT=1% - \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% - node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT} }% - \fi% - \ifnum\arcNumT=2% - \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% - node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT} }% - \fi% - % - \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlSrcAnchor) -- \tikzumlFirstArc (\relationName-2.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlDestAnchor) }% - \ifnum\thetikzumlStateLevel>0% - \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% - \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\relationName-1) (\relationName-2) (\relationName-3) }% - \fi% - }{% - % first vertical, then horizontal, finally vertical line - \ifthenelse{\equal{\geometry}{|-|}}{% - \def\tikzumlControlNodesNum{2}% - % - \def\tikzumlFirstArc{node[midway, inner sep=0, name=\relationName-1, anchor=center] {} }% - \def\tikzumlLastArc{node[midway, inner sep=0, name=\relationName-5, anchor=center] {} }% - \def\tikzumlMidOneArc{ }% - % - \begin{pgfonlayer}{connections}% - % - \ifthenelse{\equal{\armO}{auto}}{% - \ifthenelse{\equal{\armT}{auto}}{% - \node[inner sep=0] (\relationName-3) at (\relationName-middle) {};% - \node[inner sep=0] (\relationName-2) at (\tikzumlSrcClassNodeName\tikzumlSrcAnchor |- \relationName-3) {};% - \node[inner sep=0] (\relationName-4) at (\relationName-3 -| \tikzumlDestClassNodeName\tikzumlDestAnchor) {};% - }{% - \draw (\tikzumlDestClassNodeName\tikzumlDestAnchor)+(0,\armT) node[inner sep=0, name=\relationName-4] {};% - \node[inner sep=0] (\relationName-2) at (\relationName-4 -| \tikzumlSrcClassNodeName\tikzumlSrcAnchor) {};% - \node[inner sep=0] (\relationName-3) at (barycentric cs:\relationName-2=0.5,\relationName-4=0.5) {};% - }% - }{% - \draw (\tikzumlSrcClassNodeName\tikzumlSrcAnchor)+(0,\armO) node[inner sep=0, name=\relationName-2] {};% - \node[inner sep=0] (\relationName-4) at (\relationName-2 -| \tikzumlDestClassNodeName\tikzumlDestAnchor) {};% - \node[inner sep=0] (\relationName-3) at (barycentric cs:\relationName-2=0.5,\relationName-4=0.5) {};% - }% - \end{pgfonlayer}% - % - \ifnum\theposStereo>200% - \pgfmathsetmacro{\posStereo}{(\theposStereo-200)/100}% - \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\posStereo, anchor=center] {\stereotype} }% - \else% - \ifnum\theposStereo<100% - \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\posStereo, anchor=center] {\stereotype} }% - \else% - \pgfmathsetmacro{\posStereo}{(\theposStereo-100)/100}% - \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\posStereo, anchor=center] {\stereotype} }% - \fi% - \fi% - % - \ifthenelse{\thepos=200\OR\thepos=100}{% - \def\posAttrName{above left}% - \def\posMultiplicity{below right}% - }{}% - % - \ifthenelse{\thepos>200}{% - \pgfmathsetmacro{\pos}{(\thepos-200)/100}% - \def\arcNum{3}% - }{% - \ifthenelse{\thepos<100}{% - \def\arcNum{1}% - }{% - \pgfmathsetmacro{\pos}{(\thepos-100)/100}% - \def\arcNum{2}% - }% - }% - % - \ifnum\arcNum=1% - \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% - node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity} }% - \fi% - \ifnum\arcNum=2% - \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% - node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity} }% - \fi% - \ifnum\arcNum=3% - \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% - node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity} }% - \fi% - % - \ifthenelse{\theposT=200\OR\theposT=100}{% - \def\posAttrNameT{above left}% - \def\posMultiplicityT{below right}% - }{}% - % - \ifthenelse{\theposT>200}{% - \pgfmathsetmacro{\posT}{(\theposT-200)/100}% - \def\arcNumT{3}% - }{% - \ifthenelse{\theposT<100}{% - \def\arcNumT{1}% - }{% - \pgfmathsetmacro{\posT}{(\theposT-100)/100}% - \def\arcNumT{2}% - }% - }% - % - \ifnum\arcNumT=1% - \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% - node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT} }% - \fi% - \ifnum\arcNumT=2% - \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% - node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT} }% - \fi% - \ifnum\arcNumT=3% - \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% - node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT} }% - \fi% - % - \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlSrcAnchor) -- \tikzumlFirstArc (\relationName-2.base) -- \tikzumlMidOneArc (\relationName-4.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlDestAnchor) }% - \ifnum\thetikzumlStateLevel>0% - \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% - \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\relationName-1) (\relationName-2) (\relationName-3) (\relationName-4) (\relationName-5) }% - \fi% - }{% - % first horizontal, then vertical, finally horizontal line - \ifthenelse{\equal{\geometry}{-|-}}{% - \def\tikzumlControlNodesNum{2}% - % - \def\tikzumlFirstArc{node[midway, inner sep=0, name=\relationName-1, anchor=center] {} }% - \def\tikzumlLastArc{node[midway, inner sep=0, name=\relationName-5, anchor=center] {} }% - \def\tikzumlMidOneArc{}% - % - \begin{pgfonlayer}{connections}% - % - \ifthenelse{\equal{\armO}{auto}}{% - \ifthenelse{\equal{\armT}{auto}}{% - \node[inner sep=0] (\relationName-3) at (\relationName-middle) {};% - \node[inner sep=0] (\relationName-2) at (\tikzumlSrcClassNodeName\tikzumlSrcAnchor -| \relationName-3) {};% - \node[inner sep=0] (\relationName-4) at (\relationName-3 |- \tikzumlDestClassNodeName\tikzumlDestAnchor) {};% - }{% - \draw (\tikzumlDestClassNodeName\tikzumlDestAnchor)+(\armT,0) node[inner sep=0, name=\relationName-4] {};% - \node[inner sep=0] (\relationName-2) at (\relationName-4 |- \tikzumlSrcClassNodeName\tikzumlSrcAnchor) {};% - \node[inner sep=0] (\relationName-3) at (barycentric cs:\relationName-2=0.5,\relationName-4=0.5) {};% - }% - }{% - \draw (\tikzumlSrcClassNodeName\tikzumlSrcAnchor)+(\armO,0) node[inner sep=0, name=\relationName-2] {};% - \node[inner sep=0] (\relationName-4) at (\relationName-2 |- \tikzumlDestClassNodeName\tikzumlDestAnchor) {};% - \node[inner sep=0] (\relationName-3) at (barycentric cs:\relationName-2=0.5,\relationName-4=0.5) {};% - }% - \end{pgfonlayer}% - % - % - \ifnum\theposStereo>200% - \pgfmathsetmacro{\posStereo}{(\theposStereo-200)/100}% - \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\posStereo, anchor=center] {\stereotype} }% - \else% - \ifnum\theposStereo<100% - \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\posStereo, anchor=center] {\stereotype} }% - \else% - \pgfmathsetmacro{\posStereo}{(\theposStereo-100)/100}% - \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\posStereo, anchor=center] {\stereotype} }% - \fi% - \fi% - % - \ifthenelse{\thepos=200\OR\thepos=100}{% - \def\posAttrName{above left}% - \def\posMultiplicity{below right}% - }{}% - % - \ifthenelse{\thepos>200}{% - \pgfmathsetmacro{\pos}{(\thepos-200)/100}% - \def\arcNum{3}% - }{% - \ifthenelse{\thepos<100}{% - \def\arcNum{1}% - }{% - \pgfmathsetmacro{\pos}{(\thepos-100)/100}% - \def\arcNum{2}% - }% - }% - % - \ifnum\arcNum=1% - \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% - node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity} }% - \fi% - \ifnum\arcNum=2% - \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% - node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity} }% - \fi% - \ifnum\arcNum=3% - \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% - node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity} }% - \fi% - % - \ifthenelse{\theposT=200\OR\theposT=100}{% - \def\posAttrNameT{above left}% - \def\posMultiplicityT{below right}% - }{}% - % - \ifthenelse{\theposT>200}{% - \pgfmathsetmacro{\posT}{(\theposT-200)/100}% - \def\arcNumT{3}% - }{% - \ifthenelse{\theposT<100}{% - \def\arcNumT{1}% - }{% - \pgfmathsetmacro{\posT}{(\theposT-100)/100}% - \def\arcNumT{2}% - }% - }% - % - \ifnum\arcNumT=1% - \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% - node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT} }% - \fi% - \ifnum\arcNumT=2% - \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% - node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT} }% - \fi% - \ifnum\arcNumT=3% - \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% - node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT} }% - \fi% - % - \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlSrcAnchor) -- \tikzumlFirstArc (\relationName-2.base) -- \tikzumlMidOneArc (\relationName-4.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlDestAnchor) }% - \ifnum\thetikzumlStateLevel>0% - \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% - \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\relationName-1) (\relationName-2) (\relationName-3) (\relationName-4) (\relationName-5) }% - \fi% - }{% - \errmessage{TIKZUML ERROR : Unknown geometry value !!! It should be in the following list : --, |-, -|, |-|, -|-}% - }% - }% - }% - }% - }% - % - \begin{pgfonlayer}{connections}% - \draw[auto, \style, font=\tikzumlfont] \tikzumlPath ;% - \end{pgfonlayer}% - % - \stepcounter{tikzumlRelationNum}% -}% - -% shortcuts of \umlrelation -\newcommand{\umlHVrelation}[3][]{% - \pgfkeys{/tikzuml/HVrelation/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{geometry}}{% - \errmessage{TIKZUML ERROR : in umlHVrelation, forbidden option geometry}% - }{}% - }}% - \pgfkeys{/tikzuml/HVrelation/.cd, #1}% - \umlrelation[geometry=-|, #1]{#2}{#3}% -}% - -\newcommand{\umlVHrelation}[3][]{% - \pgfkeys{/tikzuml/VHrelation/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{geometry}}{% - \errmessage{TIKZUML ERROR : in umlVHrelation, forbidden option geometry}% - }{}% - }}% - \pgfkeys{/tikzuml/VHrelation/.cd, #1}% - \umlrelation[geometry=|-, #1]{#2}{#3}% -}% - -\newcommand{\umlHVHrelation}[3][]{% - \pgfkeys{/tikzuml/HVHrelation/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{geometry}}{% - \errmessage{TIKZUML ERROR : in umlHVHrelation, forbidden option geometry}% - }{}% - }}% - \pgfkeys{/tikzuml/HVHrelation/.cd, #1}% - \umlrelation[geometry=-|-, #1]{#2}{#3}% -}% - -\newcommand{\umlVHVrelation}[3][]{% - \pgfkeys{/tikzuml/VHVrelation/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{geometry}}{% - \errmessage{TIKZUML ERROR : in umlVHVrelation, forbidden option geometry}% - }{}% - }}% - \pgfkeys{/tikzuml/VHVrelation/.cd, #1}% - \umlrelation[geometry=|-|, #1]{#2}{#3}% -}% - -% shortcuts for relations -\newcommand{\umlinherit}[3][]{\umlrelation[style={tikzuml inherit style}, #1]{#2}{#3}}% -\newcommand{\umlimpl}[3][]{\umlrelation[style={tikzuml implements style}, #1]{#2}{#3}}% -\newcommand{\umlreal}[3][]{\umlrelation[style={tikzuml implements style}, #1]{#2}{#3}}% -\newcommand{\umlassoc}[3][]{\umlrelation[style={tikzuml association style}, #1]{#2}{#3}}% -\newcommand{\umlbiassoc}[3][]{\umlrelation[style={tikzuml bidirectional association style}, #1]{#2}{#3}}% -\newcommand{\umluniassoc}[3][]{\umlrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}% -\newcommand{\umlaggreg}[3][]{\umlrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}% -\newcommand{\umluniaggreg}[3][]{\umlrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}% -\newcommand{\umlcompo}[3][]{\umlrelation[style={tikzuml composition style}, #1]{#2}{#3}}% -\newcommand{\umlunicompo}[3][]{\umlrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}% -\newcommand{\umlimport}[3][]{\umlrelation[style={tikzuml import style}, #1]{#2}{#3}}% -\newcommand{\umldep}[3][]{\umlrelation[style={tikzuml dependency style}, #1]{#2}{#3}}% -\newcommand{\umlfriend}[3][]{% - \pgfkeys{/tikzuml/friendrelation/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR : in umlfriend, forbidden option stereo}% - }{}% - }}% - \pgfkeys{/tikzuml/friendrelation/.cd, #1}% - \umlrelation[stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}% -}% - -\newcommand{\umlHVinherit}[3][]{\umlHVrelation[style={tikzuml inherit style}, #1]{#2}{#3}}% -\newcommand{\umlHVimpl}[3][]{\umlHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}% -\newcommand{\umlHVreal}[3][]{\umlHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}% -\newcommand{\umlHVassoc}[3][]{\umlHVrelation[style={tikzuml association style}, #1]{#2}{#3}}% -\newcommand{\umlHVuniassoc}[3][]{\umlHVrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}% -\newcommand{\umlHVaggreg}[3][]{\umlHVrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}% -\newcommand{\umlHVuniaggreg}[3][]{\umlHVrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}% -\newcommand{\umlHVcompo}[3][]{\umlHVrelation[style={tikzuml composition style}, #1]{#2}{#3}}% -\newcommand{\umlHVunicompo}[3][]{\umlHVrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}% -\newcommand{\umlHVimport}[3][]{\umlHVrelation[style={tikzuml import style}, #1]{#2}{#3}}% -\newcommand{\umlHVdep}[3][]{\umlHVrelation[style={tikzuml dependency style}, #1]{#2}{#3}}% -\newcommand{\umlHVfriend}[3][]{% - \pgfkeys{/tikzuml/friendrelation/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR : in umlHVfriend, forbidden option stereo}% - }{% - \ifthenelse{\equal{\keyname}{geometry}}{% - \errmessage{TIKZUML ERROR : in umlHVfriend, forbidden option geometry}% - }{}% - }% - }}% - \pgfkeys{/tikzuml/friendrelation/.cd, #1}% - \umlrelation[geometry=-|, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}% -}% - -\newcommand{\umlVHinherit}[3][]{\umlVHrelation[style={tikzuml inherit style}, #1]{#2}{#3}}% -\newcommand{\umlVHimpl}[3][]{\umlVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}% -\newcommand{\umlVHreal}[3][]{\umlVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}% -\newcommand{\umlVHassoc}[3][]{\umlVHrelation[style={tikzuml association style}, #1]{#2}{#3}}% -\newcommand{\umlVHuniassoc}[3][]{\umlVHrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}% -\newcommand{\umlVHaggreg}[3][]{\umlVHrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}% -\newcommand{\umlVHuniaggreg}[3][]{\umlVHrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}% -\newcommand{\umlVHcompo}[3][]{\umlVHrelation[style={tikzuml composition style}, #1]{#2}{#3}}% -\newcommand{\umlVHunicompo}[3][]{\umlVHrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}% -\newcommand{\umlVHimport}[3][]{\umlVHrelation[style={tikzuml import style}, #1]{#2}{#3}}% -\newcommand{\umlVHdep}[3][]{\umlVHrelation[style={tikzuml dependency style}, #1]{#2}{#3}}% -\newcommand{\umlVHfriend}[3][]{% - \pgfkeys{/tikzuml/friendrelation/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR : in umlVHfriend, forbidden option stereo}% - }{% - \ifthenelse{\equal{\keyname}{geometry}}{% - \errmessage{TIKZUML ERROR : in umlVHfriend, forbidden option geometry}% - }{}% - }% - }}% - \pgfkeys{/tikzuml/friendrelation/.cd, #1}% - \umlrelation[geometry=|-, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}% -}% - -\newcommand{\umlHVHinherit}[3][]{\umlHVHrelation[style={tikzuml inherit style}, #1]{#2}{#3}}% -\newcommand{\umlHVHimpl}[3][]{\umlHVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}% -\newcommand{\umlHVHreal}[3][]{\umlHVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}% -\newcommand{\umlHVHassoc}[3][]{\umlHVHrelation[style={tikzuml association style}, #1]{#2}{#3}}% -\newcommand{\umlHVHuniassoc}[3][]{\umlHVHrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}% -\newcommand{\umlHVHaggreg}[3][]{\umlHVHrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}% -\newcommand{\umlHVHuniaggreg}[3][]{\umlHVHrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}% -\newcommand{\umlHVHcompo}[3][]{\umlHVHrelation[style={tikzuml composition style}, #1]{#2}{#3}}% -\newcommand{\umlHVHunicompo}[3][]{\umlHVHrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}% -\newcommand{\umlHVHimport}[3][]{\umlHVHrelation[style={tikzuml import style}, #1]{#2}{#3}}% -\newcommand{\umlHVHdep}[3][]{\umlHVHrelation[style={tikzuml dependency style}, #1]{#2}{#3}}% -\newcommand{\umlHVHfriend}[3][]{% - \pgfkeys{/tikzuml/friendrelation/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR : in umlHVHfriend, forbidden option stereo}% - }{% - \ifthenelse{\equal{\keyname}{geometry}}{% - \errmessage{TIKZUML ERROR : in umlHVHfriend, forbidden option geometry}% - }{}% - }% - }}% - \pgfkeys{/tikzuml/friendrelation/.cd, #1}% - \umlrelation[geometry=-|-, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}% -}% - -\newcommand{\umlVHVinherit}[3][]{\umlVHVrelation[style={tikzuml inherit style}, #1]{#2}{#3}}% -\newcommand{\umlVHVimpl}[3][]{\umlVHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}% -\newcommand{\umlVHVreal}[3][]{\umlVHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}% -\newcommand{\umlVHVassoc}[3][]{\umlVHVrelation[style={tikzuml association style}, #1]{#2}{#3}}% -\newcommand{\umlVHVuniassoc}[3][]{\umlVHVrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}% -\newcommand{\umlVHVaggreg}[3][]{\umlVHVrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}% -\newcommand{\umlVHVuniaggreg}[3][]{\umlVHVrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}% -\newcommand{\umlVHVcompo}[3][]{\umlVHVrelation[style={tikzuml composition style}, #1]{#2}{#3}}% -\newcommand{\umlVHVunicompo}[3][]{\umlVHVrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}% -\newcommand{\umlVHVimport}[3][]{\umlVHVrelation[style={tikzuml import style}, #1]{#2}{#3}}% -\newcommand{\umlVHVdep}[3][]{\umlVHVrelation[style={tikzuml dependency style}, #1]{#2}{#3}}% -\newcommand{\umlVHVfriend}[3][]{% - \pgfkeys{/tikzuml/friendrelation/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR : in umlVHVfriend, forbidden option stereo}% - }{% - \ifthenelse{\equal{\keyname}{geometry}}{% - \errmessage{TIKZUML ERROR : in umlVHVfriend, forbidden option geometry}% - }{}% - }% - }}% - \pgfkeys{/tikzuml/friendrelation/.cd, #1}% - \umlrelation[geometry=|-|, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}% -}% - -% define a node -\newcommand{\umlnode}[2]{% - \node (#2) at (#1) {};% -}% - -% main command to define a relation between two classes through a control node -% args : src class -% control node -% dest class -% optional : geometry of the line -% barycentric weight -% name of the src class type attribute defined by the relation -% multiplicity of the src class type attribute defined by the relation -% position on the relation -% text justification on the relation -% name of the dest class type attribute defined by the relation -% multiplicity of the dest class type attribute defined by the relation -% position on the relation -% border anchors -% text justification on the relation -% start angle, end angle and size of the relation (only if recursive) -% stereotype of the relation -% style of the relation (association, aggregation, composition, inherit, ...) -\newcommand{\umlCNrelation}[4][]% -{% - \pgfkeys{/tikzuml/relation/.cd,% - arg1/.initial={}, arg2/.initial={}, arg/.initial={},% - mult1/.initial={}, mult2/.initial={}, mult/.initial={},% - pos1/.initial=0.2, pos2/.initial=0.8, pos/.initial={tikzumlEmpty},% - align1/.initial={}, align2/.initial={}, align/.initial={},% - anchor1/.initial={tikzumlEmpty}, anchor2/.initial={tikzumlEmpty},% - stereo/.initial={}, pos stereo/.initial=1,% - style/.initial=->, name/.initial=relation-\thetikzumlRelationNum,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \errmessage{TIKZUML ERROR : in umlCNrelation, invalid option \keyname}% - }}% - \pgfkeys{/tikzuml/relation/.cd,#1}% - \pgfkeys{/tikzuml/relation/.cd,% - arg1/.get=\attrName, arg2/.get=\attrNameTO, arg/.get=\attrNameTT,% - mult1/.get=\multiplicity, mult2/.get=\multiplicityTO, mult/.get=\multiplicityTT,% - pos1/.get=\position, pos2/.get=\positionTO, pos/.get=\positionTT,% - align1/.get=\align, align2/.get=\alignTO, align/.get=\alignTT,% - anchor1/.get=\tikzumlSrcAnchor, anchor2/.get=\tikzumlDestAnchor,% - stereo/.get=\stereo, pos stereo/.get=\positionStereotype,% - style/.get=\style, name/.get=\relationName}% - % - % managing \_ in class names for node names - \def\tikzumlSrcClassName{#2}% - \begingroup% - \def\_{_}\edef\x{\endgroup% - \def\noexpand\tikzumlSrcClassNodeName{\tikzumlSrcClassName}}\x% - % - \StrSubstitute{\tikzumlSrcClassNodeName}{:}{@COLON@}[\tikzumlSrcClassNodeName] - % - \def\tikzumlDestClassName{#4}% - \begingroup% - \def\_{_}\edef\x{\endgroup% - \def\noexpand\tikzumlDestClassNodeName{\tikzumlDestClassName}}\x% - % - \StrSubstitute{\tikzumlDestClassNodeName}{:}{@COLON@}[\tikzumlDestClassNodeName] - % - % managing alias keys - \def\attrNameT{\attrNameTO\attrNameTT}% - \def\multiplicityT{\multiplicityTO\multiplicityTT}% - \def\alignT{\alignTO\alignTT}% - \def\orientationT{\orientationTO\orientationTT}% - % - \ifthenelse{\equal{\positionTT}{tikzumlEmpty}}{% - \def\positionT{\positionTO}% - }{% - \def\positionT{\positionTT}% - }% - % - \def\attrAlign{}% - \def\multAlign{}% - \def\attrAlignT{}% - \def\multAlignT{}% - % - \ifthenelse{\equal{\align}{left}}{% - \def\attrAlign{above right}% - \def\multAlign{below right}% - }{% - \ifthenelse{\equal{\align}{right}}{% - \def\attrAlign{above left}% - \def\multAlign{below left}% - }{}% - }% - % - \ifthenelse{\equal{\alignT}{left}}{% - \def\attrAlignT{above right}% - \def\multAlignT{below right}% - }{% - \ifthenelse{\equal{\alignT}{right}}{% - \def\attrAlignT{above left}% - \def\multAlignT{below left}% - }{}% - }% - % - % def stereotype - \ifthenelse{\equal{\stereo}{}}{% - \def\stereotype{}% - }{% - \def\stereotype{\guillemotleft\stereo\guillemotright}% - }% - % - % def anchors macros - \ifthenelse{\equal{\tikzumlSrcAnchor}{tikzumlEmpty}}{% - \def\tikzumlSrcAnchor{}% - }{% - \let\tikzumlSrcAnchorold\tikzumlSrcAnchor% - \def\tikzumlSrcAnchor{.\tikzumlSrcAnchorold}% - }% - % - \ifthenelse{\equal{\tikzumlDestAnchor}{tikzumlEmpty}}{% - \def\tikzumlDestAnchor{}% - }{% - \let\tikzumlDestAnchorold\tikzumlDestAnchor% - \def\tikzumlDestAnchor{.\tikzumlDestAnchorold}% - }% - % - \setcounter{pos}{100*\real{\position}}% - \setcounter{posT}{100*\real{\positionT}}% - \setcounter{posStereo}{100*\real{\positionStereotype}}% - % - \def\pos{\position}% - \def\posT{\positionT}% - \def\posStereo{\positionStereotype}% - % - % straight line - \def\tikzumlControlNodesNum{1}% - % - \def\tikzumlFirstArc{node[midway, name=\relationName-1, anchor=center] {} }% - \def\tikzumlLastArc{node[midway, name=\relationName-3, anchor=center]{} }% - \def\posAttrName{}% - \def\posMultiplicity{}% - \def\posAttrNameT{}% - \def\posMultiplicityT{}% - % - \begin{pgfonlayer}{connections}% - \node (\relationName-2) at (#3) {};% - \end{pgfonlayer}% - % - \ifnum\theposStereo>100% - \pgfmathsetmacro{\posStereo}{(\theposStereo-100)/100}% - \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\posStereo, anchor=center] {\stereotype} }% - \else% - \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\posStereo, anchor=center] {\stereotype} }% - \fi% - % - \ifnum\thepos>100% - \pgfmathsetmacro{\pos}{(\thepos-100)/100}% - \def\arcNum{2}% - \else% - \def\arcNum{1}% - \ifnum\thepos=100% - \def\posAttrName{above left}% - \def\posMultiplicity{below right}% - \fi% - \fi% - % - \ifnum\arcNum=1% - \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% - node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity} }% - \fi% - \ifnum\arcNum=2% - \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% - node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity} }% - \fi% - % - \ifnum\theposT>100% - \pgfmathsetmacro{\posT}{(\theposT-100)/100}% - \def\arcNumT{2}% - \else% - \def\arcNumT{1}% - \ifnum\theposT=100% - \def\posAttrNameT{above left}% - \def\posMultiplicityT{below right}% - \fi% - \fi% - % - \ifnum\arcNumT=1% - \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% - node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT} }% - \fi% - \ifnum\arcNumT=2% - \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% - node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT} }% - \fi% - % - \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlSrcAnchor) -- \tikzumlFirstArc (\relationName-2.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlDestAnchor) }% - - \begin{pgfonlayer}{connections}% - \draw[auto, \style, font=\tikzumlfont] \tikzumlPath ;% - \end{pgfonlayer}% - % - \stepcounter{tikzumlRelationNum}% -}% - -% shortcuts for cnrelations -\newcommand{\umlCNinherit}[4][]{\umlCNrelation[style={tikzuml inherit style}, #1]{#2}{#3}{#4}}% -\newcommand{\umlCNimpl}[4][]{\umlCNrelation[style={tikzuml implements style}, #1]{#2}{#3}{#4}}% -\newcommand{\umlCNreal}[4][]{\umlCNrelation[style={tikzuml implements style}, #1]{#2}{#3}{#4}}% -\newcommand{\umlCNassoc}[4][]{\umlCNrelation[style={tikzuml association style}, #1]{#2}{#3}{#4}}% -\newcommand{\umlCNuniassoc}[4][]{\umlCNrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}{#4}}% -\newcommand{\umlCNaggreg}[4][]{\umlCNrelation[style={tikzuml aggregation style}, #1]{#2}{#3}{#4}}% -\newcommand{\umlCNuniaggreg}[4][]{\umlCNrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}{#4}}% -\newcommand{\umlCNcompo}[4][]{\umlCNrelation[style={tikzuml composition style}, #1]{#2}{#3}{#4}}% -\newcommand{\umlCNunicompo}[4][]{\umlCNrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}{#4}}% -\newcommand{\umlCNimport}[4][]{\umlCNrelation[style={tikzuml import style}, #1]{#2}{#3}{#4}}% -\newcommand{\umlCNdep}[4][]{\umlCNrelation[style={tikzuml dependency style}, #1]{#2}{#3}{#4}}% -\newcommand{\umlCNfriend}[4][]{% - \pgfkeys{/tikzuml/friendrelation/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR : in umlCNfriend, forbidden option stereo}% - }{}% - }}% - \pgfkeys{/tikzuml/friendrelation/.cd, #1}% - \umlCNrelation[stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}{#4}% -}% - -% define a note -% arg : attached class -% label of the note -% optional : x,y coordinates of the note -% width of the note -% draw, fill, text colors -\newcommand{\umlnote}[3][]{ - \pgfkeys{/tikzuml/note/.cd,% - x/.initial=0, y/.initial=0, width/.initial=3cm, geometry/.initial=--,% - weight/.initial=0.5, arm/.initial={auto},% - anchor1/.initial={tikzumlEmpty}, anchor2/.initial={tikzumlEmpty},% - draw/.initial=\tikzumldrawcolor, fill/.initial=\tikzumlfillnotecolor,% - text/.initial=\tikzumltextcolor,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \errmessage{TIKZUML ERROR : in umlnote, invalid option \keyname}% - }}% - \pgfkeys{/tikzuml/note/.cd, #1}% - \pgfkeys{/tikzuml/note/.cd,% - x/.get=\tikzumlnoteX, y/.get=\tikzumlnoteY, width/.get=\notetextwidth,% - geometry/.get=\tikzumlnotegeometry,% - weight/.get=\tikzumlnoteweight, arm/.get=\tikzumlnotearm,% - anchor1/.get=\tikzumlnoteSrcAnchor, anchor2/.get=\tikzumlnoteDestAnchor,% - draw/.get=\tikzumlnotedraw, fill/.get=\tikzumlnotefill,% - text/.get=\tikzumlnotetext}% - % - \def\tikzumlClassName{#2}% - \begingroup% - \def\_{_}\edef\x{\endgroup% - \def\noexpand\tikzumlClassNodeName{\tikzumlClassName}}\x% - % - % def anchors macros - \ifthenelse{\equal{\tikzumlnoteSrcAnchor}{tikzumlEmpty}}{% - \def\tikzumlnoteSrcAnchor{}% - }{% - \let\tikzumlnoteSrcAnchorold\tikzumlnoteSrcAnchor% - \def\tikzumlnoteSrcAnchor{.\tikzumlnoteSrcAnchorold}% - }% - % - \ifthenelse{\equal{\tikzumlnoteDestAnchor}{tikzumlEmpty}}{% - \def\tikzumlnoteDestAnchor{}% - }{% - \let\tikzumlnoteDestAnchorold\tikzumlnoteDestAnchor% - \def\tikzumlnoteDestAnchor{.\tikzumlnoteDestAnchorold}% - }% - % - \node[text=\tikzumlnotetext, text width=\notetextwidth, font=\tikzumlfont, outer sep=0, inner xsep=1ex, inner ysep=3ex] (note-\thetikzumlNoteNum-coord) at (\tikzumlnoteX, \tikzumlnoteY) {#3};% - \draw (note-\thetikzumlNoteNum-coord.north east) node[name=note-\thetikzumlNoteNum-right-top, below=2ex, coordinate] {};% - \draw (note-\thetikzumlNoteNum-coord.north east) node[name=note-\thetikzumlNoteNum-top-right, left=2ex, coordinate] {};% - \draw[draw=\tikzumlnotedraw, fill=\tikzumlnotefill] (note-\thetikzumlNoteNum-coord.south west) -- (note-\thetikzumlNoteNum-coord.south east) -- (note-\thetikzumlNoteNum-right-top.base) -- (note-\thetikzumlNoteNum-top-right.base) -- (note-\thetikzumlNoteNum-coord.north west) -- cycle;% - \node[text=\tikzumlnotetext, text width=\notetextwidth, outer sep=0, inner xsep=1ex, inner ysep=3ex, font=\tikzumlfont] (note-\thetikzumlNoteNum) at (note-\thetikzumlNoteNum-coord) {#3};% - \draw[draw=\tikzumlnotedraw] (note-\thetikzumlNoteNum-right-top) -| (note-\thetikzumlNoteNum-top-right);% - % - \pgfmathsetmacro{\tikzumlnoteweightT}{1-\tikzumlnoteweight}% - \node (note-\thetikzumlNoteNum-middle) at (barycentric cs:note-\thetikzumlNoteNum-coord=\tikzumlnoteweight,\tikzumlClassNodeName=\tikzumlnoteweightT) {};% - % - \ifthenelse{\equal{\tikzumlnotegeometry}{--}% - \OR\equal{\tikzumlnotegeometry}{-|}% - \OR\equal{\tikzumlnotegeometry}{|-}}{% - \edef\tikzumlnotepath{\tikzumlnotegeometry} - }{% - \ifthenelse{\equal{\tikzumlnotegeometry}{-|-}}{% - \ifthenelse{\equal{\tikzumlnotearm}{auto}}{% - \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-coord\tikzumlnoteSrcAnchor -| note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center |- \tikzumlClassNodeName\tikzumlnoteDestAnchor) --}% - }{% - \draw (note-\thetikzumlNoteNum-coord\tikzumlnoteSrcAnchor)+(\tikzumlnotearm,0) node[name=note-\thetikzumlNoteNum-tmp] {}; - \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-tmp.center) |-}% - }% - }{% - \ifthenelse{\equal{\tikzumlnotegeometry}{|-|}}{% - \ifthenelse{\equal{\tikzumlnotearm}{auto}}{% - \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-coord\tikzumlnoteSrcAnchor |- note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center -| \tikzumlClassNodeName\tikzumlnoteDestAnchor) --}% - }{% - \draw (note-\thetikzumlNoteNum-coord\tikzumlnoteSrcAnchor)+(0,\tikzumlnotearm) node[name=note-\thetikzumlNoteNum-tmp] {}; - \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-tmp.center) -|}% - }% - - }{% - \errmessage{TIKZUML ERROR : Unknown geometry value !!! It should be in the following list : --, |-, -|, |-|, -|-}% - }% - }% - }% - % - \begin{pgfonlayer}{connections}% - \draw[dashed] (note-\thetikzumlNoteNum-coord\tikzumlnoteSrcAnchor) \tikzumlnotepath (\tikzumlClassNodeName\tikzumlnoteDestAnchor);% - \end{pgfonlayer}% - % - \stepcounter{tikzumlNoteNum}% -}% - -% shortcuts for note with geometry -\newcommand{\umlHVnote}[3][]{% - \pgfkeys{/tikzuml/note/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{geometry}}{% - \errmessage{TIKZUML ERROR : in umlHVnote, forbidden option geometry}% - }{}% - }}% - \pgfkeys{/tikzuml/note/.cd, #1}% - \umlnote[geometry=-|, #1]{#2}{#3}% -}% -\newcommand{\umlVHnote}[3][]{% - \pgfkeys{/tikzuml/note/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{geometry}}{% - \errmessage{TIKZUML ERROR : in umlVHnote, forbidden option geometry}% - }{}% - }}% - \pgfkeys{/tikzuml/note/.cd, #1}% - \umlnote[geometry=|-, #1]{#2}{#3}% -}% -\newcommand{\umlVHVnote}[3][]{% - \pgfkeys{/tikzuml/note/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{geometry}}{% - \errmessage{TIKZUML ERROR : in umlVHVnote, forbidden option geometry}% - }{}% - }}% - \pgfkeys{/tikzuml/note/.cd, #1}% - \umlnote[geometry=|-|, #1]{#2}{#3}% -}% -\newcommand{\umlHVHnote}[3][]{% - \pgfkeys{/tikzuml/note/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{geometry}}{% - \errmessage{TIKZUML ERROR : in umlHVHnote, forbidden option geometry}% - }{}% - }}% - \pgfkeys{/tikzuml/note/.cd, #1}% - \umlnote[geometry=-|-, #1]{#2}{#3}% -}% - -% define a uml association class (command) -% args : name of the class -% attributes of the class -% operations of the class -% optional : x,y coordinates of the class -% width of the class node -% type of class (class, interface, typedef, enum) -% template parameters -% draw, fill, text colors -\newcommand{\umlassocclass}[5][]{% - \pgfkeys{/tikzuml/assocclass/.cd,% - x/.initial=0, y/.initial=0, width/.initial=10ex, type/.initial=class,% - template/.initial={}, name/.initial={tikzumlEmpty}, geometry/.initial=--,% - weight/.initial=0.5, arm/.initial={auto},% - anchor1/.initial={tikzumlEmpty}, anchor2/.initial={tikzumlEmpty},% - draw/.initial=\tikzumldrawcolor,% - fill template/.initial=\tikzumlfilltemplatecolor,% - fill/.initial=\tikzumlfillclasscolor,% - text/.initial=\tikzumltextcolor,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \errmessage{TIKZUML ERROR : in umlassocclass, invalid option \keyname}% - }}% - % - \pgfkeys{/tikzuml/assocclass/.cd,#1}% - \pgfkeys{/tikzuml/assocclass/.cd,% - x/.get=\umlassocclassX, y/.get=\umlassocclassY,% - width/.get=\umlassocclassMinimumWidth, type/.get=\umlassocclassType,% - template/.get=\umlassocclassTemplateParam,% - name/.get=\umlassocclassName, geometry/.get=\tikzumlassocclassgeometry,% - weight/.get=\tikzumlassocclassweight, arm/.get=\tikzumlassocclassarm,% - anchor1/.get=\tikzumlassocclassSrcAnchor,% - anchor2/.get=\tikzumlassocclassDestAnchor,% - draw/.get=\tikzumlassocclassdraw, fill/.get=\tikzumlassocclassfill,% - text/.get=\tikzumlassocclasstext, fill template/.get=\tikzumlassocclasstemplate}% - % - \ifthenelse{\equal{\umlassocclassType}{class}\OR\equal{\umlassocclassType}{abstract}}{% - \def\tikzumlAssocClassType{}% - }{% - \def\tikzumlAssocClassType{\guillemotleft\umlassocclassType\guillemotright \\}% - }% - % - \ifthenelse{\equal{\umlassocclassTemplateParam}{}}{% - \def\tikzumlAssocClassVPadding{}% - \def\tikzumlAssocClassHPadding{}% - }{% - \def\tikzumlAssocClassVPadding{\vspace{0.1em} \\}% - \def\tikzumlAssocClassHPadding{\hspace{0.5ex} $ $}% - }% - % - \def\tikzumlAssocClassName{#2}% - \def\tikzumlAssocClassRelationName{#3}% - % - \begingroup% - \def\_{_}\edef\x{\endgroup% - \def\noexpand\tikzumlAssocClassNodeName{\tikzumlAssocClassName}}\x% - % - \begingroup% - \def\_{_}\edef\x{\endgroup% - \def\noexpand\tikzumlAssocClassRelationNodeName{\tikzumlAssocClassRelationName}}\x% - % - \ifthenelse{\equal{\umlassocclassName}{tikzumlEmpty}}{}{% - \def\tikzumlAssocClassNodeName{\umlassocclassName}% - }% - % - \StrSubstitute{\tikzumlAssocClassNodeName}{:}{@COLON@}[\tikzumlAssocClassNodeName] - % - \ifthenelse{\equal{\umlassocclassType}{abstract}}{% - \let\tikzumlAssocClassNameOld\tikzumlAssocClassName% - \def\tikzumlAssocClassName{{\it \tikzumlAssocClassNameOld}}% - }{}% - % - \def\tikzumlAssocClassPos{\umlassocclassX,\umlassocclassY}% - \def\tikzumlAssocClassAttributes{#4}% - \def\tikzumlAssocClassOperations{#5}% - % - % def anchors macros - \ifthenelse{\equal{\tikzumlassocclassSrcAnchor}{tikzumlEmpty}}{% - \def\tikzumlassocclassSrcAnchor{}% - }{% - \let\tikzumlassocclassSrcAnchorold\tikzumlassocclassSrcAnchor% - \def\tikzumlassocclassSrcAnchor{.\tikzumlassocclassSrcAnchorold}% - }% - % - \ifthenelse{\equal{\tikzumlassocclassDestAnchor}{tikzumlEmpty}}{% - \def\tikzumlassocclassDestAnchor{}% - }{% - \let\tikzumlassocclassDestAnchorold\tikzumlassocclassDestAnchor% - \def\tikzumlassocclassDestAnchor{.\tikzumlassocclassDestAnchorold}% - }% - % - \node[tikzuml class style, draw=\tikzumlassocclassdraw, fill=\tikzumlassocclassfill, text=\tikzumlassocclasstext, font=\tikzumlfont, minimum width=\umlassocclassMinimumWidth] (\tikzumlAssocClassNodeName) at (\tikzumlAssocClassPos) {\begin{tabular}{c}\tikzumlAssocClassVPadding \tikzumlAssocClassType \tikzumlAssocClassHPadding \textbf{\tikzumlAssocClassName} \tikzumlAssocClassHPadding \end{tabular}% - \nodepart{second}% - \begin{tabular}{l}% - \tikzumlAssocClassAttributes% - \end{tabular}% - \nodepart{third}% - \begin{tabular}{l}% - \tikzumlAssocClassOperations% - \end{tabular}% - };% - % - \ifthenelse{\equal{\umlassocclassTemplateParam}{}}{}{% - \draw (\tikzumlAssocClassNodeName.north east) node[tikzuml template style, name=\tikzumlAssocClassNodeName-template, draw=\tikzumlassocclassdraw, fill=\tikzumlassocclasstemplate, text=\tikzumlassocclasstext, font=\tikzumlfont] {\umlassocclassTemplateParam};% - }% - % - \pgfmathsetmacro{\tikzumlassocclassweightT}{1-\tikzumlassocclassweight} - \node (\tikzumlAssocClassNodeName-middle) at (barycentric cs:\tikzumlAssocClassNodeName=\tikzumlassocclassweight,\tikzumlAssocClassRelationNodeName=\tikzumlassocclassweightT) {};% - % - \ifthenelse{\equal{\tikzumlassocclassgeometry}{--}\OR\equal{\tikzumlassocclassgeometry}{-|}\OR\equal{\tikzumlassocclassgeometry}{|-}}{% - \edef\tikzumlassocclasspath{\tikzumlassocclassgeometry} - }{% - \ifthenelse{\equal{\tikzumlassocclassgeometry}{-|-}}{% - \ifthenelse{\equal{\tikzumlassocclassarm}{auto}}{% - \edef\tikzumlassocclasspath{-- (\tikzumlAssocClassNodeName\tikzumlassocclassSrcAnchor -| \tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center |- \tikzumlAssocClassRelationNodeName\tikzumlassocclassDestAnchor) --}% - }{% - \draw (\tikzumlAssocClassNodeName\tikzumlassocclassSrcAnchor)+(\tikzumlassocclassarm,0) node[name=\tikzumlAssocClassNodeName-tmp] {}; - \edef\tikzumlnotepath{-- (\tikzumlAssocClassNodeName-tmp.center) |-}% - }% - }{% - \ifthenelse{\equal{\tikzumlassocclassgeometry}{|-|}}{% - \ifthenelse{\equal{\tikzumlassocclassarm}{auto}}{% - \edef\tikzumlassocclasspath{-- (\tikzumlAssocClassNodeName\tikzumlassocclassSrcAnchor |- \tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center -| \tikzumlAssocClassRelationNodeName\tikzumlassocclassDestAnchor) --}% - }{% - \draw (\tikzumlAssocClassNodeName\tikzumlassocclassSrcAnchor)+(0,\tikzumlassocclassarm) node[name=\tikzumlAssocClassNodeName-tmp] {}; - \edef\tikzumlassocclasspath{-- (\thetikzumlAssocClassNodeName-tmp.center) -|}% - }% - - }{% - \errmessage{TIKZUML ERROR : Unknown geometry value !!! It should be in the following list : --, |-, -|, |-|, -|-}% - }% - }% - }% - % - \begin{pgfonlayer}{connections}% - \draw[dashed] (\tikzumlAssocClassNodeName\tikzumlassocclassSrcAnchor) \tikzumlassocclasspath (\tikzumlAssocClassRelationNodeName\tikzumlassocclassDestAnchor);% - \end{pgfonlayer}% - % - - - % - % add to fit - \ifnum\c@tikzumlPackageLevel>0% - \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}% - \ifthenelse{\equal{\umlassocclassTemplateParam}{}}{% - \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlAssocClassNodeName)(\tikzumlAssocClassNodeName-middle)}% - }{% - \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlAssocClassNodeName) (\tikzumlAssocClassNodeName-template)(\tikzumlAssocClassNodeName-middle)}% - }% - \stepcounter{tikzumlPackageClassNum}% - \fi% -}% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% use case diagrams % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\tikzstyle{tikzuml usecase style}=[ellipse, text centered]% -\tikzstyle{tikzuml actor style}=[ellipse, inner sep=0, outer sep=0]% - -\newcounter{tikzumlSystemUseCaseNum}% -\newcounter{tikzumlSystemLevel}% -\newcounter{tikzumlUseCaseNum}% -\newcounter{tikzumlActorNum}% - -% define a system -% arg : name -% optional : x, y coordinates of the system -% draw, fill, text colors -\newenvironment{umlsystem}[2][]{% - \gdef\tikzumlSystemFit{}% - \def\tikzumlSystemName{#2}% - \setcounter{tikzumlSystemUseCaseNum}{0}% - % - \pgfkeys{/tikzuml/system/.cd,% - x/.initial=0, y/.initial=0, x/.default=0, y/.default=0,% - draw/.initial=\tikzumldrawcolor, fill/.initial=\tikzumlfillsystemcolor,% - text/.initial=\tikzumltextcolor,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \errmessage{TIKZUML ERROR : in umlsystem, invalid option \keyname}% - }}% - % - \pgfkeys{/tikzuml/system/.cd, #1}% - \pgfkeys{/tikzuml/system/.cd,% - x/.get=\xshift, y/.get=\yshift,% - draw/.get=\tikzumlsystemdraw, fill/.get=\tikzumlsystemfill,% - text/.get=\tikzumlsystemtext}% - % - \stepcounter{tikzumlSystemLevel}% - % - \begin{scope}[xshift=\xshift cm, yshift=\yshift cm]% -}{% - \addtocounter{tikzumlSystemLevel}{-1}% - % if contains no usecase, one define a fictive node to enable the fit option - \ifnum\c@tikzumlSystemUseCaseNum=0% - \node[inner xsep=10ex, inner ysep=1em] (\tikzumlSystemName-root) at (0,0) {};% - \xdef\tikzumlSystemFit{(\tikzumlSystemName-root)}% - \fi% - % - \begin{pgfonlayer}{background}% - \node[inner ysep=1em, inner xsep=2ex, fit = \tikzumlSystemFit] (\tikzumlSystemName-tmp) {};% - \node[text=\tikzumlsystemtext, font=\tikzumlfont] (\tikzumlSystemName-caption-tmp) at (\tikzumlSystemName-tmp.north) {\tikzumlSystemName};% - \node[draw=\tikzumlsystemdraw, fill=\tikzumlsystemfill, text=\tikzumlsystemtext, font=\tikzumlfont, inner ysep=1em, inner xsep=2ex, fit = (\tikzumlSystemName-tmp) (\tikzumlSystemName-caption-tmp)] (\tikzumlSystemName) {};% - \node[text=\tikzumlsystemtext, font=\tikzumlfont] (\tikzumlSystemName-caption) at (\tikzumlSystemName-caption-tmp.north) {\tikzumlSystemName};% - \end{pgfonlayer}% - \end{scope}% - % -}% - -% define a use case -% arg : label of the use case -% optional : x, y coordinates of the use case -% name of the node -% draw, fill, text colors -\newcommand{\umlusecase}[2][]{% - \stepcounter{tikzumlUseCaseNum}% - \pgfkeys{/tikzuml/usecase/.cd,% - x/.initial=0, y/.initial=0, width/.initial=auto,% - name/.initial=usecase-\thetikzumlUseCaseNum,% - draw/.initial=\tikzumldrawcolor, fill/.initial=\tikzumlfillusecasecolor,% - text/.initial=\tikzumltextcolor,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \errmessage{TIKZUML ERROR : in umlusecase, invalid option \keyname}% - }}% - \pgfkeys{/tikzuml/usecase/.cd, #1}% - \pgfkeys{/tikzuml/usecase/.cd,% - x/.get=\posx, y/.get=\posy, width/.get=\tikzumlusecasetextwidth,% - name/.get=\usecaseName,% - draw/.get=\tikzumlusecasedraw, fill/.get=\tikzumlusecasefill,% - text/.get=\tikzumlusecasetext}% - % - \def\tikzumlUseCaseText{#2}% - % - \def\tikzumlUseCasePos{\posx,\posy}% - % - \ifthenelse{\equal{\tikzumlusecasetextwidth}{auto}}{% - \node[tikzuml usecase style, draw=\tikzumlusecasedraw, fill=\tikzumlusecasefill, text=\tikzumlusecasetext, font=\tikzumlfont] (\usecaseName) at (\tikzumlUseCasePos) {\tikzumlUseCaseText};% - }{% - \node[tikzuml usecase style, draw=\tikzumlusecasedraw, fill=\tikzumlusecasefill, text=\tikzumlusecasetext, font=\tikzumlfont, text width=\tikzumlusecasetextwidth] (\usecaseName) at (\tikzumlUseCasePos) {\tikzumlUseCaseText};% - }% - % - % add to fit - \ifnum\c@tikzumlSystemLevel>0% - \let\tikzumlSystemFitOld\tikzumlSystemFit% - \xdef\tikzumlSystemFit{\tikzumlSystemFitOld (\usecaseName)}% - \stepcounter{tikzumlSystemUseCaseNum}% - \fi% -}% - -% define the actor symbol -% optional : global tikzpicture styles -\newcommand{\picturedactor}[1]{% - \pgfkeys{/tikzuml/picactor/.cd, scale/.initial=1, .unknown/.code={}}% - \pgfkeys{/tikzuml/picactor/.cd,#1}% - \pgfkeys{/tikzuml/picactor/.cd, scale/.get=\tikzumlpicactorscale}% - % - \begin{tikzpicture}[#1] - \coordinate (head) at (0,4ex); - \coordinate (left-hand) at (-2ex,2ex); - \coordinate (right-hand) at (2ex,2ex); - \coordinate (left-foot) at (-2ex,-2ex); - \coordinate (right-foot) at (2ex,-2ex); - \coordinate (empty) at (0,-3ex); - \draw (empty) (0,0) -- (head); - \draw (left-hand) -- (right-hand); - \draw (0,0) -- (left-foot) (0,0) -- (right-foot); - \node[fill, draw, circle, inner sep=\tikzumlpicactorscale*0.3333ex, minimum size=\tikzumlpicactorscale*2ex] at (head) {}; - \end{tikzpicture} -}% - -% define an actor -% arg : var name -% optional : x, y coordinates of the actor -% name of the node -% draw, text colors -\newcommand{\umlactor}[2][]{% - \stepcounter{tikzumlActorNum}% - \pgfkeys{/tikzuml/actor/.cd,% - x/.initial=0, y/.initial=0, scale/.initial=1, below/.initial=0.5cm,% - draw/.initial=\tikzumldrawcolor, text/.initial=\tikzumltextcolor,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \errmessage{TIKZUML ERROR : in umlactor, invalid option \keyname}% - }}% - \pgfkeys{/tikzuml/actor/.cd, #1}% - \pgfkeys{/tikzuml/actor/.cd,% - x/.get=\posx, y/.get=\posy, scale/.get=\tikzumlactorscale,% - below/.get=\tikzumlactorbelow,% - draw/.get=\tikzumlactordraw, text/.get=\tikzumlactortext}% - % - \def\tikzumlActorName{#2}% - \begingroup% - \def\_{_}\edef\x{\endgroup% - \def\noexpand\tikzumlActorNodeName{\tikzumlActorName}}\x% - % - \def\tikzumlActorPos{\posx,\posy}% - % - \ifthenelse{\equal{}{tikzumlEmpty}}{}{} - \node[tikzuml actor style, text=\tikzumlactortext, font=\tikzumlfont] (\tikzumlActorNodeName) at (\tikzumlActorPos) {\picturedactor{scale=\tikzumlactorscale, fill=white, draw=\tikzumlactordraw, thick}};% - \node[text=\tikzumlactortext, font=\tikzumlfont, below=\tikzumlactorscale*\tikzumlactorbelow] at (\tikzumlActorNodeName) {\tikzumlActorName};% - % -}% - -% shortcuts for include and extend relation -\newcommand{\umlinclude}[3][]{% - \pgfkeys{/tikzuml/includerelation/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR : in umlinclude, forbidden option stereo}% - }{% - \ifthenelse{\equal{\keyname}{geometry}}{% - \errmessage{TIKZUML ERROR : in umlinclude, forbidden option geometry}% - }{}% - }% - }}% - \pgfkeys{/tikzuml/includerelation/.cd, #1}% - \umlrelation[stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}% -}% -\newcommand{\umlextend}[3][]{% - \pgfkeys{/tikzuml/extendrelation/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR : in umlextend, forbidden option stereo}% - }{% - \ifthenelse{\equal{\keyname}{geometry}}{% - \errmessage{TIKZUML ERROR : in umlextend, forbidden option geometry}% - }{}% - }% - }}% - \pgfkeys{/tikzuml/extendrelation/.cd, #1}% - \umlrelation[stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}% -}% - -\newcommand{\umlHVinclude}[3][]{% - \pgfkeys{/tikzuml/includerelation/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR : in umlHVinclude, forbidden option stereo}% - }{% - \ifthenelse{\equal{\keyname}{geometry}}{% - \errmessage{TIKZUML ERROR : in umlHVinclude, forbidden option geometry}% - }{}% - }% - }}% - \pgfkeys{/tikzuml/includerelation/.cd, #1}% - \umlrelation[geometry=-|, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}% -}% -\newcommand{\umlHVextend}[3][]{% - \pgfkeys{/tikzuml/extendrelation/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR : in umlHVextend, forbidden option stereo}% - }{% - \ifthenelse{\equal{\keyname}{geometry}}{% - \errmessage{TIKZUML ERROR : in umlHVextend, forbidden option geometry}% - }{}% - }% - }}% - \pgfkeys{/tikzuml/extendrelation/.cd, #1}% - \umlrelation[geometry=-|, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}% -}% - -\newcommand{\umlVHinclude}[3][]{% - \pgfkeys{/tikzuml/includerelation/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR : in umlVHinclude, forbidden option stereo}% - }{% - \ifthenelse{\equal{\keyname}{geometry}}{% - \errmessage{TIKZUML ERROR : in umlVHinclude, forbidden option geometry}% - }{}% - }% - }}% - \pgfkeys{/tikzuml/includerelation/.cd, #1}% - \umlrelation[geometry=|-, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}% -}% -\newcommand{\umlVHextend}[3][]{% - \pgfkeys{/tikzuml/extendrelation/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR :in umlVHextend, forbidden option stereo}% - }{% - \ifthenelse{\equal{\keyname}{geometry}}{% - \errmessage{TIKZUML ERROR : in umlVHextend, forbidden option geometry}% - }{}% - }% - }}% - \pgfkeys{/tikzuml/extendrelation/.cd, #1}% - \umlrelation[geometry=|-, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}% -}% - -\newcommand{\umlHVHinclude}[3][]{% - \pgfkeys{/tikzuml/includerelation/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR : in umlHVHinclude, forbidden option stereo}% - }{% - \ifthenelse{\equal{\keyname}{geometry}}{% - \errmessage{TIKZUML ERROR : in umlHVHinclude, forbidden option geometry}% - }{}% - }% - }}% - \pgfkeys{/tikzuml/includerelation/.cd, #1}% - \umlrelation[geometry=-|-, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}% -}% -\newcommand{\umlHVHextend}[3][]{% - \pgfkeys{/tikzuml/extendrelation/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR : in umlHVHextend, forbidden option stereo}% - }{% - \ifthenelse{\equal{\keyname}{geometry}}{% - \errmessage{TIKZUML ERROR : in umlHVHextend, forbidden option geometry}% - }{}% - }% - }}% - \pgfkeys{/tikzuml/extendrelation/.cd, #1}% - \umlrelation[geometry=-|-, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}% -}% - -\newcommand{\umlVHVinclude}[3][]{% - \pgfkeys{/tikzuml/includerelation/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR : in umlVHVinclude, forbidden option stereo}% - }{% - \ifthenelse{\equal{\keyname}{geometry}}{% - \errmessage{TIKZUML ERROR : in umlVHVinclude, forbidden option geometry}% - }{}% - }% - }}% - \pgfkeys{/tikzuml/includerelation/.cd, #1}% - \umlrelation[geometry=|-|, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}% -}% -\newcommand{\umlVHVextend}[3][]{% - \pgfkeys{/tikzuml/extendrelation/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR : in umlVHVextend, forbidden option stereo}% - }{% - \ifthenelse{\equal{\keyname}{geometry}}{% - \errmessage{TIKZUML ERROR : in umlVHVextend, forbidden option geometry}% - }{}% - }% - }}% - \pgfkeys{/tikzuml/extendrelation/.cd, #1}% - \umlrelation[geometry=|-|, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}% -}% - -\newcommand{\umlCNinclude}[4][]{% - \pgfkeys{/tikzuml/includerelation/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR : in umlCNinclude, forbidden option stereo}% - }{}% - }}% - \pgfkeys{/tikzuml/includerelation/.cd, #1}% - \umlCNrelation[stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}{#4}% -}% - -\newcommand{\umlCNextend}[4][]{% - \pgfkeys{/tikzuml/extendrelation/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR : in umlCNextend, forbidden option stereo}% - }{}% - }}% - \pgfkeys{/tikzuml/extendrelation/.cd, #1}% - \umlCNrelation[stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}{#4}% -}% - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% state diagrams % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - -\tikzstyle{tikzuml state style}=[rectangle split, rectangle split parts=2, rounded corners, inner xsep=1.5ex]% -\tikzstyle{tikzuml transition style}=[color=\tikzumldrawcolor, rounded corners, -angle 45]% - -\newcounter{tikzumlStateJoinNum}% -\newcounter{tikzumlStateDecisionNum}% -\newcounter{tikzumlStateInitialNum}% -\newcounter{tikzumlStateFinalNum}% -\newcounter{tikzumlStateEnterNum}% -\newcounter{tikzumlStateExitNum}% -\newcounter{tikzumlStateEndNum}% -\newcounter{tikzumlStateHistoryNum}% -\newcounter{tikzumlStateDeepHistoryNum}% -\newcounter{tikzumlStateLevel}% -\newcounter{tikzumlStateSubStateNum}% -\newcounter{tikzumlStateText}% - -\newcommand{\umlstatejoin}[1][]{% - \pgfkeys{/tikzuml/statejoin/.cd,% - x/.initial=0, y/.initial=0, width/.initial=3ex,% - name/.initial=statejoin-\thetikzumlStateJoinNum,% - color/.initial=\tikzumldrawcolor,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \errmessage{TIKZUML ERROR : in umlstatejoin, invalid option \keyname}% - }}% - \pgfkeys{/tikzuml/statejoin/.cd, #1}% - \pgfkeys{/tikzuml/statejoin/.cd,% - x/.get=\posx, y/.get=\posy, width/.get=\tikzumlstatejoinwidth,% - name/.get=\tikzumlstatejoinname, color/.get=\tikzumlstatejoincolor}% - % - \def\tikzumlStateJoinPos{\posx,\posy}% - % - \node[circle, minimum size=\tikzumlstatejoinwidth, draw=\tikzumlstatejoincolor, fill=\tikzumlstatejoincolor] (\tikzumlstatejoinname) at (\tikzumlStateJoinPos) {};% - % - % add to fit - \ifnum\c@tikzumlStateLevel>0% - \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% - \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlstatejoinname)}% - \stepcounter{tikzumlStateSubStateNum}% - \fi% - \stepcounter{tikzumlStateJoinNum}% -}% - -\newcommand{\umlstatedecision}[1][]{% - \pgfkeys{/tikzuml/statedecision/.cd,% - x/.initial=0, y/.initial=0, width/.initial=3ex,% - name/.initial=statedecision-\thetikzumlStateDecisionNum,% - color/.initial=\tikzumldrawcolor,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \errmessage{TIKZUML ERROR : in umlstatedecision, invalid option \keyname}% - }}% - \pgfkeys{/tikzuml/statedecision/.cd, #1}% - \pgfkeys{/tikzuml/statedecision/.cd,% - x/.get=\posx, y/.get=\posy, width/.get=\tikzumlstatedecisionwidth,% - name/.get=\tikzumlstatedecisionname, color/.get=\tikzumlstatedecisioncolor}% - % - \def\tikzumlStateDecisionPos{\posx,\posy}% - % - \node[rectangle, rotate=45, minimum size=\tikzumlstatedecisionwidth, draw=\tikzumlstatedecisioncolor] (\tikzumlstatedecisionname) at (\tikzumlStateDecisionPos) {};% - % - % add to fit - \ifnum\c@tikzumlStateLevel>0% - \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% - \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlstatedecisionname)}% - \stepcounter{tikzumlStateSubStateNum}% - \fi% - \stepcounter{tikzumlStateDecisionNum}% -}% - -\newcommand{\umlstateinitial}[1][]{% - \pgfkeys{/tikzuml/stateinitial/.cd,% - x/.initial=0, y/.initial=0, width/.initial=5ex,% - name/.initial=stateinitial-\thetikzumlStateInitialNum,% - color/.initial=\tikzumldrawcolor,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \errmessage{TIKZUML ERROR : in umlstateinitial, invalid option \keyname}% - }}% - \pgfkeys{/tikzuml/stateinitial/.cd, #1}% - \pgfkeys{/tikzuml/stateinitial/.cd,% - x/.get=\posx, y/.get=\posy, width/.get=\tikzumlstateinitialwidth,% - name/.get=\tikzumlstateinitialname, color/.get=\tikzumlstateinitialcolor}% - % - \def\tikzumlStateInitialPos{\posx,\posy}% - % - \node[circle, minimum size=\tikzumlstateinitialwidth, fill=\tikzumlstateinitialcolor] (\tikzumlstateinitialname) at (\tikzumlStateInitialPos) {};% - % - % add to fit - \ifnum\c@tikzumlStateLevel>0% - \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% - \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlstateinitialname)}% - \stepcounter{tikzumlStateSubStateNum}% - \fi% - \stepcounter{tikzumlStateInitialNum}% -}% - -\newcommand{\umlstatefinal}[1][]{% - \pgfkeys{/tikzuml/statefinal/.cd,% - x/.initial=0, y/.initial=0, width/.initial=5.5ex,% - name/.initial=statefinal-\thetikzumlStateFinalNum,% - color/.initial=\tikzumldrawcolor,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \errmessage{TIKZUML ERROR : in umlstatefinal, invalid option \keyname}% - }}% - \pgfkeys{/tikzuml/statefinal/.cd, #1}% - \pgfkeys{/tikzuml/statefinal/.cd, x/.get=\posx, y/.get=\posy, width/.get=\tikzumlstatefinalwidth,% - name/.get=\tikzumlstatefinalname, color/.get=\tikzumlstatefinalcolor}% - % - \def\tikzumlStateFinalPos{\posx,\posy}% - % - \node[circle, minimum size=\tikzumlstatefinalwidth, draw=\tikzumlstatefinalcolor, fill=\tikzumlstatefinalcolor, double, double distance=0.1cm] (\tikzumlstatefinalname) at (\tikzumlStateFinalPos) {};% - % - % add to fit - \ifnum\c@tikzumlStateLevel>0% - \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% - \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlstatefinalname)}% - \stepcounter{tikzumlStateSubStateNum}% - \fi% - \stepcounter{tikzumlStateFinalNum}% -}% - -\newcommand{\umlstateenter}[1][]{% - \pgfkeys{/tikzuml/stateenter/.cd,% - x/.initial=0, y/.initial=0, width/.initial=5ex,% - name/.initial=stateenter-\thetikzumlStateEnterNum,% - color/.initial=\tikzumldrawcolor,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \errmessage{TIKZUML ERROR : in umlstateenter, invalid option \keyname}% - }}% - \pgfkeys{/tikzuml/stateenter/.cd, #1}% - \pgfkeys{/tikzuml/stateenter/.cd,% - x/.get=\posx, y/.get=\posy, width/.get=\tikzumlstateenterwidth,% - name/.get=\tikzumlstateentername, color/.get=\tikzumlstateentercolor}% - % - \def\tikzumlStateEnterPos{\posx,\posy}% - % - \node[circle, minimum size=\tikzumlstateenterwidth, draw=\tikzumlstateentercolor] (\tikzumlstateentername) at (\tikzumlStateEnterPos) {};% - % - % add to fit - \ifnum\c@tikzumlStateLevel>0% - \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% - \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlstateentername)}% - \stepcounter{tikzumlStateSubStateNum}% - \fi% - \stepcounter{tikzumlStateEnterNum}% -}% - -\newcommand{\umlstateexit}[1][]{% - \pgfkeys{/tikzuml/stateexit/.cd,% - x/.initial=0, y/.initial=0, width/.initial=5ex,% - name/.initial=stateexit-\thetikzumlStateExitNum,% - color/.initial=\tikzumldrawcolor,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \errmessage{TIKZUML ERROR : in umlstateexit, invalid option \keyname}% - }}% - \pgfkeys{/tikzuml/stateexit/.cd, #1}% - \pgfkeys{/tikzuml/stateexit/.cd,% - x/.get=\posx, y/.get=\posy, width/.get=\tikzumlstateexitwidth,% - name/.get=\tikzumlstateexitname, color/.get=\tikzumlstateexitcolor}% - % - \def\tikzumlStateExitPos{\posx,\posy}% - % - \node[circle, minimum size=\tikzumlstateexitwidth, draw=\tikzumlstateexitcolor] (\tikzumlstateexitname) at (\tikzumlStateExitPos) {};% - \draw[draw=\tikzumlstateexitcolor] (\tikzumlstateexitname.north east) -- (\tikzumlstateexitname.south west) (\tikzumlstateexitname.north west) -- (\tikzumlstateexitname.south east); - % - % add to fit - \ifnum\c@tikzumlStateLevel>0% - \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% - \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlstateexitname)}% - \stepcounter{tikzumlStateSubStateNum}% - \fi% - \stepcounter{tikzumlStateExitNum}% -}% - -\newcommand{\umlstateend}[1][]{% - \pgfkeys{/tikzuml/stateend/.cd,% - x/.initial=0, y/.initial=0, width/.initial=5ex,% - name/.initial=stateend-\thetikzumlStateEndNum, color/.initial=\tikzumldrawcolor,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \errmessage{TIKZUML ERROR : in umlstateend, invalid option \keyname}% - }}% - \pgfkeys{/tikzuml/stateend/.cd, #1}% - \pgfkeys{/tikzuml/stateend/.cd, x/.get=\posx, y/.get=\posy, width/.get=\tikzumlstateendwidth,% - name/.get=\tikzumlstateendname, color/.get=\tikzumlstateendcolor}% - % - \def\tikzumlStateEndPos{\posx,\posy}% - % - \node[circle, minimum size=\tikzumlstateendwidth] (\tikzumlstateendname) at (\tikzumlStateEndPos) {};% - \draw[draw=\tikzumlstateendcolor] (\tikzumlstateendname.north east) -- (\tikzumlstateendname.south west) (\tikzumlstateendname.north west) -- (\tikzumlstateendname.south east); - % - % add to fit - \ifnum\c@tikzumlStateLevel>0% - \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% - \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlstateendname)}% - \stepcounter{tikzumlStateSubStateNum}% - \fi% - \stepcounter{tikzumlStateEndNum}% -}% - -\newcommand{\picturedhistory}[1]{% - \begin{tikzpicture}[#1] - \draw[thick] (-0.1cm,-0.15cm) -- (-0.1cm,0.15cm) - (-0.1cm,0) -- (0.1cm,0) - (0.1cm,-0.15cm) -- (0.1cm,0.15cm); - \end{tikzpicture} -}% - -\newcommand{\umlstatehistory}[1][]{% - \pgfkeys{/tikzuml/statehistory/.cd,% - x/.initial=0, y/.initial=0, width/.initial=5ex,% - name/.initial=statehistory-\thetikzumlStateHistoryNum,% - color/.initial=\tikzumldrawcolor,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \errmessage{TIKZUML ERROR : in umlstatehistory, invalid option \keyname}% - }}% - \pgfkeys{/tikzuml/statehistory/.cd, #1}% - \pgfkeys{/tikzuml/statehistory/.cd, x/.get=\posx, y/.get=\posy, width/.get=\tikzumlstatehistorywidth,% - name/.get=\tikzumlstatehistoryname, color/.get=\tikzumlstatehistorycolor}% - % - \def\tikzumlStateHistoryPos{\posx,\posy}% - % - \node[circle, minimum size=\tikzumlstatehistorywidth, draw=\tikzumlstatehistorycolor] (\tikzumlstatehistoryname) at (\tikzumlStateHistoryPos) {\picturedhistory{draw=\tikzumlstatehistorycolor}};% - % - % add to fit - \ifnum\c@tikzumlStateLevel>0% - \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% - \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlstatehistoryname)}% - \stepcounter{tikzumlStateSubStateNum}% - \fi% - \stepcounter{tikzumlStateHistoryNum}% -}% - -\newcommand{\pictureddeephistory}[1]{% - \begin{tikzpicture}[#1] - \draw[thick] (-0.1cm,-0.15cm) -- (-0.1cm,0.15cm) - (-0.1cm,0) -- (0.1cm,0) - (0.1cm,-0.15cm) -- (0.1cm,0.15cm) - (0.23cm,0.19cm) -- (0.23cm,0.11cm) - (0.20cm,0.17cm) -- (0.26cm,0.13cm) - (0.20cm,0.13cm) -- (0.26cm,0.17cm); - \end{tikzpicture} -}% - -\newcommand{\umlstatedeephistory}[1][]{% - \pgfkeys{/tikzuml/statedeephistory/.cd,% - x/.initial=0, y/.initial=0, width/.initial=5ex,% - name/.initial=statedeephistory-\thetikzumlStateDeepHistoryNum,% - color/.initial=\tikzumldrawcolor,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \errmessage{TIKZUML ERROR : in umlstatedeephistory, invalid option \keyname}% - }}% - \pgfkeys{/tikzuml/statedeephistory/.cd, #1}% - \pgfkeys{/tikzuml/statedeephistory/.cd, x/.get=\posx, y/.get=\posy, width/.get=\tikzumlstatedeephistorywidth,% - name/.get=\tikzumlstatedeephistoryname, color/.get=\tikzumlstatedeephistorycolor}% - % - \def\tikzumlStateDeepHistoryPos{\posx,\posy}% - % - \node[circle, minimum size=\tikzumlstatedeephistorywidth, draw=\tikzumlstatedeephistorycolor] (\tikzumlstatedeephistoryname) at (\tikzumlStateDeepHistoryPos) {\pictureddeephistory{draw=\tikzumlstatedeephistorycolor}};% - % - % add to fit - \ifnum\c@tikzumlStateLevel>0% - \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% - \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlstatedeephistoryname)}% - \stepcounter{tikzumlStateSubStateNum}% - \fi% - \stepcounter{tikzumlStateDeepHistoryNum}% -}% - -% define a uml state -% args : name of the state -% content of the state -% optional args : x,y coordinates of the state -% width of the state node -\newenvironment{umlstate}[2][]{% - \ifnum\thetikzumlStateLevel>0% - \let\tikzumlState@nameold\tikzumlState@fitname% - \let\tikzumlState@parentold\tikzumlState@parent% - \edef\tikzumlState@parent{\tikzumlState@parentold @@\tikzumlState@nameold}% - \else% - \def\tikzumlState@parent{}% - \fi% - - \stepcounter{tikzumlStateLevel}% - - \pgfkeys{/tikzuml/state/.cd,% - x/.initial=0, y/.initial=0, width/.initial=8ex, type/.initial=class,% - name/.initial={},% - entry/.initial={}, do/.initial={}, exit/.initial={},% - draw/.initial=\tikzumldrawcolor, fill/.initial=\tikzumlfillstatecolor,% - text/.initial=\tikzumltextcolor,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \errmessage{TIKZUML ERROR : in umlstate, invalid option \keyname}% - }}% - \pgfkeys{/tikzuml/state/.cd, #1}% - \pgfkeys{/tikzuml/state/.cd,% - x/.get=\tikzumlstateX, y/.get=\tikzumlstateY, width/.get=\umlstateMinimumWidth,% - type/.get=\umlstateType, name/.get=\umlstateName,% - entry/.get=\umlstateentry, do/.get=\umlstatedo, exit/.get=\umlstateexit,% - draw/.get=\tikzumlstatedraw, fill/.get=\tikzumlstatefill,% - text/.get=\tikzumlstatetext}% - % - \ifthenelse{\equal{\umlstateName}{}}{% - \edef\tikzumlState@name{#2}% - }{% - \edef\tikzumlState@name{\umlstateName}% - }% - % - \begingroup% - \def\_{@}\edef\x{\endgroup% - \def\noexpand\tikzumlState@fitname{\tikzumlState@name}}\x% - % - \let\tikzumlState@nodeNameold\tikzumlState@nodeName% - \def\tikzumlState@caption{#2}% - % - \begingroup% - \def\_{_}\edef\x{\endgroup% - \def\noexpand\tikzumlState@nodeName{\tikzumlState@name}}\x% - % - \expandafter\gdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{}% - % - \setcounter{tikzumlStateSubStateNum}{0}% - \setcounter{tikzumlStateText}{0}% - % - \def\tikzumlStateText{tikzumlEmpty}% - \begin{scope}[xshift=\tikzumlstateX cm, yshift=\tikzumlstateY cm]% -}{% - % - \def\tikzumlstaterootlabel{\phantom{\tikzumlState@nodeName}}% - % - \def\tikzumlstaterootinnerysep{0.5ex}% - \def\tikzumlstatebodyinnerysep{2ex}% - % - \ifthenelse{\equal{\umlstateentry}{}}{}{% - \def\tikzumlStateText{entry/\umlstateentry}% - \setcounter{tikzumlStateText}{1}% - \ifnum\c@tikzumlStateSubStateNum=0% - \def\tikzumlstatebodyinnerysep{0}% - \def\tikzumlstaterootinnerysep{0}% - \fi% - }% - \ifthenelse{\equal{\umlstatedo}{}}{}{% - \ifnum\c@tikzumlStateText=0% - \def\tikzumlStateText{do/\umlstatedo}% - \else% - \let\tikzumlStateTextOld\tikzumlStateText% - \def\tikzumlStateText{\tikzumlStateTextOld \\ do/\umlstatedo}% - \fi% - \setcounter{tikzumlStateText}{1}% - \ifnum\c@tikzumlStateSubStateNum=0% - \def\tikzumlstatebodyinnerysep{0}% - \def\tikzumlstaterootinnerysep{0}% - \fi% - }% - \ifthenelse{\equal{\umlstateexit}{}}{}{% - \ifnum\c@tikzumlStateText=0% - \def\tikzumlStateText{exit/\umlstateexit}% - \else% - \let\tikzumlStateTextOld\tikzumlStateText% - \def\tikzumlStateText{\tikzumlStateTextOld \\ exit/\umlstateexit}% - \fi% - \setcounter{tikzumlStateText}{1}% - \ifnum\c@tikzumlStateSubStateNum=0% - \def\tikzumlstatebodyinnerysep{0}% - \def\tikzumlstaterootinnerysep{0}% - \fi% - }% - % - \addtocounter{tikzumlStateLevel}{-1}% - \begin{pgfonlayer}{state\thetikzumlStateLevel}% - % - % if contains nothing, one define a fictive node to enable the fit option - \ifnum\c@tikzumlStateSubStateNum=0% - \node[inner ysep=\tikzumlstaterootinnerysep, minimum width=\umlstateMinimumWidth] (\tikzumlState@nodeName-root) at (0,0) {\tikzumlstaterootlabel};% - \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{(\tikzumlState@nodeName-root)}% - \fi% - % - \ifnum\c@tikzumlStateLevel>0% - \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent\endcsname}% - \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent\endcsname{\tikzumlStateFitTmp (\tikzumlState@nodeName-body) (\tikzumlState@nodeName-caption)}% - \stepcounter{tikzumlStateSubStateNum}% - \fi% - % - \node[inner xsep=2ex, inner ysep=\tikzumlstatebodyinnerysep, fit = \csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname] (\tikzumlState@nodeName-body) {};% - \def\tikzumlState@orig{body}% - \ifnum\c@tikzumlStateText=1% - \node[above=0] (\tikzumlState@nodeName-texttmp) at (\tikzumlState@nodeName-\tikzumlState@orig.north) {\begin{tabular}{l}\tikzumlStateText \end{tabular}};% - \def\tikzumlState@orig{texttmp}% - \fi% - \node[above] (\tikzumlState@nodeName-captiontmp) at (\tikzumlState@nodeName-\tikzumlState@orig.north) {\tikzumlState@caption};% - \node[rounded corners, draw=\tikzumlstatedraw, fill=\tikzumlstatefill, name=\tikzumlState@nodeName, fit=(\tikzumlState@nodeName-body) (\tikzumlState@nodeName-captiontmp)] {};% - \ifnum\c@tikzumlStateText=1% - \node (\tikzumlState@nodeName-text) at (\tikzumlState@nodeName-texttmp) {\begin{tabular}{l}\tikzumlStateText \end{tabular}};% - \fi% - \node (\tikzumlState@nodeName-caption) at (\tikzumlState@nodeName-captiontmp) {\tikzumlState@caption};% - \draw (\tikzumlState@nodeName-caption.south -| \tikzumlState@nodeName.north west) -- (\tikzumlState@nodeName-caption.south -| \tikzumlState@nodeName.north east);% - \end{pgfonlayer}% - \end{scope}% -}% - -% shortcut for empty state -\newcommand{\umlbasicstate}[2][]{\begin{umlstate}[#1]{#2} \end{umlstate}}% - -% command to add text in a state -\newcommand{\umlstatetext}[1]{% - \def\tikzumlStateText{#1}% - \setcounter{tikzumlStateText}{1}% -}% - -% shortcuts for state transitions macros -\newcommand{\umltrans}[3][]{% - \ifthenelse{\equal{#2}{#3}}{% - \umlrelation[style={tikzuml transition style}, recursive mode=transition, #1]{#2}{#3}% - }{% - \umlrelation[style={tikzuml transition style}, #1]{#2}{#3}% - }% -}% -\newcommand{\umlHVtrans}[3][]{\umlHVrelation[style={tikzuml transition style}, #1]{#2}{#3}}% -\newcommand{\umlVHtrans}[3][]{\umlVHrelation[style={tikzuml transition style}, #1]{#2}{#3}}% -\newcommand{\umlVHVtrans}[3][]{\umlVHVrelation[style={tikzuml transition style}, #1]{#2}{#3}}% -\newcommand{\umlHVHtrans}[3][]{\umlHVHrelation[style={tikzuml transition style}, #1]{#2}{#3}}% -\newcommand{\umlCNtrans}[4][]{\umlCNrelation[style={tikzuml transition style}, #1]{#2}{#3}{#4}}% - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% sequence diagrams % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\tikzstyle{tikzuml synchron-msg style}=[color=\tikzumldrawcolor, -triangle 45]% -\tikzstyle{tikzuml asynchron-msg style}=[color=\tikzumldrawcolor, -angle 45]% -\tikzstyle{tikzuml return-msg style}=[color=\tikzumldrawcolor, dashed, -angle 45]% -\tikzstyle{tikzuml call return style}=[color=\tikzumldrawcolor, dashed, -angle 45]% -\tikzstyle{tikzuml activity style}=[inner xsep=1ex, inner ysep=1ex]% - -\newcounter{tikzumlObjectNum} -\newcounter{tikzumlCallLevel} -\newcounter{tikzumlCallNum} -\newcounter{tikzumlFragmentLevel} -\newcounter{tikzumlFragmentLevelNum} -\newcounter{tikzumlFragmentNum} -\newcounter{tikzumlFragmentPartNum} -\newcounter{tikzumlCallStartFragmentNum} -\newcounter{tikzumlCallEndFragmentNum} - -% define a sequence diagram -% -\newenvironment{umlseqdiag}{% - \gdef\tikzumlInCreateCall{0}% - \setcounter{tikzumlObjectNum}{0}% - \setcounter{tikzumlCallLevel}{0}% - \setcounter{tikzumlCallNum}{0}% - \setcounter{tikzumlFragmentLevel}{0}% - \setcounter{tikzumlFragmentLevelNum}{0}% - \setcounter{tikzumlFragmentNum}{0}% - \setcounter{tikzumlFragmentPartNum}{0}% - \setcounter{tikzumlCallStartFragmentNum}{0}% - \setcounter{tikzumlCallEndFragmentNum}{0}% - % - \ifx \@umlactor \@empty - \newcommand{\umlactor}[2][]{% - \pgfkeys{/tikzuml/actorobj/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR : in umlactor, forbidden option stereo}% - }{}% - }}% - % - \pgfkeys{/tikzuml/actorobj/.cd, ##1}% - \umlobject[stereo=actor, ##1]{##2}% - }% - \else% - \renewcommand{\umlactor}[2][]{ - \pgfkeys{/tikzuml/actorobj/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR : in umlactor, forbidden option stereo}% - }{}% - }}% - % - \pgfkeys{/tikzuml/actorobj/.cd, ##1}% - \umlobject[stereo=actor, ##1]{##2}% - }% - \fi% - \begin{scope}[font=\tikzumlfont]% -}{% - % draw lifelines of each object - \begin{pgfonlayer}{lifelines}% - \foreach \id in \tikzumlIdList {% - \draw (\csname tikzumlLastChild@\id \endcsname)+(0,-2.5ex) node[inner sep=0, name=end-\id] {};% - \draw[dotted] (\id) -- (end-\id);% - }% - \end{pgfonlayer}% - \end{scope}% -}% - -% define the actor symbol -% optional : global tikzpicture styles -\newcommand{\pictureddatabase}[1]{% - \pgfkeys{/tikzuml/database/.cd, scale/.initial=1, .unknown/.code={}}% - \pgfkeys{/tikzuml/database/.cd,#1}% - \pgfkeys{/tikzuml/database/.cd, scale/.get=\tikzumldatabasescale}% - % - \begin{tikzpicture}[#1] - \node[fill, draw, ellipse, minimum width=\tikzumldatabasescale*4ex, minimum height=\tikzumldatabasescale*2ex, inner sep=0] (bottom) at (0,-2ex) {}; - \node[fill, draw, ellipse, minimum width=\tikzumldatabasescale*4ex, minimum height=\tikzumldatabasescale*2ex, inner sep=0] (top) at (0,4ex) {}; - \fill (bottom.west) rectangle (top.east); - \begin{scope} - \clip (-3.5ex,-0.5ex) rectangle (3.5ex,2.5ex); - \node[draw, dashed, ellipse, minimum width=\tikzumldatabasescale*4ex, minimum height=\tikzumldatabasescale*2ex, inner sep=0] (bottom2) at (0,-2ex) {}; - \end{scope} - \node[draw, ellipse, minimum width=\tikzumldatabasescale*4ex, minimum height=\tikzumldatabasescale*2ex, inner sep=0] (top2) at (0,4ex) {}; - \draw (bottom.west) -- (top.west) (bottom.east) -- (top.east); - \end{tikzpicture} -}% - -% define the actor symbol -% optional : global tikzpicture styles -\newcommand{\picturedentity}[1]{% - \pgfkeys{/tikzuml/entity/.cd, scale/.initial=1, .unknown/.code={}}% - \pgfkeys{/tikzuml/entity/.cd,#1}% - \pgfkeys{/tikzuml/entity/.cd, scale/.get=\tikzumlentityscale}% - % - \begin{tikzpicture}[#1]% - \node[fill, draw, circle, inner sep=0, minimum size=\tikzumlentityscale*5ex] (center) at (0,0) {};% - \draw (center.south) node[coordinate, name=bottom] {};% - \draw (bottom)+(-2ex,0) node[coordinate, name=bottom-left] {};% - \draw (bottom)+(2ex,0) node[coordinate, name=bottom-right] {};% - \draw (center) -- (bottom);% - \draw (bottom-left) -- (bottom-right);% - \end{tikzpicture}% -}% - -% define the actor symbol -% optional : global tikzpicture styles -\newcommand{\picturedboundary}[1]{% - \pgfkeys{/tikzuml/boundary/.cd, scale/.initial=1, .unknown/.code={}}% - \pgfkeys{/tikzuml/boundary/.cd,#1}% - \pgfkeys{/tikzuml/boundary/.cd, scale/.get=\tikzumlboundaryscale}% - % - \begin{tikzpicture}[#1] - \node[fill, draw, circle, inner sep=0, minimum size=\tikzumlboundaryscale*5ex] (center) at (0,0) {}; - \draw (center.west)+(-0.8ex,0) node[coordinate, name=left] {}; - \draw (left)+(0,0.2ex) node[coordinate, name=left-top] {}; - \draw (left)+(0,-0.2ex) node[coordinate, name=left-bottom] {}; - \draw (center) -- (left); - \draw (left-top) -- (left-bottom); - \end{tikzpicture} -}% - -% define the actor symbol -% optional : global tikzpicture styles -\newcommand{\picturedcontrol}[1]{% - \pgfkeys{/tikzuml/control/.cd, scale/.initial=1, .unknown/.code={}}% - \pgfkeys{/tikzuml/control/.cd,#1}% - \pgfkeys{/tikzuml/control/.cd, scale/.get=\tikzumlcontrolscale}% - % - \begin{tikzpicture}[#1, decoration={markings, mark=at position 0.25 with {\arrow{>}}}] - \node[fill, draw, circle, inner sep=0, minimum size=\tikzumlcontrolscale*5ex, postaction={decorate}] (center) at (0,0) {}; - \end{tikzpicture} -}% - -% define a uml object for a sequence diagram -% args : name of the object -% optional : x, y coordinates of the object -% stereotype of the object (object, actor, database, boundary, control, entity, multiobject) -% class of the object -% draw, fill, text colors -\newcommand{\umlobject}[2][]{ - \stepcounter{tikzumlObjectNum}% - % - \edef\tikzumlobject@ddot{:}% - \pgfkeys{/tikzuml/obj/.cd,% - x/.initial={tikzumlEmpty}, y/.initial=0, stereo/.initial=object,% - class/.initial={}, scale/.initial=1,% - draw/.initial=\tikzumldrawcolor, fill/.initial=\tikzumlfillobjectcolor,% - text/.initial=\tikzumltextcolor,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{no ddots}}{% - \edef\tikzumlobject@ddot{}% - }{% - \errmessage{TIKZUML ERROR : in umlobj, invalid option \keyname}% - }% - }}% - \pgfkeys{/tikzuml/obj/.cd, #1}% - \pgfkeys{/tikzuml/obj/.cd,% - x/.get=\tikzumlobjectX, y/.get=\tikzumlobjectY,% - stereo/.get=\tikzumlobjectstereo, class/.get=\tikzumlobjectclass,% - scale/.get=\tikzumlobjectscale,% - draw/.get=\tikzumlobjectdraw, fill/.get=\tikzumlobjectfill,% - text/.get=\tikzumlobjecttext}% - % - \ifthenelse{\equal{\tikzumlobjectX}{tikzumlEmpty}}{% - \pgfmathsetmacro{\tikzumlobjectX}{4*(\thetikzumlObjectNum-1)}% - }{}% - % - \def\tikzumlObjectName{#2}% - \expandafter\xdef\csname tikzumlLastChild@\tikzumlObjectName \endcsname{\tikzumlObjectName}% - % - \ifnum\thetikzumlObjectNum=1% - \xdef\tikzumlIdList{\tikzumlObjectName}% - \else% - \let\tikzumlIdListOld\tikzumlIdList% - \xdef\tikzumlIdList{\tikzumlIdListOld,\tikzumlObjectName}% - \fi% - % - \tikzstyle{tikzuml object box style}=[rectangle, text=\tikzumlobjecttext, font=\tikzumlfont]% - % - \ifthenelse{\equal{\tikzumlobjectstereo}{object}}{% - \tikzstyle{tikzuml object box style}+=[draw=\tikzumlobjectdraw, fill=\tikzumlobjectfill]% - }{% - \ifthenelse{\equal{\tikzumlobjectstereo}{multi}}{% - \tikzstyle{tikzuml object box style}+=[fill=\tikzumlobjectfill]% - }{}% - }% - % - \ifnum\tikzumlInCreateCall=1% - \draw (\tikzumlCreateCallObjectSrc -| \tikzumlobjectX,0) node[tikzuml object box style] (\tikzumlObjectName) {\tikzumlObjectName\tikzumlobject@ddot\tikzumlobjectclass};% - \else% - \node[tikzuml object box style] (\tikzumlObjectName) at (\tikzumlobjectX,\tikzumlobjectY) {\tikzumlObjectName\tikzumlobject@ddot\tikzumlobjectclass};% - \fi% - % - \ifthenelse{\equal{\tikzumlobjectstereo}{multi}}{% - \draw (\tikzumlObjectName.north east)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-tr, coordinate] {}; - \draw (\tikzumlObjectName.north west)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-tl, coordinate] {}; - \draw (\tikzumlObjectName.south east)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-br, coordinate] {}; - \draw (\tikzumlObjectName-tr)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-ttr, coordinate] {}; - \draw (\tikzumlObjectName-tl)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-ttl, coordinate] {}; - \draw (\tikzumlObjectName-br)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-tbr, coordinate] {}; - \fill[fill=\tikzumlobjectfill] (\tikzumlObjectName-ttl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-ttl) -- (\tikzumlObjectName-ttr) -- (\tikzumlObjectName-tbr) -- (\tikzumlObjectName-tbr -| \tikzumlObjectName.east) -- (\tikzumlObjectName.north east) -- (\tikzumlObjectName-ttl |- \tikzumlObjectName.north); - \draw[draw=\tikzumlobjectdraw] (\tikzumlObjectName-ttl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-ttl) -- (\tikzumlObjectName-ttr) -- (\tikzumlObjectName-tbr) -- (\tikzumlObjectName-tbr -| \tikzumlObjectName.east); - \fill[fill=\tikzumlobjectfill] (\tikzumlObjectName-tl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-tl) -- (\tikzumlObjectName-tr) -- (\tikzumlObjectName-br) -- (\tikzumlObjectName-br -| \tikzumlObjectName.east) -- (\tikzumlObjectName.north east) -- (\tikzumlObjectName-tl |- \tikzumlObjectName.north); - \draw[draw=\tikzumlobjectdraw] (\tikzumlObjectName-tl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-tl) -- (\tikzumlObjectName-tr) -- (\tikzumlObjectName-br) -- (\tikzumlObjectName-br -| \tikzumlObjectName.east); - \draw[draw=\tikzumlobjectdraw] (\tikzumlObjectName.north west) rectangle (\tikzumlObjectName.south east); - }{% - \ifthenelse{\equal{\tikzumlobjectstereo}{object}}{}{% - \node[above=1ex, name=\tikzumlObjectName-picture] at (\tikzumlObjectName) {\csname pictured\tikzumlobjectstereo \endcsname{draw=\tikzumlobjectdraw, fill=\tikzumlobjectfill, scale=\tikzumlobjectscale}}; - }% - }% -} - -% shortcuts for objects -\newcommand{\umlbasicobject}[2][]{% - \pgfkeys{/tikzuml/basicobj/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{no ddots}}{% - \errmessage{TIKZUML ERROR : in umlbasicobject, forbidden option no ddots}% - }{}% - }}% - \pgfkeys{/tikzuml/basicobj/.cd, #1}% - \umlobject[no ddots, #1]{#2}% -}% - -\newcommand{\umldatabase}[2][]{% - \pgfkeys{/tikzuml/databaseobj/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR : in umldatabase, forbidden option stereo}% - }{}% - }}% - \pgfkeys{/tikzuml/databaseobj/.cd, #1}% - \umlobject[stereo=database, #1]{#2}% -}% -\newcommand{\umlentity}[2][]{% - \pgfkeys{/tikzuml/entityobj/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR : in umlentity, forbidden option stereo}% - }{}% - }}% - \pgfkeys{/tikzuml/entityobj/.cd, #1}% - \umlobject[stereo=entity, #1]{#2}% -}% -\newcommand{\umlcontrol}[2][]{% - \pgfkeys{/tikzuml/controlobj/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR : in umlcontrol, forbidden option stereo}% - }{}% - }}% - \pgfkeys{/tikzuml/controlobj/.cd, #1}% - \umlobject[stereo=control, #1]{#2}% -}% -\newcommand{\umlboundary}[2][]{% - \pgfkeys{/tikzuml/boundaryobj/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR : in umlboundary, forbidden option stereo}% - }{}% - }}% - \pgfkeys{/tikzuml/boundaryobj/.cd, #1}% - \umlobject[stereo=boundary, #1]{#2}% -}% -\newcommand{\umlmulti}[2][]{% - \pgfkeys{/tikzuml/multiobj/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR : in umlmulti, forbidden option stereo}% - }{}% - }}% - \pgfkeys{/tikzuml/multiobj/.cd, #1}% - \umlobject[stereo=multi, #1]{#2}% -}% - -\newlength{\tikzumlCall@xa}% -\newlength{\tikzumlCall@xb}% - -% define a uml operation call for sequence diagrams -% args : call sender -% call receiver -% optional : dt, time delay from precedent event end -% name of the call -% operation name and input args -% return value -% type of the call (synchron, asynchron) -% draw, fill, text colors -% time padding from call start and to call end -\newenvironment{umlcall}[3][]{% - \stepcounter{tikzumlCallNum}% - \def\tikzumlCallWithReturn{tikzumlFalse}% - \edef\tikzumlCall@lastchildNum{\thetikzumlCallNum}% for testing presence of sub-calls - \gdef\tikzumlCallBottom{0}% - % - \pgfkeys{/tikzuml/call/.cd,% - dt/.initial={tikzumlEmpty}, name/.initial={call-\thetikzumlCallNum},% - op/.initial={}, return/.initial={}, type/.initial=synchron,% - draw/.initial=\tikzumldrawcolor, fill/.initial=\tikzumlfillcallcolor,% - text/.initial=\tikzumltextcolor,% - padding/.initial=2,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{with return}}{% - \def\tikzumlCallWithReturn{tikzumlTrue}% - }{% - \errmessage{TIKZUML ERROR : in umlcall, invalid option \keyname}% - }% - }}% - \pgfkeys{/tikzuml/call/.cd, #1}% - \pgfkeys{/tikzuml/call/.cd,% - dt/.get=\tikzumlcallDT, name/.get=\tikzumlcallname, op/.get=\tikzumlcallop,% - return/.get=\tikzumlcallreturn, type/.get=\tikzumlcalltype,% - padding/.get=\tikzumlcallpadding,% - draw/.get=\tikzumlcalldraw, fill/.get=\tikzumlcallfill,% - text/.get=\tikzumlcalltext}% - % - \edef\tikzumlfillcall{\tikzumlcallfill}% - \edef\tikzumldrawcall{\tikzumlcalldraw}% - \edef\tikzumltextcall{\tikzumlcalltext}% - \edef\tikzumltypecall{\tikzumlcalltype}% - % - \ifthenelse{\equal{\tikzumlcallDT}{tikzumlEmpty}}{% - \ifnum\thetikzumlCallNum=1% - \def\tikzumlcallDT{2}% - \def\tikzumlcallSrc{2}% - \else% - \def\tikzumlcallDT{2}% - \def\tikzumlcallSrc{1}% - \fi% - }{ - \def\tikzumlcallSrc{0}% - }% - % - \let\tikzumlCallStartNodeNameold\tikzumlCallStartNodeName% - \def\tikzumlCallStartNodeName{#2}% - \let\tikzumlCallEndNodeNameold\tikzumlCallEndNodeName% - \def\tikzumlCallEndNodeName{#3}% - \def\tikzumlcallheight{\tikzumlcallpadding}% - % - % managing time delays from previous/parent fragments - \ifnum\thetikzumlCallStartFragmentNum>0% - \let\tikzumlcallDTold\tikzumlcallDT% - \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlcallDTold}% - \edef\tikzumlcallDT{\pgfmathresult}% - \addtocounter{tikzumlCallStartFragmentNum}{-1} - \fi% - \ifnum\thetikzumlCallEndFragmentNum>0% - \let\tikzumlcallDTold\tikzumlcallDT% - \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlcallDTold}% - \edef\tikzumlcallDT{\pgfmathresult}% - \addtocounter{tikzumlCallEndFragmentNum}{-1} - \fi% - \ifnum\thetikzumlFragmentPartNum>0% - \let\tikzumlcallDTold\tikzumlcallDT% - \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlcallDTold}% - \edef\tikzumlcallDT{\pgfmathresult}% - \fi% - % - % managing parent-child structure - \ifnum\thetikzumlCallLevel>0% - \let\tikzumlCall@nameold\tikzumlCall@name% - \edef\tikzumlCall@name{\tikzumlcallname}% - \let\tikzumlCall@parentold\tikzumlCall@parent% - \edef\tikzumlCall@parent{\tikzumlCall@parentold @@\tikzumlCall@nameold}% - \else% - \edef\tikzumlCall@parent{}% - \edef\tikzumlCall@parentold{}% - \edef\tikzumlCall@nameold{} - \edef\tikzumlCall@name{\tikzumlcallname}% - \fi% - % - \begingroup% - \def\_{_}\edef\x{\endgroup% - \def\noexpand\tikzumlCall@nodeName{\tikzumlCall@name}}\x% - % - \let\tikzumlCall@nodeNameold\tikzumlCall@nodeName% - % - \def\tikzumlcallstyle{tikzuml \tikzumlcalltype-msg style}% - % - % top node of activity period of call sender - \begin{pgfonlayer}{connections}% - \pgfmathparse{\tikzumlcallDT+\tikzumlcallSrc}% - \draw (\csname tikzumlLastChild@\tikzumlCallStartNodeName \endcsname)+(0,-\pgfmathresult ex) node[coordinate, name=tikzumlTmpNode] {};% - \node[tikzuml activity style] (st-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};% - % - % update last node drawn on sender lifeline - \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallStartNodeName \endcsname{st-\tikzumlCall@nodeName}% - % - % top node of activity period of call receiver - \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}}{% - \draw (st-\tikzumlCall@nodeName)+(0,-0.75*\tikzumlcallpadding ex) node[coordinate, name=tikzumlTmpNode] {};% - \node[tikzuml activity style] (et-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};% - }{% - \node[tikzuml activity style] (et-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- st-\tikzumlCall@nodeName) {};% - }% - % - % update last node drawn on receiver lifeline - \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallEndNodeName \endcsname{et-\tikzumlCall@nodeName}% - \xdef\tikzumlCallBottomSrc{et-\tikzumlCall@nodeName}% - \end{pgfonlayer}% - % - \stepcounter{tikzumlCallLevel}% -}{% - \addtocounter{tikzumlCallLevel}{-1}% - % - % bottom nodes of activity periods of call sender and receiver - \begin{pgfonlayer}{connections}% - \ifnum\tikzumlCall@lastchildNum=\thetikzumlCallNum% - % - % this test occurs a bug with latex package preview - \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}}{% - \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlcallpadding ex) node[coordinate, name=tikzumlTmpNode] {};% - \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};% - \draw (eb-\tikzumlCall@nodeName)+(0,-0.75*\tikzumlcallpadding ex) node[coordinate, name=tikzumlTmpNode] {};% - \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};% - }{% - \ifthenelse{\equal{\tikzumlcallreturn}{tikzumlEmpty}}{% - \pgfmathsetmacro{\tikzumlcallpaddingd}{0.5*\tikzumlcallpadding}% - }{% - \pgfmathsetmacro{\tikzumlcallpaddingd}{1.2*\tikzumlcallpadding}% - }% - \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlcallpaddingd ex) node[coordinate, name=tikzumlTmpNode] {};% - \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};% - \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- eb-\tikzumlCall@nodeName) {};% - }% - \xdef\tikzumlCallBottomSrc{sb-\tikzumlCall@nodeName}% - \else% - % - % managing time delays from previous/parent fragments - \ifnum\thetikzumlCallStartFragmentNum>0% - \let\tikzumlcallheightold\tikzumlcallpadding - \pgfmathparse{\tikzumlcallheightold+0.5*\tikzumlFragment@paddingy} - \edef\tikzumlcallheight{\pgfmathresult} - \addtocounter{tikzumlCallStartFragmentNum}{-1} - \fi% - \ifnum\thetikzumlCallEndFragmentNum>0% - \let\tikzumlcallheightold\tikzumlcallpadding - \pgfmathparse{\tikzumlcallheightold+0.5*\tikzumlFragment@paddingy} - \edef\tikzumlcallheight{\pgfmathresult} - \addtocounter{tikzumlCallEndFragmentNum}{-1} - \fi% - % - \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}}{% - \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlcallheight ex) node[coordinate, name=tikzumlTmpNode] {};% - \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};% - \draw (eb-\tikzumlCall@nodeName)+(0,-0.75*\tikzumlcallpadding ex) node[coordinate, name=tikzumlTmpNode] {};% - \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};% - }{% - \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlcallheight ex) node[coordinate, name=tikzumlTmpNode] {};% - \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};% - \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- eb-\tikzumlCall@nodeName) {};% - }% - % - \xdef\tikzumlCallBottomSrc{sb-\tikzumlCall@nodeName}% - \fi% - \end{pgfonlayer}% - % - % draw activity periods - \begin{pgfonlayer}{activity}% - \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}}{% - % draw root activity period only - \ifnum\thetikzumlCallLevel=0% - \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);% - \else% - % draw root activity from inner call - \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeNameold}}{}{% - \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);% - }% - \fi% - }{% - % draw root activity period - \ifnum\thetikzumlCallLevel=0% - \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);% - \else% - % draw root activity from inner call - \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeNameold}}{}{% - \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);% - }% - \fi% - % draw receiver activity period - \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (et-\tikzumlCall@nodeName.north west) rectangle (eb-\tikzumlCall@nodeName.south east);% - }% - \end{pgfonlayer}% - \ifthenelse{\equal{\tikzumlfillcallcolor}{\tikzumlcallfill}}{}{% - \fill[\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);% - \draw[\tikzumldrawcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south west) (st-\tikzumlCall@nodeName.north east) rectangle (sb-\tikzumlCall@nodeName.south east); - }% - % - % update last nodes drawn on sender and receiver lifelines - \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallEndNodeName \endcsname{eb-\tikzumlCall@nodeName}% - \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallStartNodeName \endcsname{sb-\tikzumlCall@nodeName}% - % - % draw call arrows - \begin{pgfonlayer}{connections}% - \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}}{% - \draw[\tikzumlcallstyle, \tikzumldrawcall] (st-\tikzumlCall@nodeName.east) -- ++(2.5*\tikzumlcallpadding ex,0) % - -- ++(0,-0.75*\tikzumlcallpadding ex) % - node[font=\tikzumlfont, text=\tikzumltextcall, midway, right, name=\tikzumlCall@nodeName-op] {\tikzumlcallop} % - -- (et-\tikzumlCall@nodeName.east);% - % - % draw return arrow and update fit for parent fragment - \ifthenelse{\equal{\tikzumltypecall}{synchron}}{% - \ifthenelse{\NOT\equal{\tikzumlcallreturn}{}\OR\equal{\tikzumlCallWithReturn}{tikzumlTrue}}{% - \ifnum\c@tikzumlFragmentLevel>0% - \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}% - \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op) (\tikzumlCall@nodeName-return)}% - \fi% - % - \draw[tikzuml call return style, \tikzumldrawcall] (eb-\tikzumlCall@nodeName.east) -- ++(2.5*\tikzumlcallpadding ex,0) -- ++(0,-0.75*\tikzumlcallpadding ex) % - node[font=\tikzumlfont, text=\tikzumltextcall, midway, right, name=\tikzumlCall@nodeName-return] {\tikzumlcallreturn} % - -- (sb-\tikzumlCall@nodeName.east);% - }{% - \ifnum\c@tikzumlFragmentLevel>0% - \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}% - \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}% - \fi% -}% - }{% - \ifnum\c@tikzumlFragmentLevel>0% - \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}% - \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}% - \fi% - % - }% - }{% - % draw call arrows - \pgfextractx{\tikzumlCall@xa}{\pgfpointanchor{\tikzumlCallStartNodeName}{center}}% - \pgfextractx{\tikzumlCall@xb}{\pgfpointanchor{\tikzumlCallEndNodeName}{center}}% - % - \ifthenelse{\tikzumlCall@xb>\tikzumlCall@xa}{% - \draw[\tikzumlcallstyle, \tikzumldrawcall] (st-\tikzumlCall@nodeName.east) -- (et-\tikzumlCall@nodeName.west) % - node[font=\tikzumlfont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-op] {\tikzumlcallop};% - }{% - \draw[\tikzumlcallstyle, \tikzumldrawcall] (st-\tikzumlCall@nodeName.west) -- (et-\tikzumlCall@nodeName.east) % - node[font=\tikzumlfont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-op] {\tikzumlcallop};% - }% - % - % draw return arrow and update fit for parent fragment - \ifthenelse{\equal{\tikzumltypecall}{synchron}}{% - \ifthenelse{\NOT\equal{\tikzumlcallreturn}{}\OR\equal{\tikzumlCallWithReturn}{tikzumlTrue}}{% - \ifnum\c@tikzumlFragmentLevel>0% - \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}% - \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op) (\tikzumlCall@nodeName-return)}% - \fi% - % - \ifthenelse{\tikzumlCall@xb>\tikzumlCall@xa}{% - \draw[tikzuml call return style, \tikzumldrawcall] (eb-\tikzumlCall@nodeName.west) -- (sb-\tikzumlCall@nodeName.east) % - node[font=\tikzumlfont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-return] {\tikzumlcallreturn};% - }{% - \draw[tikzuml call return style, \tikzumldrawcall] (eb-\tikzumlCall@nodeName.east) -- (sb-\tikzumlCall@nodeName.west) % - node[font=\tikzumlfont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-return] {\tikzumlcallreturn};% - }% - }{% - \ifnum\c@tikzumlFragmentLevel>0% - \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}% - \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}% - \fi% - }% - }{% - \ifnum\c@tikzumlFragmentLevel>0% - \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}% - \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}% - \fi% - }% - }% - \end{pgfonlayer}% -}% - -% alias for function self call -\newenvironment{umlcallself}[2][]{\begin{umlcall}[#1]{#2}{#2} }{\end{umlcall}}% - -% define a combined fragment -% optional : name of fragment -% type of fragment (opt, alt, break, loop, par, critical, ignore, consider, assert, neg, weak, strict, ref) -% label of fragment (ex : condition for opt, iterator for loop, ...) -% inner xsep and ysep (padding of the fragment box) -% draw, fill, text colors -\newenvironment{umlfragment}[1][]{% - - % define a fragment separator - % optional : label of the fragment part (ex : else for alt) - \providecommand{\umlfpart}[1][]{% - \stepcounter{tikzumlFragmentPartNum}% - % - \node[outer sep=0, inner xsep=\tikzumlfragmentxsep ex, inner ysep=\tikzumlfragmentysep ex, fit=\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname, name=\tikzumlFragment@name-Part-tmp] {};% - \node[anchor=east, name=\tikzumlFragment@name-PartType-\thetikzumlFragmentPartNum] at (\tikzumlFragment@name-Part-tmp.north west |- \tikzumlCallBottomSrc) {\phantom{\tikzumlfragmenttype}}; - \draw (\tikzumlFragment@name-PartType-\thetikzumlFragmentPartNum.north west |- \tikzumlCallBottomSrc)+(0,-0.4*\tikzumlFragment@paddingy ex) node[name=\tikzumlFragment@name-PartWest-\thetikzumlFragmentPartNum] {}; - \draw (\tikzumlFragment@name-Part-tmp.north east |- \tikzumlCallBottomSrc)+(0,-0.4*\tikzumlFragment@paddingy ex) node[name=\tikzumlFragment@name-PartEast-\thetikzumlFragmentPartNum] {}; - \draw[dashed] (\tikzumlFragment@name-PartWest-\thetikzumlFragmentPartNum) -- (\tikzumlFragment@name-PartEast-\thetikzumlFragmentPartNum); - \draw (\tikzumlFragment@name-PartType-\thetikzumlFragmentPartNum)+(0,-0.4*\tikzumlFragment@paddingy ex) node[name=tikzumlTmpNode] {\phantom{\tikzumlfragmenttype}}; - \node[anchor=north west] at (tikzumlTmpNode.south west) {[##1]};% - }% - - \stepcounter{tikzumlFragmentNum}% - % - \pgfkeys{/tikzuml/fragment/.cd,% - name/.initial={fragment@\alph{tikzumlFragmentNum}}, type/.initial=opt,% - label/.initial={tikzumlEmpty},% - inner xsep/.initial=1, inner ysep/.initial=1,% - draw/.initial=\tikzumldrawcolor, fill/.initial=\tikzumlfillfragmentcolor,% - text/.initial=\tikzumltextcolor,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \errmessage{TIKZUML ERROR : in umlfragment, invalid option \keyname}% - }}% - \pgfkeys{/tikzuml/fragment/.cd, #1}% - \pgfkeys{/tikzuml/fragment/.cd,% - name/.get=\tikzumlfragmentname, type/.get=\tikzumlfragmenttype,% - label/.get=\tikzumlfragmentlabel,% - inner xsep/.get=\tikzumlfragmentxsep, inner ysep/.get=\tikzumlfragmentysep,% - draw/.get=\tikzumlfragmentdraw, fill/.get=\tikzumlfragmentfill,% - text/.get=\tikzumlfragmenttext}% - % - \ifthenelse{\equal{\tikzumlfragmentlabel}{tikzumlEmpty}}{% - \def\tikzumlfragmentlabel{}% - }{% - \let\tikzumlfragmentlabelold\tikzumlfragmentlabel% - \def\tikzumlfragmentlabel{[\tikzumlfragmentlabelold]}% - }% - - % - \ifnum\thetikzumlFragmentLevel>0% - \let\tikzumlFragment@parentold\tikzumlFragment@parent% - \let\tikzumlFragment@nameold\tikzumlFragment@name% - \edef\tikzumlFragment@parent{\tikzumlFragment@nameold}% - \else% - \setcounter{tikzumlFragmentPartNum}{0}% - \edef\tikzumlFragment@parent{}% - \edef\tikzumlFragment@parentold{}% - \edef\tikzumlFragment@nameold{}% - \fi% - % - \edef\tikzumlFragment@name{\tikzumlfragmentname}% - \expandafter\gdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{}% - % - \stepcounter{tikzumlFragmentLevel}% - % - \ifnum\thetikzumlCallLevel>0% - \stepcounter{tikzumlCallStartFragmentNum}% - \fi% - % - \pgfmathparse{6*\tikzumlfragmentysep}% - \xdef\tikzumlFragment@paddingy{\pgfmathresult}% - \if\c@tikzumlFragmentLevelNum=0% - \setcounter{tikzumlFragmentLevelNum}{\thetikzumlFragmentLevel}% - \fi% - % - % time delay adjustment for two consecutive fragments - \ifnum\thetikzumlCallEndFragmentNum>0% - \addtocounter{tikzumlCallEndFragmentNum}{-1} - \fi% -}{% - % - \addtocounter{tikzumlFragmentLevel}{-1}% - % - \ifnum\thetikzumlFragmentLevel>0% - \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@parent \endcsname}% - \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@parent \endcsname{\tikzumlFragmentFitOld (\tikzumlFragment@name)}% - \fi% - % - % draw working fragment box - \begin{pgfonlayer}{fragment\thetikzumlFragmentLevel}% - \node[outer sep=0, inner xsep=\tikzumlfragmentxsep ex, inner ysep=\tikzumlfragmentysep ex, fit=\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname, name=\tikzumlFragment@name-back] {};% - \end{pgfonlayer}% - % - % draw type and label - \node[text=\tikzumlfragmenttext, font=\tikzumlfont, anchor=north east, name=\tikzumlFragment@name-type] % - at (\tikzumlFragment@name-back.north west) {\tikzumlfragmenttype};% - \node[text=\tikzumlfragmenttext, font=\tikzumlfont, anchor=north west, name=\tikzumlFragment@name-label] % - at (\tikzumlFragment@name-type.south west) {\tikzumlfragmentlabel};% - % - % draw final fragment box - \begin{pgfonlayer}{fragment\thetikzumlFragmentLevel}% - \node[draw=\tikzumlfragmentdraw, fill=\tikzumlfragmentfill, outer sep=0, inner sep=0, font=\tikzumlfont, fit=(\tikzumlFragment@name-back) (\tikzumlFragment@name-type) (\tikzumlFragment@name-label), name=\tikzumlFragment@name] {};% - \end{pgfonlayer}% - % - \draw[draw=\tikzumlfragmentdraw] (\tikzumlFragment@name.north west) rectangle (\tikzumlFragment@name.south east);% - \draw (\tikzumlFragment@name-type.south east)+(0,1ex) node[name=\tikzumlFragment@name-typetop, inner sep=0] {};% - \draw (\tikzumlFragment@name-type.south east)+(-1ex,0) node[name=\tikzumlFragment@name-typeleft, inner sep=0] {};% - \draw (\tikzumlFragment@name.north west) -| (\tikzumlFragment@name-typetop.center) -- (\tikzumlFragment@name-typeleft.center) -| (\tikzumlFragment@name.north west);% - % - \ifnum\thetikzumlCallLevel>0% - \stepcounter{tikzumlCallEndFragmentNum}% - \fi% -}% - -% define a constructor call -% arg : call sender -% name of constructed object -% optional : x coordinate of the new object -% stereotype of the new object -% class type of the new object -% time delay from last event -% name of the call -% draw, fill, text colors -\newcommand{\umlcreatecall}[3][]{% - \stepcounter{tikzumlCallNum}% - \edef\tikzumlCall@lastchildNum{\thetikzumlCallNum}% for testing presence of sub-calls - \gdef\tikzumlInCreateCall{1}% - \pgfkeys{/tikzuml/createcall/.cd,% - x/.initial={tikzumlEmpty}, stereo/.initial=object, class/.initial={},% - dt/.initial=4, name/.initial={call-\thetikzumlCallNum},% - draw/.initial=\tikzumldrawcolor, fill/.initial=\tikzumlfillcallcolor,% - text/.initial=\tikzumltextcolor,% - draw obj/.initial=\tikzumldrawcolor, fill obj/.initial=\tikzumlfillobjectcolor,% - text obj/.initial=\tikzumltextcolor,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \errmessage{TIKZUML ERROR : in umlcreatecall, invalid option \keyname}% - }}% - \pgfkeys{/tikzuml/createcall/.cd, #1}% - \pgfkeys{/tikzuml/createcall/.cd,% - x/.get=\tikzumlcallX, stereo/.get=\tikzumlcallstereo,% - class/.get=\tikzumlcallclass,% - dt/.get=\tikzumlcallDT, name/.get=\tikzumlcallname,% - draw/.get=\tikzumlcalldraw, fill/.get=\tikzumlcallfill,% - text/.get=\tikzumlcalltext,% - draw obj/.get=\tikzumlcallobjdraw, fill obj/.get=\tikzumlcallobjfill,% - text obj/.get=\tikzumlcallobjtext}% - % - \def\tikzumlCreateCallSrc@name{#2}% - % - \begingroup% - \def\_{_}\edef\x{\endgroup% - \def\noexpand\tikzumlCreateCallSrc@nodeName{\tikzumlCreateCallSrc@name}}\x% - % - % managing time delays from previous/parent fragments - \ifnum\thetikzumlCallStartFragmentNum>0% - \let\tikzumlcallDTold\tikzumlcallDT% - \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlcallDTold}% - \edef\tikzumlcallDT{\pgfmathresult}% - \addtocounter{tikzumlCallStartFragmentNum}{-1} - \fi% - \ifnum\thetikzumlCallEndFragmentNum>0% - \let\tikzumlcallDTold\tikzumlcallDT% - \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlcallDTold}% - \edef\tikzumlcallDT{\pgfmathresult}% - \addtocounter{tikzumlCallEndFragmentNum}{-1} - \fi% - \ifnum\thetikzumlFragmentPartNum>0% - \let\tikzumlcallDTold\tikzumlcallDT% - \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlcallDTold}% - \edef\tikzumlcallDT{\pgfmathresult}% - \fi% - % - % managing parent-child structure - \ifnum\thetikzumlCallLevel>0% - \let\tikzumlCall@nameold\tikzumlCall@name% - \def\tikzumlCall@name{\tikzumlcallname}% - \let\tikzumlCall@parentold\tikzumlCall@parent% - \edef\tikzumlCall@parent{\tikzumlCall@parentold @@\tikzumlCall@nameold}% - \else% - \edef\tikzumlCall@parent{}% - \edef\tikzumlCall@parentold{}% - \edef\tikzumlCall@nameold{} - \edef\tikzumlCall@name{\tikzumlcallname}% - \fi% - % - \begingroup% - \def\_{_}\edef\x{\endgroup% - \def\noexpand\tikzumlCreateCall@nodeName{\tikzumlCall@name}}\x% - % - \draw (\csname tikzumlLastChild@\tikzumlCreateCallSrc@nodeName \endcsname)+(0,-\tikzumlcallDT ex) node[name=st-\tikzumlCreateCall@nodeName, tikzuml activity style] {};% - % - \xdef\tikzumlCreateCallObjectSrc{st-\tikzumlCreateCall@nodeName}% - % - \umlobject[x=\tikzumlcallX, stereo=\tikzumlcallstereo, class=\tikzumlcallclass, draw=\tikzumlcallobjdraw, fill=\tikzumlcallobjfill, text=\tikzumlcallobjtext]{#3}% - % - \draw (\csname tikzumlLastChild@\tikzumlCreateCallSrc@nodeName \endcsname |- #3)+(0,-0.5*\tikzumlcallDT ex) node[name=sb-\tikzumlCreateCall@nodeName, tikzuml activity style] {};% - % - \expandafter\xdef\csname tikzumlLastChild@\tikzumlCreateCallSrc@nodeName \endcsname{sb-\tikzumlCreateCall@nodeName}% - \xdef\tikzumlCallBottomSrc{sb-\tikzumlCreateCall@nodeName}% - % - \begin{pgfonlayer}{connections}% - \draw[tikzuml synchron-msg style, \tikzumlcalldraw] (st-\tikzumlCreateCall@nodeName) -- (#3) node[midway, above, font=\tikzumlfont, text=\tikzumlcalltext, name=\tikzumlCreateCall@nodeName-op] {create};% - \end{pgfonlayer}% - % - \ifnum\thetikzumlCallLevel=0% - \begin{pgfonlayer}{activity}% - \draw[draw=\tikzumlcalldraw, fill=\tikzumlcallfill] (st-\tikzumlCreateCall@nodeName.north west) rectangle (sb-\tikzumlCreateCall@nodeName.south east);% - \end{pgfonlayer}% - \fi% - % add to fit fragment - \ifnum\c@tikzumlFragmentLevel>0% - \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}% - \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCreateCall@nodeName) (sb-\tikzumlCreateCall@nodeName) (\tikzumlCreateCall@nodeName-op) (#3) }% - \fi% -} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% component diagrams % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\tikzstyle{tikzuml connector style}=[color=\tikzumldrawcolor, -]% - -\newcounter{tikzumlComponentLevel}% -\newcounter{tikzumlComponentSubComponentNum}% -\newcounter{tikzumlConnectorNum}% -\setcounter{tikzumlConnectorNum}{1}% - -\newcommand{\picturedcomponent}[1]{% - \pgfkeys{/tikzuml/component/picture/.cd, scale/.initial=1, .unknown/.code={}}% - \pgfkeys{/tikzuml/component/picture/.cd,#1}% - \pgfkeys{/tikzuml/component/picture/.cd, scale/.get=\tikzumlcomponentscale}% - \begin{tikzpicture}[#1]% - \filldraw (0,0) rectangle (1ex,1.5ex);% - \filldraw (-0.2ex,0.4ex) rectangle (0.2ex,0.6ex);% - \filldraw (-0.2ex,0.9ex) rectangle (0.2ex,1.1ex);% - \end{tikzpicture}% -}% - -% define a uml component -% args : name of the component -% content of the component -% optional args : x,y coordinates of the component -% width of the component node -\newenvironment{umlcomponent}[2][]{% - \ifnum\thetikzumlComponentLevel>0% - \let\tikzumlComponent@nameold\tikzumlComponent@fitname% - \let\tikzumlComponent@parentold\tikzumlComponent@parent% - \edef\tikzumlComponent@parent{\tikzumlComponent@parentold @@\tikzumlComponent@nameold}% - \else% - \def\tikzumlComponent@parent{}% - \fi% - % - \stepcounter{tikzumlComponentLevel}% - % - \pgfkeys{/tikzuml/component/.cd,% - x/.initial=0, y/.initial=0, width/.initial=8ex, name/.initial={},% - draw/.initial=\tikzumldrawcolor, fill/.initial=\tikzumlfillcomponentcolor,% - text/.initial=\tikzumltextcolor,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \errmessage{TIKZUML ERROR : in umlcomponent, invalid option \keyname}% - }}% - \pgfkeys{/tikzuml/component/.cd, #1}% - \pgfkeys{/tikzuml/component/.cd,% - x/.get=\tikzumlcomponentX, y/.get=\tikzumlcomponentY,% - width/.get=\umlcomponentMinimumWidth, name/.get=\umlcomponentName,% - draw/.get=\tikzumlcomponentdraw, fill/.get=\tikzumlcomponentfill,% - text/.get=\tikzumlcomponenttext}% - % - \ifthenelse{\equal{\umlcomponentName}{}}{% - \edef\tikzumlComponent@name{#2}% - }{% - \edef\tikzumlComponent@name{\umlcomponentName}% - }% - % - \begingroup% - \def\_{@}\edef\x{\endgroup% - \def\noexpand\tikzumlComponent@fitname{\tikzumlComponent@name}}\x% - % - \let\tikzumlComponent@nodeNameold\tikzumlComponent@nodeName% - \def\tikzumlComponent@caption{#2}% - % - \begingroup% - \def\_{_}\edef\x{\endgroup% - \def\noexpand\tikzumlComponent@nodeName{\tikzumlComponent@name}}\x% - % - \expandafter\gdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{}% - % - \setcounter{tikzumlComponentSubComponentNum}{0}% - % - \begin{scope}[xshift=\tikzumlcomponentX cm, yshift=\tikzumlcomponentY cm]% -}{% - \addtocounter{tikzumlComponentLevel}{-1}% - \begin{pgfonlayer}{component\thetikzumlComponentLevel}% - % - % if contains nothing, one define a fictive node to enable the fit option - \ifnum\c@tikzumlComponentSubComponentNum=0% - \node[inner ysep=0.5ex, minimum width=\umlcomponentMinimumWidth, font=\tikzumlfont] (\tikzumlComponent@nodeName-root) at (0,0) {\phantom{\tikzumlComponent@nodeName}};% - \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{(\tikzumlComponent@nodeName-root)}% - \fi% - % - \ifnum\c@tikzumlComponentLevel>0% - \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent\endcsname}% - \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent\endcsname{\tikzumlComponentFitTmp (\tikzumlComponent@nodeName-body) (\tikzumlComponent@nodeName-caption)}% - \stepcounter{tikzumlComponentSubComponentNum}% - \fi% - % - \node[inner sep=2ex, font=\tikzumlfont, fit = \csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname] (\tikzumlComponent@nodeName-body) {};% - \node[above, font=\tikzumlfont] (\tikzumlComponent@nodeName-captiontmp) at (\tikzumlComponent@nodeName-body.north) {\tikzumlComponent@caption};% - \node (\tikzumlComponent@nodeName-logotmp) at (\tikzumlComponent@nodeName-captiontmp.north -| \tikzumlComponent@nodeName-body.east) {\picturedcomponent{draw=\tikzumlcomponentdraw, fill=\tikzumlcomponentfill, font=\tikzumlfont} };% - \node[draw=\tikzumlcomponentdraw, fill=\tikzumlcomponentfill, name=\tikzumlComponent@nodeName, fit=(\tikzumlComponent@nodeName-body) (\tikzumlComponent@nodeName-captiontmp)] {};% - \node[font=\tikzumlfont] (\tikzumlComponent@nodeName-caption) at (\tikzumlComponent@nodeName-captiontmp) {\tikzumlComponent@caption};% - \draw (\tikzumlComponent@nodeName-caption.north -| \tikzumlComponent@nodeName.east) node[font=\tikzumlfont, xshift=-1ex, below=-1ex, name=\tikzumlComponent@nodeName-logo] {\picturedcomponent{draw=\tikzumlcomponentdraw, fill=\tikzumlcomponentfill, font=\tikzumlfont} };% - \draw (\tikzumlComponent@nodeName-caption.south -| \tikzumlComponent@nodeName.north west) -- (\tikzumlComponent@nodeName-caption.south -| \tikzumlComponent@nodeName.north east);% - \coordinate (\tikzumlComponent@nodeName-west-port) at (\tikzumlComponent@nodeName.west); - \coordinate (\tikzumlComponent@nodeName-east-port) at (\tikzumlComponent@nodeName.east); - \coordinate (\tikzumlComponent@nodeName-south-port) at (\tikzumlComponent@nodeName.south); - \coordinate (\tikzumlComponent@nodeName-north-port) at (\tikzumlComponent@nodeName.north); - - \end{pgfonlayer}% - \end{scope}% - % - % add to fit - \ifnum\c@tikzumlPackageLevel>0% - \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}% - \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlComponent@nodeName)}% - \stepcounter{tikzumlPackageClassNum}% - \fi% -}% - -% shortcut for empty state -\newcommand{\umlbasiccomponent}[2][]{\begin{umlcomponent}[#1]{#2} \end{umlcomponent}}% - -\newcommand{\umlrequiredinterface}[2][]{% - \def\tikzumlInterfaceWithPort{tikzumlFalse}% - \pgfkeys{/tikzuml/requiredinterfacerelation/.cd,% - interface/.initial={}, distance/.initial=2.5cm,% - width/.initial=1em, padding/.initial=1cm,% - draw/.initial=\tikzumldrawcolor, fill/.initial=\tikzumlfillcomponentcolor,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{with port}}{% - \def\tikzumlInterfaceWithPort{tikzumlTrue}% - }{}% - }}% - \pgfkeys{/tikzuml/requiredinterfacerelation/.cd, #1}% - \pgfkeys{/tikzuml/requiredinterfacerelation/.cd,% - interface/.get=\tikzumlRequiredInterfaceLabel,% - distance/.get=\tikzumlRequiredInterfaceDistance,% - width/.get=\tikzumlRequiredInterfaceWidth,% - padding/.get=\tikzumlRequiredInterfacePadding,% - draw/.get=\tikzumlrequiredinterfacedraw,% - fill/.get=\tikzumlrequiredinterfacefill,}% - % - \edef\tikzumlRequiredInterface@name{#2}% - % - \begingroup% - \def\_{_}\edef\x{\endgroup% - \def\noexpand\tikzumlRequiredInterface@nodeName{\tikzumlRequiredInterface@name}}\x% - % - \ifthenelse{\equal{\tikzumlInterfaceWithPort}{tikzumlTrue}}{% - \node[inner sep=0.5*\tikzumlRequiredInterfaceWidth, rectangle, draw=\tikzumlrequiredinterfacedraw, fill=\tikzumlrequiredinterfacefill] (\tikzumlRequiredInterface@nodeName-east-port) at (\tikzumlRequiredInterface@nodeName.east) {};% - }{% - \node[inner sep=0] (\tikzumlRequiredInterface@nodeName-east-port) at (\tikzumlRequiredInterface@nodeName.east) {};% - }% - \begin{scope}% - \draw (\tikzumlRequiredInterface@nodeName)+(\tikzumlRequiredInterfaceDistance,0) node[inner sep=0, text width=\tikzumlRequiredInterfaceWidth, circle, name=\tikzumlRequiredInterface@nodeName-east-interface-tmp] {};% - \clip (\tikzumlRequiredInterface@nodeName-east-interface-tmp.north) rectangle (\tikzumlRequiredInterface@nodeName-east-interface-tmp.south -| \tikzumlRequiredInterface@nodeName-east-interface-tmp.west);% - \node[inner sep=0, text width=\tikzumlRequiredInterfaceWidth, circle, draw=\tikzumlrequiredinterfacedraw] (\tikzumlRequiredInterface@nodeName-east-interface) at (\tikzumlRequiredInterface@nodeName-east-interface-tmp) {};% - \end{scope}% - \node[above] at (\tikzumlRequiredInterface@nodeName-east-interface.north) {\tikzumlRequiredInterfaceLabel};% - % - \umlrelation[style={tikzuml connector style}, #1]{\tikzumlRequiredInterface@nodeName-east-port}{\tikzumlRequiredInterface@nodeName-east-interface}% - - \draw (\tikzumlRequiredInterface@nodeName-east-interface)+(\tikzumlRequiredInterfacePadding,0) node[name=\tikzumlRequiredInterface@nodeName-east-padding] {};% - - % add to fit - \ifnum\c@tikzumlComponentLevel>0% - \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname}% - \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlRequiredInterface@nodeName-east-padding) (\tikzumlRequiredInterface@nodeName-east-port) }% - \fi% -}% - -\newcommand{\umlprovidedinterface}[2][]{% - \def\tikzumlInterfaceWithPort{tikzumlFalse}% - \pgfkeys{/tikzuml/providedinterfacerelation/.cd,% - interface/.initial={}, distance/.initial=3cm,% - width/.initial=1em, padding/.initial=1cm,% - draw/.initial=\tikzumldrawcolor, fill/.initial=\tikzumlfillcomponentcolor,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{with port}}{% - \def\tikzumlInterfaceWithPort{tikzumlTrue}% - }{}% - }}% - \pgfkeys{/tikzuml/providedinterfacerelation/.cd, #1}% - \pgfkeys{/tikzuml/providedinterfacerelation/.cd,% - interface/.get=\tikzumlProvidedInterfaceLabel,% - distance/.get=\tikzumlProvidedInterfaceDistance,% - padding/.get=\tikzumlProvidedInterfacePadding,% - width/.get=\tikzumlProvidedInterfaceWidth,% - draw/.get=\tikzumlprovidedinterfacedraw,% - fill/.get=\tikzumlprovidedinterfacefill}% - % - \edef\tikzumlProvidedInterface@name{#2}% - % - \begingroup% - \def\_{_}\edef\x{\endgroup% - \def\noexpand\tikzumlProvidedInterface@nodeName{\tikzumlProvidedInterface@name}}\x% - % - \ifthenelse{\equal{\tikzumlInterfaceWithPort}{tikzumlTrue}}{% - \node[inner sep=0.5*\tikzumlProvidedInterfaceWidth, rectangle, draw=\tikzumlprovidedinterfacedraw, fill=\tikzumlprovidedinterfacefill] (\tikzumlProvidedInterface@nodeName-west-port) at (\tikzumlProvidedInterface@nodeName.west) {};% - }{% - \node[inner sep=0] (\tikzumlProvidedInterface@nodeName-west-port) at (\tikzumlProvidedInterface@nodeName.west) {};% - }% - \draw (\tikzumlProvidedInterface@nodeName)+(-\tikzumlProvidedInterfaceDistance,0) node[inner sep=0, text width=\tikzumlProvidedInterfaceWidth, circle, draw=\tikzumlprovidedinterfacedraw, fill=\tikzumlprovidedinterfacefill, name=\tikzumlProvidedInterface@nodeName-west-interface] {};% - \node[above] at (\tikzumlProvidedInterface@nodeName-west-interface.north) - {\tikzumlProvidedInterfaceLabel};% - % - \umlrelation[style={tikzuml connector style}, #1]{\tikzumlProvidedInterface@nodeName-west-port}{\tikzumlProvidedInterface@nodeName-west-interface}% - - \draw (\tikzumlProvidedInterface@nodeName-west-interface)+(-\tikzumlProvidedInterfacePadding,0) node[name=\tikzumlProvidedInterface@nodeName-west-padding] {};% - % add to fit - \ifnum\thetikzumlComponentLevel>0% - \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname}% - \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlProvidedInterface@nodeName-west-padding) (\tikzumlProvidedInterface@nodeName-west-port) }% - \fi% -}% - -\newlength{\tikzuml@AC@xa}% -\newlength{\tikzuml@AC@ya}% -\newlength{\tikzuml@AC@xb}% -\newlength{\tikzuml@AC@yb}% -\newlength{\tikzuml@AC@xi}% -\newlength{\tikzuml@AC@yi}% -\newlength{\tikzuml@AC@xic}% -\newlength{\tikzuml@AC@yic}% -\newlength{\tikzuml@AC@xio}% -\newlength{\tikzuml@AC@yio}% -\newlength{\tikzuml@AC@AB}% -\newlength{\tikzuml@AC@lambda}% -\newlength{\tikzuml@AC@xtrc}% -\newlength{\tikzuml@AC@ytrc}% -\newlength{\tikzuml@AC@xtlc}% -\newlength{\tikzuml@AC@ytlc}% -\newlength{\tikzuml@AC@xblc}% -\newlength{\tikzuml@AC@yblc}% -\newlength{\tikzuml@AC@xbrc}% -\newlength{\tikzuml@AC@ybrc}% -\newlength{\tikzuml@AC@middleArm}% - -\newcommand{\umlassemblyconnectorsymbol}[2]{% - \ifthenelse{\NOT\equal{\tikzumlAssemblyConnectorLabel}{}}{% - \edef\tikzuml@ACStart@name{#1}% - \edef\tikzuml@ACEnd@name{#2}% - \edef\tikzuml@AC@width{\tikzumlAssemblyConnectorWidth}% - % - \begingroup% - \def\_{_}\edef\x{\endgroup% - \def\noexpand\tikzuml@ACStart@nodeName{\tikzuml@ACStart@name}}\x% - % - \begingroup% - \def\_{_}\edef\x{\endgroup% - \def\noexpand\tikzuml@ACEnd@nodeName{\tikzuml@ACEnd@name}}\x% - % - \begingroup% - \def\_{_}\edef\x{\endgroup% - \def\noexpand\tikzuml@ACInterface@nodeName{\tikzumlAssemblyConnectorSymbolName}}\x% - % - \pgfextractx{\tikzuml@AC@xa}{\pgfpointanchor{\tikzuml@ACStart@nodeName}{\tikzumlAssemblyConnectorStartAnchor}}% - \pgfextracty{\tikzuml@AC@ya}{\pgfpointanchor{\tikzuml@ACStart@nodeName}{\tikzumlAssemblyConnectorStartAnchor}}% - \pgfextractx{\tikzuml@AC@xb}{\pgfpointanchor{\tikzuml@ACEnd@nodeName}{\tikzumlAssemblyConnectorEndAnchor}}% - \pgfextracty{\tikzuml@AC@yb}{\pgfpointanchor{\tikzuml@ACEnd@nodeName}{\tikzumlAssemblyConnectorEndAnchor}}% - \pgfmathsetlength{\tikzuml@AC@xi}{0.5*\tikzuml@AC@xa+0.5*\tikzuml@AC@xb}% - \pgfmathsetlength{\tikzuml@AC@yi}{0.5*\tikzuml@AC@ya+0.5*\tikzuml@AC@yb}% - \pgfmathsetlength{\tikzuml@AC@AB}{veclen(\tikzuml@AC@xa-\tikzuml@AC@xb,\tikzuml@AC@ya-\tikzuml@AC@yb)}% - \pgfmathsetlength{\tikzuml@AC@lambda}{0.25*\tikzuml@AC@width/\tikzuml@AC@AB}% - \pgfmathsetlength{\tikzuml@AC@xic}{\tikzuml@AC@xi-\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}% - \pgfmathsetlength{\tikzuml@AC@yic}{\tikzuml@AC@yi-\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}% - \pgfmathsetlength{\tikzuml@AC@xio}{\tikzuml@AC@xi+\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}% - \pgfmathsetlength{\tikzuml@AC@yio}{\tikzuml@AC@yi+\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}% - \node[inner sep=0.5*\tikzuml@AC@width] (\tikzuml@ACInterface@nodeName-interface) at (\tikzuml@AC@xi,\tikzuml@AC@yi) {};% - \node[inner sep=0, text width=\tikzuml@AC@width, circle, draw=\tikzumlassemblyconnectordraw, fill=\tikzumlassemblyconnectorfill] (\tikzuml@ACInterface@nodeName-io) at (\tikzuml@AC@xio,\tikzuml@AC@yio) {};% - \begin{scope}% - \pgfmathsetlength{\tikzuml@AC@xtrc}{\tikzuml@AC@xic-2*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}% - \pgfmathsetlength{\tikzuml@AC@ytrc}{\tikzuml@AC@yic+2*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}% - \pgfmathsetlength{\tikzuml@AC@xbrc}{\tikzuml@AC@xic+2*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}% - \pgfmathsetlength{\tikzuml@AC@ybrc}{\tikzuml@AC@yic-2*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}% - \pgfmathsetlength{\tikzuml@AC@xtlc}{\tikzuml@AC@xic-3*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya+\tikzuml@AC@xb-\tikzuml@AC@xa)}% - \pgfmathsetlength{\tikzuml@AC@ytlc}{\tikzuml@AC@yic+3*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa+\tikzuml@AC@ya-\tikzuml@AC@yb)}% - \pgfmathsetlength{\tikzuml@AC@xblc}{\tikzuml@AC@xic+3*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya+\tikzuml@AC@xa-\tikzuml@AC@xb)}% - \pgfmathsetlength{\tikzuml@AC@yblc}{\tikzuml@AC@yic-3*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa+\tikzuml@AC@yb-\tikzuml@AC@ya)}% - \coordinate (\tikzuml@ACInterface@nodeName-trc) at (\tikzuml@AC@xtrc,\tikzuml@AC@ytrc);% - \coordinate (\tikzuml@ACInterface@nodeName-brc) at (\tikzuml@AC@xbrc,\tikzuml@AC@ybrc);% - \coordinate (\tikzuml@ACInterface@nodeName-tlc) at (\tikzuml@AC@xtlc,\tikzuml@AC@ytlc);% - \coordinate (\tikzuml@ACInterface@nodeName-blc) at (\tikzuml@AC@xblc,\tikzuml@AC@yblc);% - \clip (\tikzuml@ACInterface@nodeName-trc) -- (\tikzuml@ACInterface@nodeName-tlc) -- (\tikzuml@ACInterface@nodeName-blc) -- (\tikzuml@ACInterface@nodeName-brc) -- cycle;% - \node[inner sep=0, text width=\tikzuml@AC@width, circle, draw=\tikzumlassemblyconnectordraw, fill=\tikzumlassemblyconnectorfill] (\tikzuml@ACInterface@nodeName-ic) at (\tikzuml@AC@xic,\tikzuml@AC@yic) {};% - \end{scope}% - \node[above, font=\tikzumlfont] at (\tikzuml@ACInterface@nodeName-interface.north) - {\tikzumlAssemblyConnectorLabel};% - }{}% -}% - -\newcommand{\umlassemblyconnector}[3][]{% - \def\tikzumlAssemblyConnectorWithPort{tikzumlFalse}% - \def\tikzumlAssemblyConnectorFirstArm{tikzumlFalse}% - \def\tikzumlAssemblyConnectorSecondArm{tikzumlFalse}% - \def\tikzumlAssemblyConnectorMiddleArm{tikzumlFalse}% - \def\tikzumlAssemblyConnectorLastArm{tikzumlFalse}% - \pgfkeys{/tikzuml/assemblyconnectorrelation/.cd,% - geometry/.initial=--, interface/.initial={},% - arm1/.initial={auto}, arm2/.initial={auto},% - name/.initial=connector-\thetikzumlConnectorNum, width/.initial=1em,% - anchor1/.initial={}, anchor2/.initial={},% - draw/.initial=\tikzumldrawcolor,% - fill assembly connector/.initial=\tikzumlfillassemblyconnectorcolor,% - fill port/.initial=\tikzumlfillportcolor,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{with port}}{% - \def\tikzumlAssemblyConnectorWithPort{tikzumlTrue}% - }{% - \ifthenelse{\equal{\keyname}{first arm}}{% - \def\tikzumlAssemblyConnectorFirstArm{tikzumlTrue}% - }{% - \ifthenelse{\equal{\keyname}{second arm}}{% - \def\tikzumlAssemblyConnectorSecondArm{tikzumlTrue}% - }{% - \ifthenelse{\equal{\keyname}{middle arm}}{% - \def\tikzumlAssemblyConnectorMiddleArm{tikzumlTrue}% - }{% - \ifthenelse{\equal{\keyname}{last arm}}{% - \def\tikzumlAssemblyConnectorLastArm{tikzumlTrue}% - }{% - }% - }% - }% - }% - }% - }}% - \pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, #1}% - \pgfkeys{/tikzuml/assemblyconnectorrelation/.cd,% - geometry/.get=\tikzumlAssemblyConnectorGeometry,% - name/.get=\tikzumlAssemblyConnectorName,% - interface/.get=\tikzumlAssemblyConnectorLabel,% - width/.get=\tikzumlAssemblyConnectorWidth,% - arm1/.get=\tikzumlAssemblyConnectorStartArm,% - arm2/.get=\tikzumlAssemblyConnectorEndArm,% - anchor1/.get=\umlAssemblyConnectorStartAnchor,% - anchor2/.get=\umlAssemblyConnectorEndAnchor,% - draw/.get=\tikzumlassemblyconnectordraw,% - fill assembly connector/.get=\tikzumlassemblyconnectorfill,% - fill port/.get=\tikzumlassemblyconnectorportfill}% - % - \edef\tikzumlAssemblyConnectorStart@name{#2}% - \edef\tikzumlAssemblyConnectorEnd@name{#3}% - % - \begingroup% - \def\_{_}\edef\x{\endgroup% - \def\noexpand\tikzumlAssemblyConnectorStart@nodeName{\tikzumlAssemblyConnectorStart@name}}\x% - % - \begingroup% - \def\_{_}\edef\x{\endgroup% - \def\noexpand\tikzumlAssemblyConnectorEnd@nodeName{\tikzumlAssemblyConnectorEnd@name}}\x% - % - \begingroup% - \def\_{_}\edef\x{\endgroup% - \def\noexpand\tikzumlAssemblyConnectorLabel@nodeName{\tikzumlAssemblyConnectorLabel}}\x% - % - \pgfextractx{\tikzuml@AC@xa}{\pgfpointanchor{\tikzumlAssemblyConnectorStart@nodeName}{center}}% - \pgfextracty{\tikzuml@AC@ya}{\pgfpointanchor{\tikzumlAssemblyConnectorStart@nodeName}{center}}% - \pgfextractx{\tikzuml@AC@xb}{\pgfpointanchor{\tikzumlAssemblyConnectorEnd@nodeName}{center}}% - \pgfextracty{\tikzuml@AC@yb}{\pgfpointanchor{\tikzumlAssemblyConnectorEnd@nodeName}{center}}% - % - \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{--}}{% - \ifthenelse{\tikzuml@AC@xb>\tikzuml@AC@xa}{% - \def\tikzumlAssemblyConnectorStartAnchor{east}% - \def\tikzumlAssemblyConnectorEndAnchor{west}% - }{% - \def\tikzumlAssemblyConnectorStartAnchor{west}% - \def\tikzumlAssemblyConnectorEndAnchor{east}% - } - }{}% - % - \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|}}{% - \ifthenelse{\tikzuml@AC@xb>\tikzuml@AC@xa}{% - \def\tikzumlAssemblyConnectorStartAnchor{east}% - }{% - \def\tikzumlAssemblyConnectorStartAnchor{west}% - } - \ifthenelse{\tikzuml@AC@yb>\tikzuml@AC@ya}{% - \def\tikzumlAssemblyConnectorEndAnchor{south}% - }{% - \def\tikzumlAssemblyConnectorEndAnchor{north}% - } - }{}% - % - \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-}}{% - \ifthenelse{\tikzuml@AC@xb>\tikzuml@AC@xa}{% - \def\tikzumlAssemblyConnectorEndAnchor{west}% - }{% - \def\tikzumlAssemblyConnectorEndAnchor{east}% - } - \ifthenelse{\tikzuml@AC@yb>\tikzuml@AC@ya}{% - \def\tikzumlAssemblyConnectorStartAnchor{north}% - }{% - \def\tikzumlAssemblyConnectorStartAnchor{south}% - } - }{}% - % - \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|-}}{% - \ifthenelse{\equal{\tikzumlAssemblyConnectorStartArm}{auto}}{% - \ifthenelse{\equal{\tikzumlAssemblyConnectorEndArm}{auto}}{% - \pgfmathsetlength{\tikzuml@AC@middleArm}{0.5 * \tikzuml@AC@xa + 0.5 * \tikzuml@AC@xb}% - }{% - \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@xb+\tikzumlAssemblyConnectorEndArm}% - }% - }{% - \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@xa+\tikzumlAssemblyConnectorStartArm}% - }% - \pgfmathparse{\tikzuml@AC@middleArm>\tikzuml@AC@xa} - \pgfmathparse{\tikzuml@AC@middleArm>\tikzuml@AC@xb} - \ifthenelse{\lengthtest{\tikzuml@AC@middleArm>\tikzuml@AC@xa}}{% - \def\tikzumlAssemblyConnectorStartAnchor{east}% - }{% - \def\tikzumlAssemblyConnectorStartAnchor{west}% - } - \ifthenelse{\lengthtest{\tikzuml@AC@middleArm>\tikzuml@AC@xb}}{% - \def\tikzumlAssemblyConnectorEndAnchor{east}% - }{% - \def\tikzumlAssemblyConnectorEndAnchor{west}% - } - }{}% - % - \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-|}}{% - \ifthenelse{\equal{\tikzumlAssemblyConnectorStartArm}{auto}}{% - \ifthenelse{\equal{\tikzumlAssemblyConnectorEndArm}{auto}}{% - \pgfmathsetlength{\tikzuml@AC@middleArm}{0.5 * \tikzuml@AC@ya + 0.5 * \tikzuml@AC@yb}% - }{% - \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@yb+\tikzumlAssemblyConnectorEndArm}% - }% - }{% - \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@ya+\tikzumlAssemblyConnectorStartArm}% - }% - \ifthenelse{\tikzuml@AC@middleArm>\tikzuml@AC@ya}{% - \def\tikzumlAssemblyConnectorStartAnchor{north}% - }{% - \def\tikzumlAssemblyConnectorStartAnchor{south}% - } - \ifthenelse{\tikzuml@AC@middleArm>\tikzuml@AC@yb}{% - \def\tikzumlAssemblyConnectorEndAnchor{north}% - }{% - \def\tikzumlAssemblyConnectorEndAnchor{south}% - } - }{}% - % - \ifthenelse{\equal{\umlAssemblyConnectorStartAnchor}{}}{% - }{% - \def\tikzumlAssemblyConnectorStartAnchor{\umlAssemblyConnectorStartAnchor}% - }% - \ifthenelse{\equal{\umlAssemblyConnectorEndAnchor}{}}{% - }{% - \def\tikzumlAssemblyConnectorEndAnchor{\umlAssemblyConnectorEndAnchor}% - }% - % - \node[inner sep=0] (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) at (\tikzumlAssemblyConnectorStart@nodeName.\tikzumlAssemblyConnectorStartAnchor) {};% - \node[inner sep=0] (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) at (\tikzumlAssemblyConnectorEnd@nodeName.\tikzumlAssemblyConnectorEndAnchor) {};% - % - \umlrelation[style={tikzuml connector style}, #1]{\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp}{\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp}% - % - \ifthenelse{\equal{\tikzumlAssemblyConnectorWithPort}{tikzumlTrue}}{% - \node[inner sep=0.5*\tikzumlAssemblyConnectorWidth, rectangle, draw=\tikzumlassemblyconnectordraw, fill=\tikzumlassemblyconnectorportfill] (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) {};% - \node[inner sep=0.5*\tikzumlAssemblyConnectorWidth, rectangle, draw=\tikzumlassemblyconnectordraw, fill=\tikzumlassemblyconnectorportfill] (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) {};% - }{% - \node[inner sep=0] (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorStart@nodeName.\tikzumlAssemblyConnectorStartAnchor) {};% - \node[inner sep=0] (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorEnd@nodeName.\tikzumlAssemblyConnectorEndAnchor) {};% - }% - % - \addtocounter{tikzumlRelationNum}{-1}% - \ifthenelse{\equal{\tikzumlAssemblyConnectorName}{connector-\thetikzumlConnectorNum}}{% - \edef\tikzumlAssemblyConnectorName{relation-\thetikzumlRelationNum}% - \edef\tikzumlAssemblyConnectorSymbolName{\tikzumlAssemblyConnectorLabel@nodeName}% - }{% - \edef\tikzumlAssemblyConnectorSymbolName{\tikzumlAssemblyConnectorName}% - }% - % - \stepcounter{tikzumlRelationNum}% - % - \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{--}}{% - \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorEnd@nodeName}% - }{% - \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|}}{% - \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{% - \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}% - }{% - \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorEnd@nodeName}% - }% - }{% - \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-}}{% - \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{% - \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}% - }{% - \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorEnd@nodeName}% - }% - }{% - \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|-}}{% - \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{% - \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}% - }{% - \ifthenelse{\equal{\tikzumlAssemblyConnectorLastArm}{tikzumlTrue}}{% - \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-4}{\tikzumlAssemblyConnectorEnd@nodeName}% - }{% - \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorName-4}% - }% - }% - }{% - \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-|}}{% - \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{% - \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}% - }{% - \ifthenelse{\equal{\tikzumlAssemblyConnectorLastArm}{tikzumlTrue}}{% - \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-4}{\tikzumlAssemblyConnectorEnd@nodeName}% - }{% - \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorName-4}% - }% - }% - }{}% - }% - }% - }% - }% - \stepcounter{tikzumlConnectorNum}% -}% - -% shortcuts of \umlassemblyconnector -\newcommand{\umlHVassemblyconnector}[3][]{% - \pgfkeys{/tikzuml/HVassemblyconnector/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{geometry}}{% - \errmessage{TIKZUML ERROR : in umlHVassemblyconnector, forbidden option geometry}% - }{}% - }}% - \pgfkeys{/tikzuml/HVassemblyconnector/.cd, #1}% - \umlassemblyconnector[geometry=-|, #1]{#2}{#3}% -}% - -\newcommand{\umlVHassemblyconnector}[3][]{% - \pgfkeys{/tikzuml/VHassemblyconnector/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{geometry}}{% - \errmessage{TIKZUML ERROR : in umlVHassemblyconnector, forbidden option geometry}% - }{}% - }% - }% - \pgfkeys{/tikzuml/VHassemblyconnector/.cd, #1}% - \umlassemblyconnector[geometry=|-, #1]{#2}{#3}% -}% - -\newcommand{\umlHVHassemblyconnector}[3][]{% - \pgfkeys{/tikzuml/HVHassemblyconnector/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{geometry}}{% - \errmessage{TIKZUML ERROR : in umlHVHassemblyconnector, forbidden option geometry}% - }{}% - }}% - \pgfkeys{/tikzuml/HVHassemblyconnector/.cd, #1}% - \umlassemblyconnector[geometry=-|-, #1]{#2}{#3}% -}% - -\newcommand{\umlVHVassemblyconnector}[3][]{% - \pgfkeys{/tikzuml/VHVassemblyconnector/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{geometry}}{% - \errmessage{TIKZUML ERROR : in umlVHVassemblyconnector, forbidden option geometry}% - }{}% - }}% - \pgfkeys{/tikzuml/VHVassemblyconnector/.cd, #1}% - \umlassemblyconnector[geometry=|-|, #1]{#2}{#3}% -}% - -\newcommand{\umlport}[3][]{% - \pgfkeys{/tikzuml/port/.cd,% - draw/.initial=\tikzumldrawcolor, fill/.initial=\tikzumlfillportcolor,% - width/.initial=1em,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \errmessage{TIKZUML ERROR : in umlport forbidden option \keyname}% - }}% - \pgfkeys{/tikzuml/port/.cd, #1}% - \pgfkeys{/tikzuml/port/.cd,% - width/.get=\tikzumlPortWidth,% - draw/.get=\tikzumlportdraw, fill/.get=\tikzumlportfill}% - \edef\tikzumlPort@name{#2}% - \edef\tikzumlPort@anchor{#3}% - \begingroup% - \def\_{_}\edef\x{\endgroup% - \def\noexpand\tikzumlPort@nodeName{\tikzumlPort@name}}\x% - % - \node[inner sep=0.5*\tikzumlPortWidth, rectangle, draw=\tikzumlportdraw, fill=\tikzumlportfill] (\tikzumlPort@nodeName-\tikzumlPort@anchor-port) at (\tikzumlPort@nodeName.\tikzumlPort@anchor) {}; -} - -\newcommand{\umldelegateconnector}[3][]{% - \def\tikzumlDelegateConnectorWithStartPort{tikzumlFalse}% - \def\tikzumlDelegateConnectorWithEndPort{tikzumlFalse}% - \pgfkeys{/tikzuml/delegateconnector/.cd, - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR : in umldelegateconnector, forbidden option stereo}% - }{}% - }}% - \pgfkeys{/tikzuml/delegateconnector/.cd, #1}% - \umlrelation[style={tikzuml connector style}, stereo=delegate, #1]{#2}{#3}% -}% - - -% shortcuts of \umldelegateconnector -\newcommand{\umlHVdelegateconnector}[3][]{% - \pgfkeys{/tikzuml/HVdelegateconnector/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR : in umlHVdelegateconnector, forbidden option \keyname}% - }{}% - }}% - \pgfkeys{/tikzuml/HVdelegateconnector/.cd, #1}% - \umldelegateconnector[geometry=-|, #1]{#2}{#3}% -}% - -\newcommand{\umlVHdelegateconnector}[3][]{% - \pgfkeys{/tikzuml/VHdelegateconnector/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR : in umlVHdelegateconnector, forbidden option \keyname}% - }{}% - }}% - \pgfkeys{/tikzuml/VHdelegateconnector/.cd, #1}% - \umldelegateconnector[geometry=|-, #1]{#2}{#3}% -}% - -\newcommand{\umlHVHdelegateconnector}[3][]{% - \pgfkeys{/tikzuml/HVHdelegateconnector/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR : in umlHVHdelegateconnector, forbidden option \keyname}% - }{}% - }}% - \pgfkeys{/tikzuml/HVHdelegateconnector/.cd, #1}% - \umldelegateconnector[geometry=-|-, #1]{#2}{#3}% -}% - -\newcommand{\umlVHVdelegateconnector}[3][]{% - \pgfkeys{/tikzuml/VHVdelegateconnector/.cd,% - .unknown/.code={% - \let\keyname=\pgfkeyscurrentname% - \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{% - \errmessage{TIKZUML ERROR : in umlVHVdelegateconnector, forbidden option \keyname}% - }{}% - }}% - \pgfkeys{/tikzuml/VHVdelegateconnector/.cd, #1}% - \umldelegateconnector[geometry=|-|, #1]{#2}{#3}% -}% -%%% End of tikz-uml.sty -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file diff --git a/talk/tools/compiling.tex b/talk/tools/compiling.tex deleted file mode 100644 index 5da7bee7..00000000 --- a/talk/tools/compiling.tex +++ /dev/null @@ -1,229 +0,0 @@ -\subsection[gcc]{The Compiling Chain} - -\begin{frame}[fragile] - \frametitlecpp[17]{The compiling chain} - \center - \begin{tikzpicture} - \draw[thick] node (code) at(0,0) [rectangle,draw] {Source code} - node (cpp) at(0, -1.5cm) [rectangle,rounded corners,draw] {Preprocessor} - node (gcc) at(3.5cm,-1.5cm) [rectangle,rounded corners,draw] {Compiler} - node (ld) at(7cm,-1.5cm) [rectangle,rounded corners,draw] {Linker} - node (bin) at(7cm,0) [rectangle,draw] {Binary} - node at(0, -2.2cm) {cpp, gcc -E} - node at(3.5cm, -2.2cm) {g++ -c, gcc -c} - node at(7cm, -2.2cm) {ld, gcc, g++}; - \draw[very thick,->] (code) -- (cpp) node [midway,right] {.cpp, .hpp}; - \draw[very thick,->] (cpp) -- (gcc) node [midway,below] {.cpp}; - \draw[very thick,->] (gcc) -- (ld) node [midway,below] {.o}; - \draw[very thick,->] (ld) -- (bin) node [midway,left] {.so, exe}; - \end{tikzpicture} - \begin{block}{The steps} - \begin{description} - \item[cpp] - the preprocessor \\ - handles the \# directives (macros, includes) \\ - creates ``complete'' source code (ie. translation unit) - \item[g++] - the compiler \\ - creates machine code from \cpp code - \item[ld] - the linker \\ - links several binary files into libraries and executables - \end{description} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Compilers} - \begin{block}{Available tools} - \begin{description} - \item[\href{http://gcc.gnu.org/}{\beamergotobutton{gcc}}] - the most common and most used\\ - free and open source - \item[\href{http://clang.llvm.org/}{\beamergotobutton{clang}}] - drop-in replacement of gcc \\ - free and open source, based on LLVM - \item[\href{https://www.intel.com/content/www/us/en/developer/tools/oneapi/dpc-compiler.html\#gs.dyllp0}{\beamergotobutton{icc} \beamergotobutton{icx}}] - Intel's compilers, proprietary but now free \\ - optimized for Intel hardware \\ - icc being replaced by icx, based on LLVM - \item[\href{https://visualstudio.microsoft.com/}{\beamergotobutton{Visual \cpp / MSVC}}] - Microsoft's C++ compiler on Windows - \end{description} - \end{block} - \begin{alertblock}{My preferred choice today} - \begin{itemize} - \item \alert{gcc} as the de facto standard in HEP - \item \hspace{0pt}\alert{clang} in parallel to catch more bugs - \end{itemize} - \end{alertblock} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Useful compiler options (gcc/clang)} - \begin{block}{Get more warnings} - \begin{description} - \item[-Wall -Wextra] get all warnings - \item[-Werror] force yourself to look at warnings - \end{description} - \end{block} - \begin{block}{Optimization} - \begin{description} - \item[-g] add debug symbols (also: \texttt{-g3} or \texttt{-ggdb}) - \item[-Ox] 0 = no opt., 1-2 = opt., 3 = highly opt. (maybe larger binary), g = opt. for debugging - \end{description} - \end{block} - \begin{block}{Compilation environment} - \begin{description} - \item[\texttt{-I} \textless{}path\textgreater] where to find header files - \item[\texttt{-L} \textless{}path\textgreater] where to find libraries - \item[\texttt{-l} \textless{}name\textgreater] link with libname.so - \item[\texttt{-E / -c}] stop after preprocessing / compilation - \end{description} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitle{How to inspect object files?} - \begin{block}{Listing symbols : \texttt{nm}} - \begin{itemize} - \item gives list of symbols in a file - \begin{itemize} - \item these are functions and constants - \item with their internal (mangled/encoded) naming - \end{itemize} - \item also gives type and location in the file for each symbol - \begin{itemize} - \item 'U' type means undefined - \begin{itemize} - \item so a function used but not defined - \item linking will be needed to resolve it - \end{itemize} - \end{itemize} - \item use \texttt{-C} option to demangle on the fly - \end{itemize} - \end{block} - \small - \begin{minted}{shell} -> nm -C Struct.o - U strlen - U _Unwind_Resume -000000000000008a T SlowToCopy::SlowToCopy(SlowToCopy const&) -0000000000000000 T SlowToCopy::SlowToCopy() -0000000000000064 T SlowToCopy::SlowToCopy(std::__cxx11::basic_string... - \end{minted} -\end{frame} - -\begin{frame}[fragile] - \frametitle{How to inspect libraries/executables?} - \begin{block}{Listing dependencies : \texttt{ldd}} - \begin{itemize} - \item gives (recursive) list of libraries required by the given argument - \begin{itemize} - \item and if/where they are found in the current context - \end{itemize} - \item use \texttt{-r} to list missing symbols (mangled) - \end{itemize} - \end{block} - \small - \begin{minted}{shell} -> ldd -r trypoly - linux-vdso.so.1 (0x00007f3938085000) - libpoly.so => not found - libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f3937e00000) - [...] - undefined symbol: _ZNK7Hexagon16computePerimeterEv (./trypoly.sol) - undefined symbol: _ZNK7Polygon16computePerimeterEv (./trypoly.sol) - undefined symbol: _ZN7HexagonC1Ef (./trypoly.sol) - undefined symbol: _ZN8PentagonC1Ef (./trypoly.sol) - \end{minted} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Makefiles} - \begin{block}{Why to use them} - \begin{itemize} - \item an organized way of describing building steps - \item avoids a lot of typing - \end{itemize} - \end{block} - \begin{block}{Several implementations} - \begin{itemize} - \item raw Makefiles: suitable for small projects - \item cmake: portable, the current best choice - \item automake: GNU project solution - \end{itemize} - \end{block} - \begin{minted}{makefile} - test : test.cpp libpoly.so - $(CXX) -Wall -Wextra -o $@ $^ - libpoly.so: Polygons.cpp - $(CXX) -Wall -Wextra -shared -fPIC -o $@ $^ - clean: - rm -f *o *so *~ test test.sol - \end{minted} -\end{frame} - -\begin{frame}[fragile] - \frametitle{CMake} - \begin{block}{} - \begin{itemize} - \item a cross-platform meta build system - \item generates platform-specific build systems - \item see also this \href{https://www.youtube.com/watch?v=eC9-iRN2b04}{basic} and \href{https://www.youtube.com/watch?v=bsXLMQ6WgIk}{detailed} talks - \end{itemize} - \end{block} - \begin{block}{Example CMakeLists.txt} - \begin{minted}[linenos=true,autogobble]{cmake} - cmake_minimum_required(VERSION 3.18) - project(hello CXX) - - find_package(ZLIB REQUIRED) # for external libs - - add_executable(hello main.cpp util.h util.cpp) - set(CMAKE_CXX_STANDARD 20) - target_link_libraries(hello PUBLIC ZLIB::ZLIB) - \end{minted} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitle{CMake - Building} - \begin{block}{Building a CMake-based project} - Start in the directory with the top-level \texttt{CMakeLists.txt}: - \begin{minted}[linenos=true,autogobble]{bash} - mkdir build # will contain all build-related files - cd build - cmake .. # configures and generates a build system - cmake -DCMAKE_BUILD_TYPE=Release .. # pass arguments - ccmake . # change configuration using terminal GUI - cmake-gui . # change configuration using Qt GUI - cmake --build . -j8 # build project with 8 jobs - cmake --build . --target hello # build only hello - sudo cmake --install . # install project into system - cd .. - rm -r build # clean everything - \end{minted} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Compiler chain} - \begin{exercise}{Compiler chain} - \begin{itemize} - \item go to \texttt{exercises/polymorphism} - \item preprocess Polygons.cpp (g++ -E -o output) - \item compile Polygons.o and trypoly.o (g++ -c -o output) - \item use nm to check symbols in .o files - \item look at the Makefile - \item try make clean; make - \item see linking stage of the final program using g++ -v - \begin{itemize} - \item just add a -v in the Makefile command for trypoly target - \item run make clean; make - \item look at the collect 2 line, from the end up to ``-o trypoly'' - \end{itemize} - \item see library dependencies of `trypoly` using `ldd` - \end{itemize} - \end{exercise} -\end{frame} diff --git a/talk/tools/cppinsights.png b/talk/tools/cppinsights.png deleted file mode 100644 index feec56f0..00000000 Binary files a/talk/tools/cppinsights.png and /dev/null differ diff --git a/talk/tools/debugging.tex b/talk/tools/debugging.tex deleted file mode 100644 index 84644c16..00000000 --- a/talk/tools/debugging.tex +++ /dev/null @@ -1,93 +0,0 @@ -\subsection[gdb]{Debugging} - -\begin{frame}[fragile] - \frametitle{Debugging} - \begin{alertblock}{The problem} - \begin{itemize} - \item everything compiles fine (no warning) - \item but crashes at run time - \item no error message, no clue - \end{itemize} - \end{alertblock} - \pause - \begin{block}{The solution: debuggers} - \begin{itemize} - \item dedicated program able to stop execution at any time - \item and show you where you are and what you have - \end{itemize} - \end{block} - \pause - \begin{block}{Existing tools} - \begin{description} - \item[\href{http://www.sourceware.org/gdb/}{\beamergotobutton{gdb}}] - THE main player - \item[\href{http://lldb.llvm.org/}{\beamergotobutton{lldb}}] - the debugger coming with clang/LLVM - \item[\href{https://www.intel.com/content/www/us/en/develop/documentation/get-started-with-debugging-dpcpp-linux/top.html}{\beamergotobutton{gdb-oneapi}}] - the Intel OneAPI debugger - \end{description} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitle{gdb crash course} - \begin{block}{start gdb} - \begin{itemize} - \item gdb \textless{}program\textgreater - \item gdb \textless{}program\textgreater \textless{}core file\textgreater - \item gdb -{}-args \textless{}program\textgreater \textless{}program arguments\textgreater - \end{itemize} - \end{block} - \begin{block}{inspect state} - \begin{description} - \item[bt] prints a backtrace - \item[print \textless{}var\textgreater] prints current content of the variable - \item[list] show code around current point - \item[up/down] go up or down in call stack - \end{description} - \end{block} - \begin{block}{breakpoints} - \begin{description} - \item[break \textless{}function\textgreater] puts a breakpoint on function entry - \item[break \textless{}file\textgreater:\textless{}line\textgreater] puts a breakpoint on that line - \end{description} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitle{gdb} - \begin{exercise}{gdb} - \begin{itemize} - \item go to \texttt{exercises/debug} - \item compile, run, see the crash - \item run it in gdb (or lldb on newer MacOS) - \item inspect backtrace, variables - \item find problem and fix bug - \item try stepping, breakpoints - \end{itemize} - \end{exercise} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Debugging UIs} - \begin{block}{User interfaces for debuggers} - \begin{itemize} - \item offer convenience on top of command line - \item windows for variables, breakpoints, call stack, active threads, watch variables in-code, disassembly, run to cursor ... - \end{itemize} - \begin{description} - \item[Native gdb] Try ``tui enable'' for a simple built-in UI - \item[\href{https://code.visualstudio.com/docs/cpp/cpp-debug}{\beamergotobutton{VSCode}}] - Built-in support for gdb - \item[\href{https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb}{\beamergotobutton{CodeLLDB}}] - VS Code plugin for LLDB - \item[\href{https://github.com/cyrus-and/gdb-dashboard}{\beamergotobutton{GDB dashboard}}] - Poplar terminal UI for gdb - \item[\href{https://github.com/hugsy/gef}{\beamergotobutton{GEF}}] - Modern terminal UI for gdb - \end{description} - \begin{itemize} - \item some editors and most IDEs have good debugger integration - \end{itemize} - \end{block} -\end{frame} diff --git a/talk/tools/doxygen.tex b/talk/tools/doxygen.tex deleted file mode 100644 index 583ee3cb..00000000 --- a/talk/tools/doxygen.tex +++ /dev/null @@ -1,87 +0,0 @@ -\subsection[doxygen]{Doxygen} - -\begin{frame}[fragile] - \frametitle{Doxygen} - \begin{block}{Doxygen} - \begin{itemize} - \item Generates documentation from source code comments - \item Output formats: HTML, LaTeX, XML, ... - \begin{itemize} - \item May be input for further generators, e.g.\ Sphinx - \end{itemize} - \item Doxygen uses a config file, usually called Doxyfile - \item Run \mintinline{bash}{doxygen -g} to generate an initial Doxyfile - \item Edit Doxyfile (e.g.\ output format, source code location, etc.) - \item Run \mintinline{bash}{doxygen} to (re-)generate documentation - \item View e.g.\ HTML documentation using a standard web browser - \item More on the \href{https://doxygen.nl/manual/starting.html}{doxygen website} - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Doxygen} - \begin{block}{Comment blocks} - \begin{columns} - \begin{column}{.35\textwidth} - \begin{cppcode*}{} - /** - * text/directives ... - */ - some_cpp_entity - - /*! - * text/directives ... - */ - some_cpp_entity - \end{cppcode*} - \end{column} - \begin{column}{.35\textwidth} - \begin{cppcode*}{firstnumber=10} - /// - /// text/directives ... - /// - some_cpp_entity - - //! - //! text/directives ... - //! - some_cpp_entity - \end{cppcode*} - \end{column} - \end{columns} - \begin{itemize} - \item More details available \href{https://www.doxygen.nl/manual/docblocks.html}{here} - \end{itemize} - \end{block} - \begin{block}{Comment blocks for members} - \begin{cppcode*}{linenos=false} - int a_class_member; ///< trailing documentation - \end{cppcode*} - \end{block} - -\end{frame} - -\begin{frame}[fragile] - \frametitle{Doxygen} - \begin{block}{Comment directives} - \begin{cppcode*}{} - /** - * Long description here. May include HTML etc. - * - * \brief Checks whether i is odd - * \tparam Integral The integral type of the input - * \param i Input value - * \return True if i is odd, otherwise false - * \throw std::out_of_range if i is larger than 100 - * \see isEven - */ - template <typename Integral> - bool isOdd(Integral i); - \end{cppcode*} - \begin{itemize} - \item All directives can also start with @ instead of \textbackslash - \item A list of all commands can be found \href{https://doxygen.nl/manual/commands.html}{here} - \end{itemize} - \end{block} -\end{frame} diff --git a/talk/tools/editors.tex b/talk/tools/editors.tex deleted file mode 100644 index 94d34463..00000000 --- a/talk/tools/editors.tex +++ /dev/null @@ -1,29 +0,0 @@ -\subsection[edit]{\cpp editor} - -\begin{frame}[fragile] - \frametitle{\cpp editors and IDEs} - \begin{block}{Can dramatically improve your efficiency by} - \begin{itemize} - \item Coloring the code for you to ``see'' the structure - \item Helping with indenting and formatting properly - \item Allowing you to easily navigate in the source tree - \item Helping with compilation/debugging, profiling, static analysis - \item Showing you errors and suggestions while typing - \end{itemize} - \end{block} - \begin{block}{} - \begin{description} - \item[\href{http://www.microsoft.com/}{\beamergotobutton{Visual Studio}}] - Heavy, fully fledged IDE for Windows - \item[\href{https://code.visualstudio.com/}{\beamergotobutton{Visual Studio Code}}] - Editor, open source, portable, many plugins - \item[\href{https://www.eclipse.org/}{\beamergotobutton{Eclipse}}] - IDE, open source, portable - \item[\href{http://www.gnu.org/software/emacs/}{\beamergotobutton{Emacs}} \href{https://www.vim.org/}{\beamergotobutton{Vim}}] - Editors for experts, extremely powerful. \\ - They are to IDEs what latex is to PowerPoint - \item[CLion, Code::Blocks, Atom, NetBeans, Sublime Text, ...] - \end{description} - Choosing one is mostly a matter of taste - \end{block} -\end{frame} diff --git a/talk/tools/formatting.tex b/talk/tools/formatting.tex deleted file mode 100644 index 789bb149..00000000 --- a/talk/tools/formatting.tex +++ /dev/null @@ -1,40 +0,0 @@ -\subsection[format]{Code formatting} - -\begin{frame}[fragile] -\frametitle{clang-format} -\begin{block}{.clang-format} - \begin{itemize} - \item File describing your formatting preferences - \item Should be checked-in at the repository root (project wide) - \item \mintinline{bash}{clang-format -style=LLVM -dump-config >} \\ - \mintinline{bash}{.clang-format} - \item Adapt style options with help from: \url{https://clang.llvm.org/docs/ClangFormatStyleOptions.html} - \end{itemize} -\end{block} -\begin{block}{Run clang-format} - \begin{itemize} - \item \mintinline{bash}{clang-format --style=LLVM -i <file.cpp>} - \item \mintinline{bash}{clang-format -i <file.cpp>} (looks for .clang-format file) - \item \mintinline{bash}{git clang-format} (formats local changes) - \item \mintinline{bash}{git clang-format <ref>} (formats changes since git \textless{}ref\textgreater{}) - \item Most editors/IDEs can find a .clang-format file and adapt - \end{itemize} -\end{block} -\end{frame} - -\begin{frame}[fragile] -\frametitle{clang-format} -\begin{exercise}{clang-format} - \begin{itemize} - \item Go to any example - \item Format code with: \mintinline{bash}{clang-format --style=GNU -i <file.cpp>} - \item Inspect changes, try \mintinline{bash}{git diff .} - \item Revert changes using \mintinline{bash}{git checkout -- <file.cpp>} or \mintinline{bash}{git checkout .} - \item Go to \texttt{exercises} directory and create a .clang-format file \\ - \mintinline{bash}{clang-format -style=LLVM -dump-config >} \\ - \mintinline{bash}{.clang-format} - \item Run \mintinline{bash}{clang-format -i <any_exercise>/*.cpp} - \item Revert changes using \mintinline{bash}{git checkout <any_exercise>} - \end{itemize} -\end{exercise} -\end{frame} diff --git a/talk/tools/godbolt.png b/talk/tools/godbolt.png deleted file mode 100644 index fdf37441..00000000 Binary files a/talk/tools/godbolt.png and /dev/null differ diff --git a/talk/tools/profiling.tex b/talk/tools/profiling.tex deleted file mode 100644 index 5081a2ff..00000000 --- a/talk/tools/profiling.tex +++ /dev/null @@ -1,42 +0,0 @@ -\subsection[prof]{Profiling} - -\begin{frame}[fragile] - \frametitle{Profiling} - \begin{block}{Conceptually} - \begin{itemize} - \item take a measurement of a performance aspect of a program - \begin{itemize} - \item where in my code is most of the time spent? - \item is my program compute or memory bound? - \item does my program make good use of the cache? - \item is my program using all cores most of the time? - \item how often are threads blocked and why? - \item which API calls are made and in which order? - \item ... - \end{itemize} - \item the goal is to find performance bottlenecks - \item is usually done on a compiled program, not on source code - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitle{perf, VTune and uProf} - \begin{block}{perf} - \begin{itemize} - \item perf is a powerful command line profiling tool for linux - \item compile with \mintinline{bash}{-g -fno-omit-frame-pointer} - \item \mintinline{bash}{perf stat -d <prg>} gathers performance statistics while running \mintinline{bash}{<prg>} - \item \mintinline{bash}{perf record -g <prg>} starts profiling \mintinline{bash}{<prg>} - \item \mintinline{bash}{perf report} displays a report from the last profile - \item More information in \href{https://perf.wiki.kernel.org/index.php/Main_Page}{this wiki}, \href{https://www.brendangregg.com/linuxperf.html}{this website} or \href{https://indico.cern.ch/event/980497/contributions/4130271/attachments/2161581/3647235/linux-systems-performance.pdf}{this talk}. - \end{itemize} - \end{block} - \begin{block}{Intel VTune and AMD uProf} - \begin{itemize} - \item Graphical profilers from CPU vendors with rich features - \item Needs vendor's CPU for full experience - \item More information on \href{https://www.intel.com/content/www/us/en/developer/tools/oneapi/vtune-profiler.html}{Intel's website} and \href{https://developer.amd.com/amd-uprof/}{AMD's website} - \end{itemize} - \end{block} -\end{frame} diff --git a/talk/tools/sanitizers.tex b/talk/tools/sanitizers.tex deleted file mode 100644 index 284803be..00000000 --- a/talk/tools/sanitizers.tex +++ /dev/null @@ -1,275 +0,0 @@ -\subsection[sani]{Sanitizers} - -\begin{frame}[fragile] - \frametitle{Address Sanitizer (ASan)} - \begin{block}{ASan introduction} - \begin{itemize} - \item Compiler instrumentation - \item Program stops on invalid memory access, e.g.\ - \begin{itemize} - \item Invalid read/write on heap and stack - \item Double free/delete, use after free - \item Buffer overflow on stack (few tools can do this) - \item Only linux: memory leaks - \end{itemize} - \end{itemize} - \end{block} - \pause - \begin{exampleblock}{Usage (gcc/clang syntax)} - \begin{itemize} - \item Compile with \mintinline{bash}{-fsanitize=address -fno-omit-frame-pointer -g} - \item With clang, add optionally: \texttt{-fsanitize-address-use-after-return=always -fsanitize-address-use-after-scope} - \item Link with \mintinline{bash}{-fsanitize=address} - \item Run the program - \end{itemize} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Address Sanitizer (ASan)} - \begin{block}{How it works} - \begin{itemize} - \item Compiler adds run-time checks ($\sim$2x slow down) - \item \cppinline{IsPoisoned(address)} looks up state of address in asan's ``shadow memory'' - \item Shadow memory: memory where 1 shadow byte tracks state of 8 application bytes (state = accessible, poisoned, \ldots) - \item Functions that deal with memory (\cppinline{new() / delete()} / strings / ...) update entries in shadow memory when called - \end{itemize} - \end{block} - \begin{exampleblock}{asan instrumentation (mock code)} - \begin{overprint} - \onslide<1> - \vfill - \begin{cppcode*}{} - int i = *address; - \end{cppcode*} - \onslide<2-> - \vfill - \begin{cppcode*}{} - if (IsPoisoned(address)) { - ReportError(address, kAccessSize, kIsWrite); - } - int i = *address; - \end{cppcode*} - \end{overprint} - \end{exampleblock} -\end{frame} - - -\begin{frame}[fragile] - \begin{block}{ASan red zones} - \begin{itemize} - \item If adjacent data blocks are owned by the process, the operating system will allow an access - \item<2> ASan surrounds blocks of memory by poisoned red zones - \item<2> Program stops when accessing a red zone - \end{itemize} - \end{block} - \begin{exampleblock}{Illegal access (not detected without ASan)} - \begin{multicols}{2} - \begin{overprint} - \onslide<1> - \begin{cppcode*}{} - void foo() { - char a[8]; - char b[8]; - a[8] = '1'; - } - \end{cppcode*} - \onslide<2> - \begin{minted}{diff} - void foo() { -+ char redzone1[32]; - char a[8]; -+ char redzone2[24]; - char b[8]; -+ char redzone3[24]; -+ // <poison redzones> - a[8] = '1'; -+ // <unpoison redzones> - } - \end{minted} - \end{overprint} - \columnbreak - \begin{tikzpicture} - \clip (0,0) rectangle (6cm, 3cm); - \memorystack[word size=4,nb blocks=4] - \onslide<1>{ - \draw[fill=green!70,opacity=0.5] (0.,0.*\stacksizey) rectangle (\stacksizex/4.,1.*\stacksizey) node[midway]{\footnotesize a[0-7]}; - \draw[fill=orange,opacity=0.5] (\stacksizex/4.,0.*\stacksizey) rectangle (\stacksizex/2.,1.*\stacksizey) node[midway]{\footnotesize b[0-7]}; - } - \memorygoto{2} - \onslide<2->{ - \draw[fill=red!70,opacity=0.5] (0.,0.*\stacksizey) rectangle (\stacksizex,1.*\stacksizey) node[midway]{redzone1}; - \memorypush{a[0-7]} - \draw[fill=red!70,opacity=0.5] (0.+\stacksizex/4.,1.*\stacksizey) rectangle (\stacksizex,2.*\stacksizey) node[midway]{redzone2}; - \memorypush{b[0-7]} - \draw[fill=red!70,opacity=0.5] (0.+\stacksizex/4.,2.*\stacksizey) rectangle (\stacksizex,3.*\stacksizey) node[midway]{redzone3}; - } - \end{tikzpicture} - \end{multicols} - \vspace{1mm} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \vspace{-1\baselineskip} - \begin{columns} - \column{\textwidth+1cm} - \scriptsize - \begin{Verbatim}[commandchars=\\\{\}] - \ttfamily -\textcolor{teal}{==34015==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffee93ed968 at pc 0x000106812df4 bp 0x7ffee93ed930 sp 0x7ffee93ed928} -\textcolor{blue}{WRITE of size 1 at 0x7ffee93ed968 thread T0} - #0 0x106812df3 in foo() asan.cpp:4 - #1 0x106812ed8 in main asan.cpp:9 - #2 0x7fff6d3923d4 in start (libdyld.dylib:x86_64+0x163d4) - -\textcolor{teal}{Address 0x7ffee93ed968 is located in stack of thread T0 at offset 40 in frame} - #0 0x106812cdf in foo() asan.cpp:1 - - This frame has 2 object(s): - [32, 40) 'a' (line 2) \textcolor{teal}{<== Memory access at offset 40 overflows this variable} - [64, 72) 'b' (line 3) -Shadow bytes around the buggy address: -=>0x1fffdd27db20: 00 00 00 00 00 00 00 00 \textcolor{red}{f1 f1 f1 f1} 00[\textcolor{red}{f2}]\textcolor{red}{f2 f2} - 0x1fffdd27db30: 00 \textcolor{red}{f3 f3 f3} 00 00 00 00 00 00 00 00 00 00 00 00 - 0x1fffdd27db40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 0x1fffdd27db50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -Shadow byte legend (one shadow byte represents 8 application bytes): - Addressable: 00 - Partially addressable: 01 02 03 04 05 06 07 - Heap left redzone: \textcolor{red}{fa} - Freed heap region: \textcolor{pink}{fd} - Stack left redzone: \textcolor{red}{f1} - Stack mid redzone: \textcolor{red}{f2} - Stack right redzone: \textcolor{red}{f3} - Stack after return: \textcolor{pink}{f5} - \end{Verbatim} - \end{columns} -\end{frame} - -\begin{frame}[fragile] - \begin{columns} - \column{\textwidth+1cm} - \begin{block}{Finding memory leaks with ASan} - \begin{itemize} - \item On linux, ASan can display memory leaks (``LeakSanitizer'') - \item Might be active already, otherwise start executable with \mintinline{bash}{ASAN_OPTIONS=detect_leaks=1 ./myProgram} - \end{itemize} - \end{block} - \scriptsize - \begin{Verbatim}[commandchars=\\\{\}] - \ttfamily -\textcolor{red}{==113262==ERROR: LeakSanitizer: detected memory leaks} - -\textcolor{blue}{Direct leak of 32 byte(s) in 1 object(s) allocated from:} - #0 0x7f2671201647 in operator new(unsigned long) /build/dkonst/WORK/build/contrib/gcc-10.1.0/src/gcc/10.1.0/libsanitizer/asan/asan_new_delete.cpp:99 - #1 0x4033c7 in memoryLeak[abi:cxx11]() /afs/cern.ch/user/s/shageboe/asan.cpp:33 - #2 0x403633 in main /afs/cern.ch/user/s/shageboe/asan.cpp:40 - #3 0x7f2670a15492 in __libc_start_main (/lib64/libc.so.6+0x23492) - -\textcolor{blue}{Indirect leak of 22 byte(s) in 1 object(s) allocated from:} - #0 0x7f2671201647 in operator new(unsigned long) /build/dkonst/WORK/build/contrib/gcc-10.1.0/src/gcc/10.1.0/libsanitizer/asan/asan_new_delete.cpp:99 - #1 0x403846 in void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char const*>(char const*, char const*, std::forward_iterator_tag) /cvmfs/sft.cern.ch/lcg/releases/gcc/10.1.0.c82-6f386/x86_64-centos8/include/c++/10.1.0/bits/basic_string.tcc:219 - #2 0x4033f4 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string<std::allocator<char> >(char const*, std::allocator<char> const&) /cvmfs/sft.cern.ch/lcg/releases/gcc/10.1.0.c82-6f386/x86_64-centos8/include/c++/10.1.0/bits/basic_string.h:247 - #3 0x4033f4 in memoryLeak[abi:cxx11]() /afs/cern.ch/user/s/shageboe/asan.cpp:33 - #4 0x403633 in main /afs/cern.ch/user/s/shageboe/asan.cpp:40 - #5 0x7f2670a15492 in __libc_start_main (/lib64/libc.so.6+0x23492) - -SUMMARY: AddressSanitizer: 54 byte(s) leaked in 2 allocation(s). - \end{Verbatim} - \end{columns} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Address sanitizer (ASan)} - \begin{block}{Wrap up} - \begin{itemize} - \item If a program crashes, run it with asan - \item Should be part of every \cpp{} continuous integration system - \item It will also find bugs that by luck didn't crash the program - \item It doesn't generate false positives - \end{itemize} - \end{block} - - \begin{exampleblock}{More info} - \begin{itemize} - \item \url{https://github.com/google/sanitizers/wiki/AddressSanitizer} - \item Compile with asan, and start executable using \mintinline{bash}{ASAN_OPTIONS=help=1 <executable>} - \end{itemize} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Address sanitizer (ASan)} - \begin{exercise}{address sanitizer} - \begin{itemize} - \item Go to \texttt{exercises/asan} - \item Compile and run the program \texttt{./asan} - \item There are two bugs and one memory leak. Use asan to trace them down. - \end{itemize} - \end{exercise} - -\end{frame} - -\begin{frame}[fragile] - \frametitle{Thread sanitizer (TSan)} - \begin{block}{TSan} - \begin{itemize} - \item Thread sanitizer detects many data races in MT programs - \item Recompile your program with e.g.\ \mintinline{shell}{clang++ -fsanitize=thread -g -O1 datarace.cpp} - \end{itemize} - \end{block} - - \footnotesize - \begin{verbatim} -% ./a.out -WARNING: ThreadSanitizer: data race (pid=19219) -Write of size 4 at 0x7fcf47b21bc0 by thread T1: - #0 Thread1 datarace.c:4 (exe+0x00000000a360) - -Previous write of size 4 at 0x7fcf47b21bc0 by main thread: - #0 main datarace.c:10 (exe+0x00000000a3b4) - -Thread T1 (running) created at: - #0 pthread_create tsan_interceptors.cc:705 (exe+0x00000000c790) - #1 main datarace.c:9 (exe+0x00000000a3a4) - \end{verbatim} - - \begin{block}{} - \scriptsize - \url{https://github.com/google/sanitizers/wiki/ThreadSanitizerCppManual} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Undefined Behaviour Sanitizer (UBSan)} - \begin{block}{UBSan} - \begin{itemize} - \item Tracks uninitialised memory, broken arithmetic, wrong array indexing and other undefined behaviour - \item Recompile your program with e.g.\ \mintinline{bash}{clang++ -fsanitize=undefined -g -O1 ub.cpp} - \end{itemize} - \end{block} - \small - \begin{verbatim} -% ./a.out -up.cpp:3:5: runtime error: signed integer overflow: - 2147483647 + 1 cannot be represented in type 'int' - \end{verbatim} - \begin{block}{} - \footnotesize - \url{https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Undefined Behaviour Sanitizer (UBSan)} - \begin{exercise}{Finding evil run-time bugs} - \begin{itemize} - \item Go to \texttt{exercises/ubsan} - \item Compile and run the program following the instructions in README or in the program - \item The program should run without observable issues - \item Recompile with UBSan and see that almost every second line contains evil bugs - \end{itemize} - \end{exercise} - -\end{frame} diff --git a/talk/tools/staticanalysis.tex b/talk/tools/staticanalysis.tex deleted file mode 100644 index a3e4a66e..00000000 --- a/talk/tools/staticanalysis.tex +++ /dev/null @@ -1,109 +0,0 @@ -\subsection[static]{Static code analysis} - -\begin{frame}[fragile] - \frametitle{Static analysis} - \begin{alertblock}{The problem} - \begin{itemize} - \item all the tools discussed so far work on binaries - \item they analyze the code being run - \item so there is a coverage problem (e.g. for error cases) - \end{itemize} - \end{alertblock} - \pause - \begin{block}{A (partial) solution : analyzing the source code} - \begin{itemize} - \item build a graph of dependencies of the calls - \item use graph tools to detect potential memory corruptions, - memory leaks or missing initializations - \end{itemize} - \end{block} - \pause - \begin{block}{Existing tools} - \begin{description} - \item[\href{http://www.coverity.com/}{\beamergotobutton{Coverity}}] - proprietary tool, the most complete - \item[\href{http://cppcheck.sourceforge.net/}{\beamergotobutton{cppcheck}}] - free and opensource, but less complete - \item[\href{https://clang.llvm.org/extra/clang-tidy/}{\beamergotobutton{clang-tidy}}] - clang-based ``linter'', includes clang static analyzer - \end{description} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitle{cppcheck} - \begin{exercise}{cppcheck} - \begin{itemize} - \item go to \texttt{exercises/cppcheck} - \item compile, run, see that it works - \item use valgrind: no issue - \item use cppcheck, see the problem - \item analyze the issue, and fix it - \item bonus: understand why valgrind did not complain \\ - and how the standard deviation could be biased \\ - hint : use gdb and check addresses of v and diffs - \end{itemize} - \end{exercise} -\end{frame} - -\begin{frame}[fragile] - \frametitle{clang-tidy} - \begin{block}{Documentation and supported checks} - \begin{itemize} - \item \url{https://clang.llvm.org/extra/clang-tidy/} - \end{itemize} - \end{block} - \begin{block}{Run clang-tidy} - \begin{itemize} - \item \mintinline{bash}{clang-tidy <file.cpp> -checks=...} - \item \mintinline{bash}{clang-tidy <file.cpp>} (checks from .clang-tidy file) - \item \mintinline{bash}{clang-tidy <file.cpp> --fix} (applies fixes) - - \end{itemize} - \end{block} - \begin{block}{Compilation flags} - \begin{itemize} - \item clang-tidy needs to know exactly how your program is built - \item \mintinline{bash}{clang-tidy ... -- <all compiler flags>} - \end{itemize} - \end{block} - \begin{block}{.clang-tidy file} - \begin{itemize} - \item describes which checks to run - \item usually checked in at repository root - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \begin{block}{Automatically collecting compilation flags} - \begin{itemize} - \item clang-tidy looks for a file called compile\_commands.json - \item contains the exact build flags for each .cpp file - \item generate with CMake: \\ - \mintinline{bash}{cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ...} - \item for Makefiles try \href{https://github.com/rizsotto/Bear}{\beamergotobutton{Bear}} - \item allows to run clang-tidy in bulk on all files: - \begin{itemize} - \item \mintinline{bash}{run-clang-tidy -checks ...} - \item \mintinline{bash}{run-clang-tidy} (checks from .clang-tidy) - \item \mintinline{bash}{run-clang-tidy -fix} (applies fixes) - \end{itemize} - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitle{clang-tidy} - \begin{exercise}{clang-tidy} - \begin{itemize} - \item go to any example which compiles (e.g. \texttt{exercises/cppcheck}) - \item \mintinline{bash}{mkdir build && cd build} - \item \mintinline{bash}{cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ..} - \item \mintinline{bash}{clang-tidy <../file.cpp> -checks=*} - \item inspect output - \item run with \mintinline{bash}{--fix} flag - \item revert changes using \mintinline{bash}{git checkout <../file.cpp>} - \end{itemize} - \end{exercise} -\end{frame} diff --git a/talk/tools/valgrind.tex b/talk/tools/valgrind.tex deleted file mode 100644 index 2bd53546..00000000 --- a/talk/tools/valgrind.tex +++ /dev/null @@ -1,138 +0,0 @@ -\subsection[valgrind]{The Valgrind family} - -\begin{frame}[fragile] - \frametitle{The valgrind family} - \begin{block}{Valgrind fundamentals} - \begin{itemize} - \item valgrind is a framework for different tools - \item a processor simulator allowing checks in between instructions - \item slow (10-50 times slower than normal execution) - \item easy to use : ``valgrind \textless{}your executable\textgreater'' - \begin{itemize} - \item no recompilation - \item better with -g -O0, but not strictly needed - \end{itemize} - \item it is free and open source - \end{itemize} - \end{block} - \pause - \begin{block}{Main tools} - \begin{description} - \item[memcheck] a memory checker (default tool) and leak detector - \item[callgrind] a call graph builder - \item[helgrind] a race condition detector - \end{description} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitle{memcheck} - \begin{block}{} - \begin{itemize} - \item keeps track of all memory allocations and deallocations - \item is able to detect accesses to unallocated memory - \item and even tell you when it was deallocated if it was - \item or what is the closest array in case of overflow - \item is able to list still allocated memory when program exits\\ - (memory leaks detection) - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitle{valgrind} - \begin{exercise}{valgrind} - \begin{itemize} - \item go to \texttt{exercises/valgrind} - \item compile, run, it should work - \item run with valgrind, see the problem - \item fix the problem - \vspace{.3cm} - \item go back to the \texttt{exercises/debug} exercise - \item check it with valgrind - \item analyze the issue, see that the variance was biaised - \item fix the issue - \end{itemize} - \end{exercise} -\end{frame} - -\begin{frame}[fragile] - \frametitle{memcheck} - \begin{exercise}{memcheck} - \begin{itemize} - \item go to \texttt{exercises/memcheck} - \item compile, run, it should work - \item run with valgrind, see LEAK summary - \item run with -{}-leak-check=full to get details - \item analyze and correct it - \end{itemize} - \end{exercise} -\end{frame} - -\begin{frame}[fragile] - \frametitle{callgrind and kcachegrind} - \begin{block}{callgrind} - \begin{itemize} - \item keeps track of all function calls - \item and time spent in each function - \item build statistics on calls, CPU usages and more - \item outputs flat statistics file, quite unreadable - \end{itemize} - \end{block} - \begin{block}{kcachegrind} - \begin{itemize} - \item a gui exploiting statistics built by callgrind - \item able to browse graphically the program calls - \item able to ``graph'' CPU usage on the program structure - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitle{callgrind} - \begin{exercise}{callgrind} - \begin{itemize} - \item go to \texttt{exercises/callgrind} - \item compile, run, it will be slow - \item change nb iterations to 20 - \item run with valgrind -{}-tool=callgrind - \item look at output with kcachegrind - \item change fibo call to fibo2 - \item observe the change in kcachegrind - \end{itemize} - \end{exercise} -\end{frame} - -\begin{frame}[fragile] - \frametitle{helgrind} - \begin{block}{} - \begin{itemize} - \item keeps track of all pthreads activity - \item in particular keeps track of all mutexes - \item builds a graph of dependencies of the different actions - \item works on the resulting graph to detect: - \begin{itemize} - \item possible dead locks - \item possible data races - \end{itemize} - \end{itemize} - \end{block} - \pause - \begin{alertblock}{} - Note the ``possible''. It finds future problems! - \end{alertblock} -\end{frame} - -\begin{frame}[fragile] - \frametitle{helgrind} - \begin{exercise}{helgrind} - \begin{itemize} - \item go to \texttt{exercises/helgrind} - \item compile, run - \item check it with valgrind. You may see strange behavior \\ - or it will be perfectly fine - \item check it with valgrind -{}-tool=helgrind - \item understand issue and fix - \end{itemize} - \end{exercise} -\end{frame} diff --git a/talk/tools/vcs.tex b/talk/tools/vcs.tex deleted file mode 100644 index 95e7688b..00000000 --- a/talk/tools/vcs.tex +++ /dev/null @@ -1,49 +0,0 @@ -\subsection[VCS]{Version control} - -\begin{frame}[fragile] - \frametitle{Version control} - \begin{alertblock}{Please use one!} - \begin{itemize} - \item Even locally - \item Even on a single file - \item Even if you are the only committer - \end{itemize} - It will soon save your day - \end{alertblock} - \begin{block}{A few tools} - \begin{description} - \item[\href{http://git-scm.com/}{\beamergotobutton{git}}] - THE mainstream choice. Fast, light, easy to use - \item[\href{http://mercurial.selenic.com/}{\beamergotobutton{mercurial}}] - The alternative to git - \item[\href{http://bazaar.canonical.com/en/}{\beamergotobutton{Bazaar}}] - Another alternative - \item[\href{https://subversion.apache.org/}{\beamergotobutton{Subversion}}] - Historical, not distributed - don't use - \item[\href{https://cvs.nongnu.org/}{\beamergotobutton{CVS}}] - Archeological, not distributed - don't use - \end{description} - \end{block} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Git crash course} - \begin{minted}{shell-session} - $ git init myProject - Initialized empty Git repository in myProject/.git/ - - $ vim file.cpp; vim file2.cpp - $ git add file.cpp file2.cpp - $ git commit -m "Committing first 2 files" - [master (root-commit) c481716] Committing first 2 files - ... - - $ git log --oneline - d725f2e Better STL test - f24a6ce Reworked examples + added stl one - bb54d15 implemented template part - ... - - $ git diff f24a6ce bb54d15 - \end{minted} -\end{frame} diff --git a/talk/tools/webtools.tex b/talk/tools/webtools.tex deleted file mode 100644 index 6f26b262..00000000 --- a/talk/tools/webtools.tex +++ /dev/null @@ -1,69 +0,0 @@ -\subsection[web]{Web tools} - -\begin{frame} - \frametitle{Godbolt / Compiler Explorer } - \begin{block}{Concept} - An online generic compiler with immediate feedback. - Allows: - \begin{itemize} - \item trying various compilers in the browser - \item inspecting the assembly generated - \item use of external libraries (over 50 available !) - \item running the produced code - \item sharing small pieces of code via permanent short links - \end{itemize} - \end{block} - \begin{exampleblock}{Typical usage} - \begin{itemize} - \item check small pieces of code on different compilers - \item check some new \cpp functionality and its support - \item optimize small pieces of code - \item NOT relevant for large codes - \end{itemize} - \end{exampleblock} -\end{frame} - -\begin{frame} - \frametitle{Godbolt by example} - \begin{block}{Check effect of optimization flags} - \url{https://godbolt.org/z/Pb8WsWjEx} - \begin{itemize} - \item Check generated code with -O0, -O1, -O2, -O3 - \item See how it gets shorter and simpler - \end{itemize} - \end{block} - \includegraphics[width=\textwidth]{tools/godbolt.png} -\end{frame} - -\begin{frame} - \frametitle{cppinsights} - \begin{block}{Concept} - Reveals the actual code behind \cpp syntactic sugar - \begin{itemize} - \item lambdas - \item range-based loops - \item templates - \item initializations - \item auto - \item ... - \end{itemize} - \end{block} - \begin{exampleblock}{Typical usage} - \begin{itemize} - \item understand how things work behind the \cpp syntax - \item debug some non working pieces of code - \end{itemize} - \end{exampleblock} -\end{frame} - -\begin{frame} - \frametitle{cppinsights by example} - \begin{block}{Check how range-based loop work} - \url{https://cppinsights.io/s/b886aa76} - \begin{itemize} - \item See how they map to regular iterators - \item And how operators are converted to function calls - \end{itemize} - \end{block} - \includegraphics[width=\textwidth]{tools/cppinsights.png} -\end{frame} diff --git a/talk/vscode-tricks.txt b/talk/vscode-tricks.txt deleted file mode 100644 index 2da463ef..00000000 --- a/talk/vscode-tricks.txt +++ /dev/null @@ -1,11 +0,0 @@ - -# From markdown to latex, with vscode replace - -`(.*?)` -> \\mintinline{cpp}{$1} -\*(.*?)\* -> \\textbf{$1} - -# Other - -## Replace {\it <=} with \mintinline{cpp}{<=} - -\{\\it (.*?)\} -> \\mintinline{cpp}{$1} diff --git a/talk/youtube.png b/talk/youtube.png deleted file mode 100644 index ba688b77..00000000 Binary files a/talk/youtube.png and /dev/null differ