├── .coveragerc ├── .gitattributes ├── .github ├── FUNDING.yml ├── dependabot.yml └── workflows │ └── pythonpackage.yml ├── .gitignore ├── CITATION.cff ├── LICENSE ├── Makefile ├── Procfile ├── README.rst ├── app.py ├── app_test.py ├── docs ├── 404.rst ├── Makefile ├── _extra │ └── robots.txt ├── _static │ ├── dennis.png │ └── style.css ├── _templates │ ├── cheatsheets.html │ ├── github.html │ ├── layout.html │ ├── link.html │ └── sidebarintro.html ├── conf.py ├── index.rst └── notes │ ├── asm_basic.rst │ ├── bash_basic.rst │ ├── bash_date.rst │ ├── bash_find.rst │ ├── bash_os.rst │ ├── bash_re.rst │ ├── c_basic.rst │ ├── c_concurrency.rst │ ├── c_file.rst │ ├── c_gnuext.rst │ ├── c_macro.rst │ ├── c_make.rst │ ├── c_signal.rst │ ├── c_socket.rst │ ├── cmake_basic.rst │ ├── cmake_external.rst │ ├── cmake_package.rst │ ├── cpp_algorithm.rst │ ├── cpp_basic.rst │ ├── cpp_casting.rst │ ├── cpp_constexpr.rst │ ├── cpp_constructor.rst │ ├── cpp_container.rst │ ├── cpp_coroutine.rst │ ├── cpp_forwarding.rst │ ├── cpp_initialization.rst │ ├── cpp_iterator.rst │ ├── cpp_lambda.rst │ ├── cpp_ranges.rst │ ├── cpp_rvo.rst │ ├── cpp_smartpointers.rst │ ├── cpp_string.rst │ ├── cpp_template.rst │ ├── cpp_time.rst │ ├── cpp_variadic.rst │ ├── gdb_debug.rst │ ├── perf.rst │ └── systemd.rst ├── requirements.txt └── runtime.txt /.coveragerc: -------------------------------------------------------------------------------- 1 | [report] 2 | omit = 3 | */python?.?/* 4 | */site-packages/* 5 | app_test.py 6 | 7 | exclude_lines = 8 | if __name__ == .__main__.: 9 | if .DYNO. in os.environ: 10 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.svg filter=lfs diff=lfs merge=lfs -text 2 | *.ico filter=lfs diff=lfs merge=lfs -text 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: crazyguitar 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "pip" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | -------------------------------------------------------------------------------- /.github/workflows/pythonpackage.yml: -------------------------------------------------------------------------------- 1 | name: Python package 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | strategy: 10 | max-parallel: 4 11 | matrix: 12 | python: ["3.9", "3.10", "3.11"] 13 | 14 | steps: 15 | - uses: actions/checkout@master 16 | - name: Set up Python ${{ matrix.python }} 17 | uses: actions/setup-python@v1 18 | with: 19 | python-version: ${{ matrix.python }} 20 | - name: Install 21 | run: make deps 22 | - name: Test 23 | run: make clean && make test 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | _build/ 2 | 3 | # Created by https://www.gitignore.io/api/vim,python 4 | 5 | ### Python ### 6 | # Byte-compiled / optimized / DLL files 7 | __pycache__/ 8 | *.py[cod] 9 | *$py.class 10 | 11 | # C extensions 12 | *.so 13 | 14 | # Distribution / packaging 15 | .Python 16 | build/ 17 | develop-eggs/ 18 | dist/ 19 | downloads/ 20 | eggs/ 21 | .eggs/ 22 | lib/ 23 | lib64/ 24 | parts/ 25 | sdist/ 26 | var/ 27 | wheels/ 28 | *.egg-info/ 29 | .installed.cfg 30 | *.egg 31 | 32 | # PyInstaller 33 | # Usually these files are written by a python script from a template 34 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 35 | *.manifest 36 | *.spec 37 | 38 | # Installer logs 39 | pip-log.txt 40 | pip-delete-this-directory.txt 41 | 42 | # Unit test / coverage reports 43 | htmlcov/ 44 | .tox/ 45 | .coverage 46 | .coverage.* 47 | .cache 48 | nosetests.xml 49 | coverage.xml 50 | *.cover 51 | .hypothesis/ 52 | 53 | # Translations 54 | *.mo 55 | *.pot 56 | 57 | # Django stuff: 58 | *.log 59 | local_settings.py 60 | 61 | # Flask stuff: 62 | instance/ 63 | .webassets-cache 64 | 65 | # Scrapy stuff: 66 | .scrapy 67 | 68 | # Sphinx documentation 69 | docs/_build/ 70 | 71 | # PyBuilder 72 | target/ 73 | 74 | # Jupyter Notebook 75 | .ipynb_checkpoints 76 | 77 | # pyenv 78 | .python-version 79 | 80 | # celery beat schedule file 81 | celerybeat-schedule 82 | 83 | # SageMath parsed files 84 | *.sage.py 85 | 86 | # Environments 87 | .env 88 | .venv 89 | env/ 90 | venv/ 91 | ENV/ 92 | env.bak/ 93 | venv.bak/ 94 | 95 | # Spyder project settings 96 | .spyderproject 97 | .spyproject 98 | 99 | # Rope project settings 100 | .ropeproject 101 | 102 | # mkdocs documentation 103 | /site 104 | 105 | # mypy 106 | .mypy_cache/ 107 | 108 | ### Vim ### 109 | # swap 110 | [._]*.s[a-v][a-z] 111 | [._]*.sw[a-p] 112 | [._]s[a-v][a-z] 113 | [._]sw[a-p] 114 | # session 115 | Session.vim 116 | # temporary 117 | .netrwhist 118 | *~ 119 | # auto-generated tag files 120 | tags 121 | 122 | # End of https://www.gitignore.io/api/vim,python 123 | -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | cff-version: 1.2.0 2 | message: "If you use this software, please cite it as below." 3 | title: "C/C++ Cheatsheet" 4 | authors: 5 | - family-names: "Tsai" 6 | given-names: "Chang-Ning" 7 | orcid: "https://orcid.org/0009-0000-5297-5940" 8 | github: "crazyguitar" 9 | abstract: "A comprehensive C++ cheat sheet covering C++ syntax, features, and code snippets." 10 | version: "master" 11 | repository-code: "https://github.com/crazyguitar/cppcheatsheet" 12 | license: "MIT" 13 | date-released: "2016-05-06" 14 | url: "https://github.com/crazyguitar/cppcheatsheet" 15 | keywords: 16 | - cpp 17 | - cheatsheet 18 | - c-plus-plus 19 | - programming 20 | - reference 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Chang Ning Tsai 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | REQUIREMENT = requirements.txt 2 | 3 | VER = $(word 2, $(shell python --version 2>&1)) 4 | SRC = app.py app_test.py 5 | PY36 = $(shell expr $(VER) \>= 3.6) 6 | 7 | .PHONY: build deps test 8 | build: html 9 | 10 | %: 11 | cd docs && make $@ 12 | 13 | test: clean build 14 | pycodestyle $(SRC) 15 | pydocstyle $(SRC) 16 | bandit $(SRC) 17 | coverage run app_test.py && coverage report --fail-under=100 -m $(SRC) 18 | ifeq ($(PY36), 1) 19 | black --quiet --diff --check --line-length 79 $(SRC) 20 | endif 21 | 22 | deps: 23 | pip install -r requirements.txt 24 | ifeq ($(PY36), 1) 25 | pip install black==22.3.0 26 | endif 27 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: make clean && make && gunicorn app:app --log-file - 2 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Documentation Status 2 | ====================== 3 | 4 | .. image:: https://img.shields.io/badge/doc-pdf-blue 5 | :target: https://cppcheatsheet.readthedocs.io/_/downloads/en/latest/pdf/ 6 | 7 | .. image:: https://zenodo.org/badge/53253009.svg 8 | :target: https://doi.org/10.5281/zenodo.15528895 9 | 10 | C Cheat Sheet 11 | ============= 12 | 13 | - `From Scratch `_ 14 | - `GNU C Extension `_ 15 | - `Macro `_ 16 | - `Makefile `_ 17 | - `X86 Assembly `_ 18 | 19 | Modern C++ Cheat Sheet 20 | ====================== 21 | 22 | - `Modern C++ From Scratch `_ 23 | - `Constructor `_ 24 | - `Initialization `_ 25 | - `String `_ 26 | - `Container `_ 27 | - `Iterator `_ 28 | - `Template `_ 29 | - `Variadic `_ 30 | - `Forwarding `_ 31 | - `Casting `_ 32 | - `Constexpr `_ 33 | - `Lambda `_ 34 | - `Time `_ 35 | - `Smart Pointer `_ 36 | - `Return Value Optimization `_ 37 | - `Algorithm `_ 38 | - `Coroutine `_ 39 | - `Ranges `_ 40 | 41 | System Programming Cheat Sheet 42 | ============================== 43 | 44 | - `File I/O `_ 45 | - `Signal `_ 46 | - `Socket `_ 47 | - `Concurrency `_ 48 | 49 | CMake 50 | ===== 51 | 52 | - `CMake `_ 53 | - `Package `_ 54 | - `External Project `_ 55 | 56 | Shell 57 | ===== 58 | 59 | - `Bash From Scratch `_ 60 | - `Bash Date `_ 61 | - `Bash Find `_ 62 | - `Bash Regular Expression `_ 63 | - `Operating System `_ 64 | 65 | GNU Debugger 66 | ============ 67 | 68 | - `GDB `_ 69 | - `Perf `_ 70 | 71 | Systemd 72 | ======= 73 | 74 | - `Systemd `_ 75 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | """This is a simple cheatsheet webapp.""" 2 | 3 | import os 4 | 5 | from flask import Flask, abort, send_from_directory, render_template 6 | from flask_sslify import SSLify 7 | from flask_seasurf import SeaSurf 8 | from flask_talisman import Talisman 9 | 10 | DIR = os.path.dirname(os.path.realpath(__file__)) 11 | ROOT = os.path.join(DIR, "docs", "_build", "html") 12 | 13 | 14 | def find_key(token): 15 | """Find the key from the environment variable.""" 16 | if token == os.environ.get("ACME_TOKEN"): 17 | return os.environ.get("ACME_KEY") 18 | for k, v in os.environ.items(): 19 | if v == token and k.startswith("ACME_TOKEN_"): 20 | n = k.replace("ACME_TOKEN_", "") 21 | return os.environ.get("ACME_KEY_{}".format(n)) 22 | 23 | 24 | csp = { 25 | "default-src": "'none'", 26 | "style-src": ["'self'", "'unsafe-inline'"], 27 | "script-src": [ 28 | "'self'", 29 | "*.cloudflare.com", 30 | "*.googletagmanager.com", 31 | "*.google-analytics.com", 32 | "*.carbonads.com", 33 | "*.carbonads.net", 34 | "'unsafe-inline'", 35 | "'unsafe-eval'", 36 | ], 37 | "form-action": "'self'", 38 | "base-uri": "'self'", 39 | "img-src": "*", 40 | "frame-src": "ghbtns.com", 41 | "frame-ancestors": "'none'", 42 | "object-src": "'none'", 43 | } 44 | 45 | feature_policy = {"geolocation": "'none'"} 46 | 47 | app = Flask(__name__, template_folder=ROOT) 48 | app.config["SECRET_KEY"] = os.urandom(16) 49 | app.config["SESSION_COOKIE_NAME"] = "__Secure-session" 50 | app.config["SESSION_COOKIE_SAMESITE"] = "Strict" 51 | app.config["CSRF_COOKIE_NAME"] = "__Secure-csrf-token" 52 | app.config["CSRF_COOKIE_HTTPONLY"] = True 53 | app.config["CSRF_COOKIE_SECURE"] = True 54 | csrf = SeaSurf(app) 55 | talisman = Talisman( 56 | app, 57 | force_https=False, 58 | content_security_policy=csp, 59 | feature_policy=feature_policy, 60 | ) 61 | 62 | if "DYNO" in os.environ: 63 | sslify = SSLify(app, permanent=True, skips=[".well-known"]) 64 | 65 | 66 | @app.errorhandler(404) 67 | def page_not_found(e): 68 | """Redirect to 404.html.""" 69 | return render_template("404.html"), 404 70 | 71 | 72 | @app.route("/") 73 | def static_proxy(path): 74 | """Find static files.""" 75 | return send_from_directory(ROOT, path) 76 | 77 | 78 | @app.route("/") 79 | def index_redirection(): 80 | """Redirecting index file.""" 81 | return send_from_directory(ROOT, "index.html") 82 | 83 | 84 | @csrf.exempt 85 | @app.route("/.well-known/acme-challenge/") 86 | def acme(token): 87 | """Find the acme-key from environment variable.""" 88 | key = find_key(token) 89 | if key is None: 90 | abort(404) 91 | return key 92 | 93 | 94 | if __name__ == "__main__": 95 | app.run(debug=False) 96 | -------------------------------------------------------------------------------- /app_test.py: -------------------------------------------------------------------------------- 1 | """Test app.py.""" 2 | 3 | import multiprocessing 4 | import platform 5 | import unittest 6 | import requests 7 | import os 8 | 9 | from werkzeug.exceptions import NotFound 10 | from flask_testing import LiveServerTestCase 11 | 12 | from app import acme, find_key, static_proxy, index_redirection, page_not_found 13 | 14 | from app import ROOT 15 | from app import app 16 | 17 | 18 | if platform.system() == "Darwin": 19 | multiprocessing.set_start_method("fork") 20 | 21 | 22 | class PysheeetTest(LiveServerTestCase): 23 | """Test app.""" 24 | 25 | def create_app(self): 26 | """Create a app for test.""" 27 | # remove env ACME_TOKEN* 28 | for k, v in os.environ.items(): 29 | if not k.startswith("ACME_TOKEN"): 30 | continue 31 | del os.environ[k] 32 | 33 | self.token = "token" 34 | self.key = "key" 35 | os.environ["ACME_TOKEN"] = self.token 36 | os.environ["ACME_KEY"] = self.key 37 | os.environ["FLASK_ENV"] = "development" 38 | os.environ["FLASK_DEBUG"] = "1" 39 | app.config["TESTING"] = True 40 | app.config["LIVESERVER_PORT"] = 0 41 | return app 42 | 43 | def check_security_headers(self, resp): 44 | """Check security headers.""" 45 | headers = resp.headers 46 | self.assertTrue("Content-Security-Policy" in headers) 47 | self.assertTrue("X-XSS-Protection" in headers) 48 | self.assertTrue("X-Content-Type-Options" in headers) 49 | self.assertTrue("Content-Security-Policy" in headers) 50 | self.assertTrue("Feature-Policy" in headers) 51 | self.assertEqual(headers["Feature-Policy"], "geolocation 'none'") 52 | self.assertEqual(headers["X-Frame-Options"], "SAMEORIGIN") 53 | 54 | def check_csrf_cookies(self, resp): 55 | """Check cookies for csrf.""" 56 | cookies = resp.cookies 57 | self.assertTrue(cookies.get("__Secure-session")) 58 | self.assertTrue(cookies.get("__Secure-csrf-token")) 59 | 60 | def test_index_redirection_req(self): 61 | """Test that send a request for the index page.""" 62 | url = self.get_server_url() 63 | resp = requests.get(url) 64 | self.check_security_headers(resp) 65 | self.check_csrf_cookies(resp) 66 | self.assertEqual(resp.status_code, 200) 67 | 68 | def test_static_proxy_req(self): 69 | """Test that send a request for notes.""" 70 | htmls = os.listdir(os.path.join(ROOT, "notes")) 71 | url = self.get_server_url() 72 | for h in htmls: 73 | u = url + "/notes/" + h 74 | resp = requests.get(u) 75 | self.check_security_headers(resp) 76 | self.check_csrf_cookies(resp) 77 | self.assertEqual(resp.status_code, 200) 78 | 79 | def test_acme_req(self): 80 | """Test that send a request for a acme key.""" 81 | url = self.get_server_url() 82 | u = url + "/.well-known/acme-challenge/token" 83 | resp = requests.get(u) 84 | self.check_security_headers(resp) 85 | self.assertEqual(resp.status_code, 200) 86 | 87 | u = url + "/.well-known/acme-challenge/foo" 88 | resp = requests.get(u) 89 | self.check_security_headers(resp) 90 | self.assertEqual(resp.status_code, 404) 91 | 92 | def test_find_key(self): 93 | """Test that find a acme key from the environment.""" 94 | token = self.token 95 | key = self.key 96 | self.assertEqual(find_key(token), key) 97 | 98 | del os.environ["ACME_TOKEN"] 99 | del os.environ["ACME_KEY"] 100 | 101 | os.environ["ACME_TOKEN_ENV"] = token 102 | os.environ["ACME_KEY_ENV"] = key 103 | self.assertEqual(find_key(token), key) 104 | 105 | del os.environ["ACME_TOKEN_ENV"] 106 | del os.environ["ACME_KEY_ENV"] 107 | 108 | def test_acme(self): 109 | """Test that send a request for a acme key.""" 110 | token = self.token 111 | key = self.key 112 | self.assertEqual(acme(token), key) 113 | 114 | token = token + "_env" 115 | key = key + "_env" 116 | os.environ["ACME_TOKEN_ENV"] = token 117 | os.environ["ACME_KEY_ENV"] = key 118 | self.assertEqual(find_key(token), key) 119 | 120 | del os.environ["ACME_TOKEN_ENV"] 121 | del os.environ["ACME_KEY_ENV"] 122 | 123 | self.assertRaises(NotFound, acme, token) 124 | 125 | def test_index_redirection(self): 126 | """Test index page redirection.""" 127 | resp = index_redirection() 128 | self.assertEqual(resp.status_code, 200) 129 | resp.close() 130 | 131 | def test_static_proxy(self): 132 | """Test that request static pages.""" 133 | htmls = os.listdir(os.path.join(ROOT, "notes")) 134 | 135 | for h in htmls: 136 | u = "notes/" + h 137 | resp = static_proxy(u) 138 | self.assertEqual(resp.status_code, 200) 139 | resp.close() 140 | 141 | def test_page_not_found(self): 142 | """Test page not found.""" 143 | html, status_code = page_not_found(None) 144 | self.assertEqual(status_code, 404) 145 | 146 | 147 | if __name__ == "__main__": 148 | unittest.main() 149 | -------------------------------------------------------------------------------- /docs/404.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | 404 Page Not Found 4 | ================== 5 | 6 | What you were looking for is just not there. 7 | 8 | `Click here to go back to homepage. `_ 9 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 21 | 22 | .PHONY: help 23 | help: 24 | @echo "Please use \`make ' where is one of" 25 | @echo " html to make standalone HTML files" 26 | @echo " dirhtml to make HTML files named index.html in directories" 27 | @echo " singlehtml to make a single large HTML file" 28 | @echo " pickle to make pickle files" 29 | @echo " json to make JSON files" 30 | @echo " htmlhelp to make HTML files and a HTML help project" 31 | @echo " qthelp to make HTML files and a qthelp project" 32 | @echo " applehelp to make an Apple Help Book" 33 | @echo " devhelp to make HTML files and a Devhelp project" 34 | @echo " epub to make an epub" 35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 36 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 38 | @echo " text to make text files" 39 | @echo " man to make manual pages" 40 | @echo " texinfo to make Texinfo files" 41 | @echo " info to make Texinfo files and run them through makeinfo" 42 | @echo " gettext to make PO message catalogs" 43 | @echo " changes to make an overview of all changed/added/deprecated items" 44 | @echo " xml to make Docutils-native XML files" 45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 46 | @echo " linkcheck to check all external links for integrity" 47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 48 | @echo " coverage to run coverage check of the documentation (if enabled)" 49 | 50 | .PHONY: clean 51 | clean: 52 | rm -rf $(BUILDDIR)/* 53 | 54 | .PHONY: html 55 | html: 56 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 57 | @echo 58 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 59 | 60 | .PHONY: dirhtml 61 | dirhtml: 62 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 63 | @echo 64 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 65 | 66 | .PHONY: singlehtml 67 | singlehtml: 68 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 69 | @echo 70 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 71 | 72 | .PHONY: pickle 73 | pickle: 74 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 75 | @echo 76 | @echo "Build finished; now you can process the pickle files." 77 | 78 | .PHONY: json 79 | json: 80 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 81 | @echo 82 | @echo "Build finished; now you can process the JSON files." 83 | 84 | .PHONY: htmlhelp 85 | htmlhelp: 86 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 87 | @echo 88 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 89 | ".hhp project file in $(BUILDDIR)/htmlhelp." 90 | 91 | .PHONY: qthelp 92 | qthelp: 93 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 94 | @echo 95 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 96 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 97 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/csheeet.qhcp" 98 | @echo "To view the help file:" 99 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/csheeet.qhc" 100 | 101 | .PHONY: applehelp 102 | applehelp: 103 | $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp 104 | @echo 105 | @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." 106 | @echo "N.B. You won't be able to view it unless you put it in" \ 107 | "~/Library/Documentation/Help or install it in your application" \ 108 | "bundle." 109 | 110 | .PHONY: devhelp 111 | devhelp: 112 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 113 | @echo 114 | @echo "Build finished." 115 | @echo "To view the help file:" 116 | @echo "# mkdir -p $$HOME/.local/share/devhelp/csheeet" 117 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/csheeet" 118 | @echo "# devhelp" 119 | 120 | .PHONY: epub 121 | epub: 122 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 123 | @echo 124 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 125 | 126 | .PHONY: latex 127 | latex: 128 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 129 | @echo 130 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 131 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 132 | "(use \`make latexpdf' here to do that automatically)." 133 | 134 | .PHONY: latexpdf 135 | latexpdf: 136 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 137 | @echo "Running LaTeX files through pdflatex..." 138 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 139 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 140 | 141 | .PHONY: latexpdfja 142 | latexpdfja: 143 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 144 | @echo "Running LaTeX files through platex and dvipdfmx..." 145 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 146 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 147 | 148 | .PHONY: text 149 | text: 150 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 151 | @echo 152 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 153 | 154 | .PHONY: man 155 | man: 156 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 157 | @echo 158 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 159 | 160 | .PHONY: texinfo 161 | texinfo: 162 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 163 | @echo 164 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 165 | @echo "Run \`make' in that directory to run these through makeinfo" \ 166 | "(use \`make info' here to do that automatically)." 167 | 168 | .PHONY: info 169 | info: 170 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 171 | @echo "Running Texinfo files through makeinfo..." 172 | make -C $(BUILDDIR)/texinfo info 173 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 174 | 175 | .PHONY: gettext 176 | gettext: 177 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 178 | @echo 179 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 180 | 181 | .PHONY: changes 182 | changes: 183 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 184 | @echo 185 | @echo "The overview file is in $(BUILDDIR)/changes." 186 | 187 | .PHONY: linkcheck 188 | linkcheck: 189 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 190 | @echo 191 | @echo "Link check complete; look for any errors in the above output " \ 192 | "or in $(BUILDDIR)/linkcheck/output.txt." 193 | 194 | .PHONY: doctest 195 | doctest: 196 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 197 | @echo "Testing of doctests in the sources finished, look at the " \ 198 | "results in $(BUILDDIR)/doctest/output.txt." 199 | 200 | .PHONY: coverage 201 | coverage: 202 | $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage 203 | @echo "Testing of coverage in the sources finished, look at the " \ 204 | "results in $(BUILDDIR)/coverage/python.txt." 205 | 206 | .PHONY: xml 207 | xml: 208 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 209 | @echo 210 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 211 | 212 | .PHONY: pseudoxml 213 | pseudoxml: 214 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 215 | @echo 216 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 217 | -------------------------------------------------------------------------------- /docs/_extra/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /docs/_static/dennis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazyguitar/cppcheatsheet/1caf80413b6947fcb3f1695605effad49a98445b/docs/_static/dennis.png -------------------------------------------------------------------------------- /docs/_static/style.css: -------------------------------------------------------------------------------- 1 | nav#table-of-contents { 2 | display: none; 3 | } 4 | 5 | div.highlight > pre { 6 | font-size: 14px; 7 | border-radius: 3px; 8 | background: #f6f8fa !important; 9 | border: 1px solid #000000 !important; 10 | } 11 | -------------------------------------------------------------------------------- /docs/_templates/cheatsheets.html: -------------------------------------------------------------------------------- 1 |

Cheat Sheets

2 | 5 | -------------------------------------------------------------------------------- /docs/_templates/github.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /docs/_templates/layout.html: -------------------------------------------------------------------------------- 1 | {% extends "!layout.html" %} 2 | {%- block extrahead %} 3 | 4 | {%- if pagename == 'index' %} 5 | 6 | 7 | {%- elif pagename == '404' -%} 8 | {%- else %} 9 | 10 | 11 | {%- endif %} 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | {%- if tracking_id %} 24 | 25 | 26 | 33 | {% endif -%} 34 | {%- if pagename == '404' -%} 35 | 42 | {%- endif -%} 43 | {% endblock %} 44 | -------------------------------------------------------------------------------- /docs/_templates/link.html: -------------------------------------------------------------------------------- 1 |

Useful Links

2 | 7 | -------------------------------------------------------------------------------- /docs/_templates/sidebarintro.html: -------------------------------------------------------------------------------- 1 |

About csheeet

2 |

This project tries to provide a lot of piece of c code that makes life easier.

3 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # cppcheatsheet documentation build configuration file, created by 4 | # sphinx-quickstart on Sun Mar 6 19:16:33 2016. 5 | # 6 | # This file is execfile()d with the current directory set to its 7 | # containing dir. 8 | # 9 | # Note that not all possible configuration values are present in this 10 | # autogenerated file. 11 | # 12 | # All configuration values have a default; values that are commented out 13 | # serve to show the default. 14 | 15 | from datetime import datetime 16 | import sys 17 | import os 18 | 19 | # If extensions (or modules to document with autodoc) are in another directory, 20 | # add these directories to sys.path here. If the directory is relative to the 21 | # documentation root, use os.path.abspath to make it absolute, like shown here. 22 | #sys.path.insert(0, os.path.abspath('.')) 23 | 24 | # -- General configuration ------------------------------------------------ 25 | 26 | # If your documentation needs a minimal Sphinx version, state it here. 27 | #needs_sphinx = '1.0' 28 | 29 | # Add any Sphinx extension module names here, as strings. They can be 30 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 31 | # ones. 32 | extensions = [ 33 | 'sphinx.ext.todo', 34 | 'sphinx.ext.coverage', 35 | 'sphinx.ext.viewcode', 36 | ] 37 | 38 | # Add any paths that contain templates here, relative to this directory. 39 | templates_path = ['_templates'] 40 | 41 | # The suffix(es) of source filenames. 42 | # You can specify multiple suffix as a list of string: 43 | # source_suffix = ['.rst', '.md'] 44 | source_suffix = '.rst' 45 | 46 | # The encoding of source files. 47 | #source_encoding = 'utf-8-sig' 48 | 49 | # The master toctree document. 50 | master_doc = 'index' 51 | 52 | # General information about the project. 53 | year = datetime.now().year 54 | project = u'cppcheatsheet' 55 | copyright = u'2016-{}, crazyguitar'.format(year) 56 | author = u'crazyguitar' 57 | 58 | # The version info for the project you're documenting, acts as replacement for 59 | # |version| and |release|, also used in various other places throughout the 60 | # built documents. 61 | # 62 | # The short X.Y version. 63 | version = u'0.1.0' 64 | # The full version, including alpha/beta/rc tags. 65 | release = u'0.1.0' 66 | 67 | # The language for content autogenerated by Sphinx. Refer to documentation 68 | # for a list of supported languages. 69 | # 70 | # This is also used if you do content translation via gettext catalogs. 71 | # Usually you set "language" from the command line for these cases. 72 | language = None 73 | 74 | # There are two options for replacing |today|: either, you set today to some 75 | # non-false value, then it is used: 76 | #today = '' 77 | # Else, today_fmt is used as the format for a strftime call. 78 | #today_fmt = '%B %d, %Y' 79 | 80 | # List of patterns, relative to source directory, that match files and 81 | # directories to ignore when looking for source files. 82 | exclude_patterns = [] 83 | 84 | # The reST default role (used for this markup: `text`) to use for all 85 | # documents. 86 | #default_role = None 87 | 88 | # If true, '()' will be appended to :func: etc. cross-reference text. 89 | #add_function_parentheses = True 90 | 91 | # If true, the current module name will be prepended to all description 92 | # unit titles (such as .. function::). 93 | #add_module_names = True 94 | 95 | # If true, sectionauthor and moduleauthor directives will be shown in the 96 | # output. They are ignored by default. 97 | #show_authors = False 98 | 99 | # The name of the Pygments (syntax highlighting) style to use. 100 | pygments_style = 'sphinx' 101 | 102 | # A list of ignored prefixes for module index sorting. 103 | #modindex_common_prefix = [] 104 | 105 | # If true, keep warnings as "system message" paragraphs in the built documents. 106 | #keep_warnings = False 107 | 108 | # If true, `todo` and `todoList` produce output, else they produce nothing. 109 | todo_include_todos = True 110 | 111 | 112 | # -- Options for HTML output ---------------------------------------------- 113 | 114 | # The theme to use for HTML and HTML Help pages. See the documentation for 115 | # a list of builtin themes. 116 | html_theme = 'alabaster' 117 | 118 | # Theme options are theme-specific and customize the look and feel of a theme 119 | # further. For a list of options available for each theme, see the 120 | # documentation. 121 | html_theme_options = { 122 | 'logo':'dennis.png', 123 | 'show_powered_by': False, 124 | 'github_user': 'crazyguitar', 125 | 'github_repo': 'cppcheatsheet', 126 | 'github_banner': True, 127 | 'github_button': False, 128 | 'show_related': False, 129 | 'head_font_family': 'Georgia', 130 | 'font_family': 'Georgia' 131 | } 132 | 133 | # Add any paths that contain custom themes here, relative to this directory. 134 | #html_theme_path = [] 135 | 136 | # The name for this set of Sphinx documents. If None, it defaults to 137 | # " v documentation". 138 | html_title = "cppcheatsheet" 139 | html_context = { 140 | "tracking_id": os.environ.get("TRACKING_ID") 141 | } 142 | 143 | # A shorter title for the navigation bar. Default is the same as html_title. 144 | #html_short_title = None 145 | 146 | # The name of an image file (relative to this directory) to place at the top 147 | # of the sidebar. 148 | #html_logo = None 149 | 150 | # The name of an image file (relative to this directory) to use as a favicon of 151 | # the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 152 | # pixels large. 153 | #html_favicon = None 154 | 155 | # Add any paths that contain custom static files (such as style sheets) here, 156 | # relative to this directory. They are copied after the builtin static files, 157 | # so a file named "default.css" will overwrite the builtin "default.css". 158 | html_static_path = ['_static'] 159 | html_css_files = ['style.css'] 160 | 161 | # Add any extra paths that contain custom files (such as robots.txt or 162 | # .htaccess) here, relative to this directory. These files are copied 163 | # directly to the root of the documentation. 164 | html_extra_path = ['_extra'] 165 | 166 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 167 | # using the given strftime format. 168 | #html_last_updated_fmt = '%b %d, %Y' 169 | 170 | # If true, SmartyPants will be used to convert quotes and dashes to 171 | # typographically correct entities. 172 | #html_use_smartypants = True 173 | 174 | # Custom sidebar templates, maps document names to template names. 175 | html_sidebars = { 176 | 'index': [ 177 | 'sidebarintro.html', 178 | 'about.html', 179 | 'link.html', 180 | 'github.html', 181 | 'cheatsheets.html', 182 | 'searchbox.html' 183 | ], 184 | '**': [ 185 | 'sidebarintro.html', 186 | 'link.html', 187 | 'github.html', 188 | 'cheatsheets.html', 189 | 'localtoc.html', 190 | 'relations.html', 191 | 'searchbox.html' 192 | ] 193 | } 194 | 195 | # Additional templates that should be rendered to pages, maps page names to 196 | # template names. 197 | #html_additional_pages = {} 198 | 199 | # If false, no module index is generated. 200 | #html_domain_indices = True 201 | 202 | # If false, no index is generated. 203 | #html_use_index = True 204 | 205 | # If true, the index is split into individual pages for each letter. 206 | #html_split_index = False 207 | 208 | # If true, links to the reST sources are added to the pages. 209 | #html_show_sourcelink = True 210 | 211 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 212 | #html_show_sphinx = True 213 | 214 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 215 | #html_show_copyright = True 216 | 217 | # If true, an OpenSearch description file will be output, and all pages will 218 | # contain a tag referring to it. The value of this option must be the 219 | # base URL from which the finished HTML is served. 220 | #html_use_opensearch = '' 221 | 222 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 223 | #html_file_suffix = None 224 | 225 | # Language to be used for generating the HTML full-text search index. 226 | # Sphinx supports the following languages: 227 | # 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' 228 | # 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' 229 | #html_search_language = 'en' 230 | 231 | # A dictionary with options for the search language support, empty by default. 232 | # Now only 'ja' uses this config value 233 | #html_search_options = {'type': 'default'} 234 | 235 | # The name of a javascript file (relative to the configuration directory) that 236 | # implements a search results scorer. If empty, the default will be used. 237 | #html_search_scorer = 'scorer.js' 238 | 239 | # Output file base name for HTML help builder. 240 | htmlhelp_basename = 'cppcheatsheetdoc' 241 | 242 | # -- Options for LaTeX output --------------------------------------------- 243 | 244 | latex_elements = { 245 | # The paper size ('letterpaper' or 'a4paper'). 246 | #'papersize': 'letterpaper', 247 | 248 | # The font size ('10pt', '11pt' or '12pt'). 249 | #'pointsize': '10pt', 250 | 251 | # Additional stuff for the LaTeX preamble. 252 | #'preamble': '', 253 | 254 | # Latex figure (float) alignment 255 | #'figure_align': 'htbp', 256 | } 257 | 258 | # Grouping the document tree into LaTeX files. List of tuples 259 | # (source start file, target name, title, 260 | # author, documentclass [howto, manual, or own class]). 261 | latex_documents = [ 262 | (master_doc, 'cppcheatsheet.tex', u'C/C++ cheatsheet Documentation', 263 | u'crazyguitar', 'manual'), 264 | ] 265 | 266 | # The name of an image file (relative to this directory) to place at the top of 267 | # the title page. 268 | #latex_logo = None 269 | 270 | # For "manual" documents, if this is true, then toplevel headings are parts, 271 | # not chapters. 272 | #latex_use_parts = False 273 | 274 | # If true, show page references after internal links. 275 | #latex_show_pagerefs = False 276 | 277 | # If true, show URL addresses after external links. 278 | #latex_show_urls = False 279 | 280 | # Documents to append as an appendix to all manuals. 281 | #latex_appendices = [] 282 | 283 | # If false, no module index is generated. 284 | #latex_domain_indices = True 285 | 286 | 287 | # -- Options for manual page output --------------------------------------- 288 | 289 | # One entry per manual page. List of tuples 290 | # (source start file, name, description, authors, manual section). 291 | man_pages = [ 292 | (master_doc, 'C/C++ cheatsheet', u'C/C++ cheatsheet Documentation', 293 | [author], 1) 294 | ] 295 | 296 | # If true, show URL addresses after external links. 297 | #man_show_urls = False 298 | 299 | 300 | # -- Options for Texinfo output ------------------------------------------- 301 | 302 | # Grouping the document tree into Texinfo files. List of tuples 303 | # (source start file, target name, title, author, 304 | # dir menu entry, description, category) 305 | texinfo_documents = [ 306 | (master_doc, 'cpp-cheatsheet', u'cpp-cheatsheet Documentation', 307 | author, 'cpp-cheatsheet', 'One line description of project.', 308 | 'Miscellaneous'), 309 | ] 310 | 311 | # Documents to append as an appendix to all manuals. 312 | #texinfo_appendices = [] 313 | 314 | # If false, no module index is generated. 315 | #texinfo_domain_indices = True 316 | 317 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 318 | #texinfo_show_urls = 'footnote' 319 | 320 | # If true, do not generate a @detailmenu in the "Top" node's menu. 321 | #texinfo_no_detailmenu = False 322 | 323 | 324 | # Example configuration for intersphinx: refer to the Python standard library. 325 | intersphinx_mapping = {'https://docs.python.org/': None} 326 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | ============================ 2 | Welcome to C/C++ cheatsheet! 3 | ============================ 4 | 5 | C Cheat Sheet 6 | ------------- 7 | 8 | .. toctree:: 9 | :maxdepth: 1 10 | 11 | notes/c_basic 12 | notes/c_gnuext.rst 13 | notes/c_macro 14 | notes/c_make 15 | notes/asm_basic 16 | 17 | Modern C++ Cheat Sheet 18 | ---------------------- 19 | 20 | .. toctree:: 21 | :maxdepth: 1 22 | 23 | notes/cpp_basic 24 | notes/cpp_constructor 25 | notes/cpp_initialization 26 | notes/cpp_string 27 | notes/cpp_container 28 | notes/cpp_iterator 29 | notes/cpp_template 30 | notes/cpp_variadic 31 | notes/cpp_forwarding 32 | notes/cpp_casting 33 | notes/cpp_constexpr 34 | notes/cpp_lambda 35 | notes/cpp_time 36 | notes/cpp_smartpointers 37 | notes/cpp_rvo 38 | notes/cpp_algorithm 39 | notes/cpp_coroutine 40 | notes/cpp_ranges 41 | 42 | Bash Cheat Sheet 43 | ---------------- 44 | 45 | .. toctree:: 46 | :maxdepth: 1 47 | 48 | notes/bash_basic 49 | notes/bash_date 50 | notes/bash_find 51 | notes/bash_re 52 | notes/bash_os 53 | 54 | System Programming Cheat Sheet 55 | ------------------------------ 56 | 57 | .. toctree:: 58 | :maxdepth: 1 59 | 60 | notes/c_file 61 | notes/c_signal 62 | notes/c_socket 63 | notes/c_concurrency 64 | 65 | CMake Cheat Sheet 66 | ----------------- 67 | 68 | .. toctree:: 69 | :maxdepth: 1 70 | 71 | notes/cmake_basic 72 | notes/cmake_package 73 | notes/cmake_external 74 | 75 | GNU Debugger Cheat Sheet 76 | ------------------------ 77 | 78 | .. toctree:: 79 | :maxdepth: 1 80 | 81 | notes/gdb_debug 82 | notes/perf 83 | 84 | Systemd Cheat Sheet 85 | ------------------- 86 | 87 | .. toctree:: 88 | :maxdepth: 1 89 | 90 | notes/systemd 91 | -------------------------------------------------------------------------------- /docs/notes/asm_basic.rst: -------------------------------------------------------------------------------- 1 | ======================= 2 | X86 Assembly cheatsheet 3 | ======================= 4 | 5 | .. contents:: Table of Contents 6 | :backlinks: none 7 | 8 | Exit 9 | ---- 10 | 11 | .. code-block:: asm 12 | 13 | # gcc -o a.out -nostdlib a.s 14 | 15 | .global _start 16 | .section .text 17 | 18 | _start: 19 | 20 | mov $0x1,%eax # 32 bit of exit is 1 21 | mov $0x1,%ebx 22 | int $0x80 23 | 24 | .section .data 25 | 26 | Note that ``int 0x80`` always invokes 32-bit system calls. To use system calls 27 | define on X64 systems, we need to use ``syscall`` instruction. 28 | 29 | .. code-block:: asm 30 | 31 | .global _start 32 | .section .text 33 | 34 | _start: 35 | 36 | mov $0x3c,%eax # 64 bit of exit is 60(0x3c) 37 | mov $0x1,%ebx 38 | syscall 39 | 40 | .section .data 41 | 42 | Hello Word 43 | ---------- 44 | 45 | .. code-block:: asm 46 | 47 | # gcc -o a.out -nostdlib a.s 48 | # ./a.out 49 | # Hello World 50 | 51 | .global _start 52 | .section .text 53 | 54 | _start: 55 | 56 | # write(stdout, "Hello World", 13); 57 | 58 | mov $0x4,%eax # 32 bit write syscall number 59 | mov $0x1,%ebx # unsigned int fd (stdout) 60 | lea (message),%ecx # const char *buf 61 | mov $13,%edx # size_t count 62 | int $0x80 63 | 64 | # exit(0) 65 | 66 | mov $0x1,%eax 67 | mov $0x0,%ebx 68 | int $0x80 69 | 70 | .section .data 71 | message: 72 | .ascii "Hello World\n" 73 | 74 | do while 75 | -------- 76 | 77 | .. code-block:: asm 78 | 79 | .global _start 80 | .section .text 81 | 82 | _start: 83 | 84 | mov $0x1,%rsi 85 | 86 | loop: # do { 87 | 88 | # write(stdout, "Hello World\n", 13) 89 | mov $0x4,%eax 90 | mov $0x1,%ebx 91 | lea (message),%ecx 92 | mov $13,%edx 93 | int $0x80 94 | 95 | add $0x1,%rsi 96 | cmp $0x5,%rsi 97 | jbe loop # } while(i<=5) 98 | 99 | # exit 100 | mov $0x1,%eax 101 | mov $0x0,%ebx 102 | int $0x80 103 | 104 | .section .data 105 | message: .ascii "Hello World\n" 106 | 107 | Procedures 108 | ---------- 109 | 110 | .. code-block:: asm 111 | 112 | .global _start 113 | .section .text 114 | 115 | _start: 116 | 117 | callq print 118 | 119 | # exit 120 | mov $0x1,%eax 121 | mov $0x0,%ebx 122 | int $0x80 123 | 124 | print: 125 | # write(stdout, "Hello World\n", 13) 126 | mov $0x4,%eax 127 | mov $0x1,%ebx 128 | lea (message),%ecx 129 | mov $13,%edx 130 | int $0x80 131 | ret 132 | 133 | .section .data 134 | message: .ascii "Hello World\n" 135 | 136 | Reference 137 | --------- 138 | 139 | - `Linux System Call Table `_ 140 | - `x86_64 Assembly Linux System Call Confusion `_ 141 | -------------------------------------------------------------------------------- /docs/notes/bash_basic.rst: -------------------------------------------------------------------------------- 1 | ===================== 2 | Bash Basic cheatsheet 3 | ===================== 4 | 5 | .. contents:: Table of Contents 6 | :backlinks: none 7 | 8 | : 9 | - 10 | 11 | `true` was instead simply aliased to :, and false like `let 0`. 12 | 13 | .. code-block:: bash 14 | 15 | $ while :; do sleep 1; date; done 16 | 17 | Special Parameters 18 | ------------------ 19 | 20 | .. code-block:: bash 21 | 22 | #!/bin/bash 23 | 24 | foo() { 25 | # expand to the position params, equal to "$1$2..." 26 | echo $* 27 | # expand to the position params, equal to "$1" "$2" ... 28 | echo $@ 29 | # expand to the number of position params 30 | echo $# 31 | # expand to the pid 32 | echo $$ 33 | # expand to the exit status 34 | echo $? 35 | # expand to the name of shell script 36 | echo $0 37 | } 38 | 39 | foo "a" "b" "c" 40 | 41 | Set Positional Parameters 42 | ------------------------- 43 | 44 | .. code-block:: bash 45 | 46 | $ set -- a b c 47 | $ echo $@ 48 | a b c 49 | $ echo "$1" "$2" "$3" 50 | a b c 51 | 52 | Brace Expansion 53 | --------------- 54 | 55 | .. code-block:: bash 56 | 57 | $ echo foo.{pdf,txt,png,jpg} 58 | foo.pdf foo.txt foo.png foo.jpg 59 | 60 | Variable Expansion 61 | ------------------ 62 | 63 | .. code-block:: bash 64 | 65 | $ foo1="foo1" 66 | $ foo2="foo2" 67 | 68 | # expand to "$foo1 foo2" 69 | $ echo "${!foo*}" 70 | 71 | # expand to "$foo1" "$foo2" 72 | $ echo "${!foo@}" 73 | 74 | Globs 75 | ----- 76 | 77 | "Globs" is a functionality in Bash that matches or expands specific patterns. 78 | It's important to note that in the shell, the asterisk (*) is expanded only if 79 | it is unquoted. If placed within quotation marks, the asterisk will be treated 80 | as a regular character and not undergo expansion. 81 | 82 | .. code-block:: bash 83 | 84 | # list a file which name is "*" 85 | $ ls "${PWD}/*" 86 | 87 | # list current folder files 88 | $ ls ${PWD}/* 89 | 90 | # list files with prefix `foo` 91 | $ ls ${PWD}/foo* 92 | 93 | # list files containing foo 94 | $ ls ${PWD}/*foo* 95 | 96 | # list files with any character in the end (fools not matched) 97 | $ ls ${PWD}/foo? 98 | 99 | # list files with pattern fooc or food 100 | $ ls ${PWD}/foo[ch] 101 | 102 | # list files with ranges [abcd] 103 | $ ls ${PWD}/foo[abcd] 104 | 105 | # list files with ranges [a-z] 106 | $ ls ${PWD}/foo[a-z]* 107 | 108 | # list files with alphanumeric [a-zA-Z0-9] 109 | $ ls ${PWD}/foo[[:alnum:]]* 110 | $ ls ${PWD}/foo[a-zA-Z0-9]* 111 | 112 | String length 113 | ------------- 114 | 115 | .. code-block:: bash 116 | 117 | echo ${#foo} 118 | 7 119 | 120 | String Slice 121 | ------------ 122 | 123 | .. code-block:: bash 124 | 125 | $ foo="01234567890abcdefg" 126 | 127 | # ${param:offset} 128 | $ echo ${foo:7} 129 | 7890abcdefg 130 | 131 | $ echo ${foo: -7} 132 | abcdefg 133 | $ echo ${foo: -7:2} 134 | ab 135 | 136 | # ${param:offset:length} 137 | $ echo ${foo:7:3} 138 | 789 139 | 140 | Delete Match String 141 | ------------------- 142 | 143 | .. code-block:: bash 144 | 145 | $ foo="123,456,789" 146 | # ${p##substring} delete longest match of substring from front 147 | $ echo ${foo##*,} 148 | 789 149 | 150 | # ${p#substring} delete shortest match of substring from front 151 | echo ${foo#*,} 152 | 456,789 153 | 154 | # ${p%%substring} delete longest match of substring from back 155 | $ echo ${foo%%,*} 156 | 123 157 | 158 | $ echo ${foo%,*} 159 | 123,456 160 | 161 | Other examples 162 | 163 | .. code-block:: bash 164 | 165 | disk="/dev/sda" 166 | $ echo ${disk##*/} 167 | sda 168 | 169 | $ disk="/dev/sda3" 170 | echo ${disk%%[0-9]*} 171 | /dev/sda 172 | 173 | Here Documents 174 | -------------- 175 | 176 | .. code-block:: bash 177 | 178 | cat <&2 212 | } 213 | 214 | err() { 215 | echo -e "[$(date +'%Y-%m-%dT%H:%M:%S%z')][${RED}error${REST}] $*" >&2 216 | } 217 | 218 | Check Command Exist 219 | ------------------- 220 | 221 | .. code-block:: bash 222 | 223 | cmd="tput" 224 | if command -v "${tput}" > /dev/null; then 225 | echo "$cmd exist" 226 | else 227 | echo "$cmd does not exist" 228 | fi 229 | 230 | Read a File Line by Line 231 | ------------------------ 232 | 233 | .. code-block:: bash 234 | 235 | #!/bin/bash 236 | 237 | file="file.txt" 238 | while IFS= read -r l; do echo $l; done < "$file" 239 | 240 | Read a File field wise 241 | ---------------------- 242 | 243 | .. code-block:: bash 244 | 245 | #!/bin/bash 246 | 247 | file="/etc/passwd" 248 | while IFS=: read -r n _ _ _ _ _ _; do echo $n; done < "$file" 249 | 250 | Dictionary 251 | ---------- 252 | 253 | .. code-block:: bash 254 | 255 | #!/bin/bash 256 | 257 | declare -A d 258 | d=( ["foo"]="FOO" ["bar"]="BAR" ) 259 | d["baz"]="BAZ" 260 | 261 | for k in "${!d[@]}"; do 262 | echo "${d[$k]}" 263 | done 264 | 265 | Check if a Key Exists in a Dictionary 266 | ------------------------------------- 267 | 268 | .. code-block:: bash 269 | 270 | #!/bin/bash 271 | 272 | declare -A d 273 | d["foo"]="FOO" 274 | if [ -v "d[foo]" ]; then 275 | echo "foo exists in d" 276 | else 277 | echo "foo does exists in d" 278 | fi 279 | 280 | Remove a Key-Value from a Dictionary 281 | ------------------------------------ 282 | 283 | .. code-block:: bash 284 | 285 | $ declare -A d 286 | $ d["foo"]="FOO" 287 | $ unset d["foo"] 288 | 289 | 290 | Append Elements to an Array 291 | --------------------------- 292 | 293 | .. code-block:: bash 294 | 295 | #!/bin/bash 296 | 297 | arr=() 298 | 299 | for i in "a b c d e"; do 300 | arr+=($i) 301 | done 302 | 303 | echo "${arr[@]}" 304 | 305 | Prompt 306 | ------ 307 | 308 | .. code-block:: bash 309 | 310 | #!/bin/bash 311 | 312 | read -p "Continue (y/n)? " c 313 | case "$c" in 314 | y|Y|yes) echo "yes" ;; 315 | n|N|no) echo "no" ;; 316 | *) echo "invalid" ;; 317 | esac 318 | 319 | Parse Arguments 320 | --------------- 321 | 322 | .. code-block:: bash 323 | 324 | #!/bin/bash 325 | 326 | program="$1" 327 | 328 | usage() { 329 | cat <&2; exit 1 ;; 351 | # positional arguments 352 | *) params="$params $1"; shift ;; 353 | esac 354 | done 355 | -------------------------------------------------------------------------------- /docs/notes/bash_date.rst: -------------------------------------------------------------------------------- 1 | ==================== 2 | Bash Date cheatsheet 3 | ==================== 4 | 5 | .. contents:: Table of Contents 6 | :backlinks: none 7 | 8 | Today 9 | ----- 10 | 11 | .. code-block:: bash 12 | 13 | $ date 14 | Sun Jun 20 15:23:20 CST 2021 15 | $ date +"%Y%m%d" 16 | 20210620 17 | 18 | N Days Before 19 | ------------- 20 | 21 | .. code-block:: bash 22 | 23 | # Linux 24 | $ date +%Y%m%d -d "1 day ago" 25 | 20210619 26 | 27 | # BSD (MacOS) 28 | $ date -j -v-1d +"%Y%m%d" 29 | 20210619 30 | -------------------------------------------------------------------------------- /docs/notes/bash_find.rst: -------------------------------------------------------------------------------- 1 | ==================== 2 | Bash Find cheatsheet 3 | ==================== 4 | 5 | .. contents:: Table of Contents 6 | :backlinks: none 7 | 8 | 9 | Find by Suffix 10 | -------------- 11 | 12 | .. code-block:: bash 13 | 14 | $ find "${path}" -name "*.py" 15 | 16 | Find by Substring 17 | ----------------- 18 | 19 | .. code-block:: bash 20 | 21 | $ find "${path}" -name "*code*" 22 | 23 | Find by Case Insensitive 24 | ------------------------ 25 | 26 | .. code-block:: bash 27 | 28 | $ find "${path}" -iname "*.py" 29 | 30 | Find by File Type 31 | ----------------- 32 | 33 | .. code-block:: bash 34 | 35 | # b block 36 | # c character 37 | # d directory 38 | # p named pipe 39 | # f regular file 40 | # l symbolic link 41 | # s socket 42 | 43 | # find regular file 44 | $ find "${path}" -type f -name "*.py" 45 | 46 | # find directory 47 | $ find "${path}" -type d 48 | 49 | Find by Size 50 | ------------ 51 | 52 | .. code-block:: bash 53 | 54 | # find files < 50M 55 | $ find "${path}" -type f -size -50M 56 | 57 | # find files > 50M 58 | $ find "${path}" -type f -size +50M 59 | 60 | Find by Date 61 | ------------ 62 | 63 | .. code-block:: bash 64 | 65 | # files are not accessed > 7 days 66 | $ find "${path}" -type f -atime +7 67 | 68 | # files are accessed < 7 days 69 | $ find "${path}" -type f -atime -7 70 | 71 | # files are not accessed > 10 min 72 | $ find "${path}" -type f -amin +10 73 | 74 | # files are accessed < 10 min 75 | $ find "${path}" -type f -amin -10 76 | 77 | Find by User 78 | ------------ 79 | 80 | .. code-block:: bash 81 | 82 | $ find "${path}" -type f -user "${USER}" 83 | 84 | Delete after Find 85 | ----------------- 86 | 87 | .. code-block:: bash 88 | 89 | # delete by pattern 90 | $ find "${path}" -type f -name "*.sh" -delete 91 | 92 | # delete recursively 93 | find ker -type d -exec rm -rf {} \+ 94 | 95 | 96 | Sort files 97 | ---------- 98 | 99 | .. code-block:: bash 100 | 101 | # ref: https://unix.stackexchange.com/questions/34325 102 | find . -name "*.txt" -print0 | sort -z | xargs -r0 -I{} echo "{}" 103 | 104 | 105 | Loop through files 106 | ------------------ 107 | 108 | .. code-block:: bash 109 | 110 | # ref: https://stackoverflow.com/questions/9612090 111 | 112 | # execute `echo` once for each file 113 | find "${path}" -name "*.txt" -exec echo {} \; 114 | 115 | # execute `echo` once with all the files 116 | find "${path}" -name "*.txt" -exec echo {} + 117 | 118 | # using while loop 119 | find "${path}" -name "*.txt" -print0 | while IFS= read -r -d '' file; do 120 | echo "$file" 121 | done 122 | 123 | # the above example will invoke a subshell, so if we have to set a variable, 124 | # we can rewrite a while loop as following snippet 125 | var=0 126 | while IFS= read -r -d '' file; do 127 | echo "${file}" 128 | var=1 129 | done < <(find . -print0) 130 | echo "${var}" 131 | 132 | # ref: https://unix.stackexchange.com/questions/9496 133 | # https://askubuntu.com/questions/678915 134 | 135 | ``grep`` after find 136 | ------------------- 137 | 138 | .. code-block:: bash 139 | 140 | $ find ker -type f -exec grep -rni "test" {} \+ 141 | 142 | # or 143 | 144 | $ find ker -type f -exec grep -rni "test" {} \; 145 | -------------------------------------------------------------------------------- /docs/notes/bash_os.rst: -------------------------------------------------------------------------------- 1 | =========================== 2 | Operating System cheatsheet 3 | =========================== 4 | 5 | .. contents:: Table of Contents 6 | :backlinks: none 7 | 8 | Get Number of CPUs 9 | ------------------ 10 | 11 | .. code-block:: bash 12 | 13 | # linux 14 | nproc --all 15 | 16 | # max 17 | sysctl -n hw.logicalcpu 18 | -------------------------------------------------------------------------------- /docs/notes/bash_re.rst: -------------------------------------------------------------------------------- 1 | ================================== 2 | Bash Regular Expression Cheatsheet 3 | ================================== 4 | 5 | .. contents:: Table of Contents 6 | :backlinks: none 7 | 8 | ``grep`` vs ``grep -E`` 9 | ----------------------- 10 | 11 | The difference between grep and grep -E is that grep uses basic regular 12 | expressions while grep -E uses extended regular expressions. In basic 13 | regular expressions, the characters "?", "+", "{", "|", "(",")" lose their 14 | special meaning; instead, use "?", "+", "{", "|", "(", ")". 15 | 16 | 17 | .. code-block:: bash 18 | 19 | $ echo "987-123-4567" | grep "^[0-9]\{3\}-[0-9]\{3\}-[0-9]\{4\}$" 20 | $ echo "987-123-4567" | grep -E "^[0-9]{3}-[0-9]{3}-[0-9]{4}$" 21 | 22 | 23 | 24 | `tr` Substitutes Strings 25 | ------------------------ 26 | 27 | 28 | .. code-block:: bash 29 | 30 | # tr substitutes white spaces to newline 31 | $ echo "a b c" | tr "[:space:]+" "\n" 32 | a 33 | b 34 | c 35 | 36 | # tr spueeze multiple spaces 37 | $ echo "a b c" | tr -s " " 38 | a b c 39 | 40 | `uniq` Filters out Repeated Lines 41 | --------------------------------- 42 | 43 | .. code-block:: bash 44 | 45 | $ echo "a a b b c" | tr " " "\n" | sort | uniq 46 | a 47 | b 48 | c 49 | 50 | # display count 51 | $ echo "a a b b a c" | tr " " "\n" | sort | uniq -c 52 | 3 a 53 | 2 b 54 | 1 c 55 | 56 | Note that ``uniq`` only filters out lines continuously. However, if characters 57 | are equal but they does not appear continually, ``uniq`` does not squeeze them. 58 | Therefore, a programmer needs to use ``sort`` to categorizes lines before 59 | ``uniq``. 60 | 61 | .. code-block:: bash 62 | 63 | $ echo "a a b b a c" | tr " " "\n" | uniq 64 | a 65 | b 66 | a 67 | c 68 | 69 | ``sort`` lines 70 | -------------- 71 | 72 | .. code-block:: bash 73 | 74 | # sort by lines 75 | $ echo "b a c d" | tr " " "\n" | sort 76 | 77 | # sort by lines reversely 78 | $ echo "b a c d" | tr " " "\n" | sort -r 79 | 80 | # sort by a field 81 | $ echo "b a b c d" | tr " " "\n" | sort | uniq -c | sort -k1 82 | -------------------------------------------------------------------------------- /docs/notes/c_concurrency.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | C Concurrency cheatsheet 3 | ======================== 4 | 5 | .. contents:: Table of Contents 6 | :backlinks: none 7 | 8 | How to write a UNIX daemon 9 | -------------------------- 10 | 11 | .. code-block:: c 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | int main(int argc, char *argv[]) 20 | { 21 | int ret = -1; 22 | pid_t pid; 23 | 24 | /* become daemon */ 25 | 26 | pid = fork(); 27 | if (-1 == pid) { 28 | printf("Fork get error\n"); 29 | goto Error; 30 | } else if (pid != 0) { 31 | ret = 0; 32 | goto Error; 33 | } 34 | /* Change the file mode mask */ 35 | umask(0); 36 | 37 | /* set sid */ 38 | if (-1 == setsid()) { 39 | printf("set sid failed\n"); 40 | goto Error; 41 | } 42 | /* chdir to root "/" */ 43 | if (-1 == chdir("/")) { 44 | printf("chdir(\"/\") failed\n"); 45 | goto Error; 46 | } 47 | /* close stdin, stdout, stderr */ 48 | close(STDIN_FILENO); 49 | close(STDOUT_FILENO); 50 | close(STDERR_FILENO); 51 | 52 | /* Do some task here */ 53 | while (1) { sleep(3); syslog(LOG_ERR, "Hello"); } 54 | 55 | ret = 0; 56 | Error: 57 | return ret; 58 | } 59 | 60 | Using ``daemon(nochdir, noclose)`` 61 | ---------------------------------- 62 | 63 | .. code-block:: c 64 | 65 | #include 66 | #include 67 | #include 68 | 69 | int main(int argc, char *argv[]) 70 | { 71 | int ret = -1; 72 | /* make process as a daemon */ 73 | if (-1 == daemon(0, 0)) { 74 | syslog(LOG_ERR, "create a daemon get error"); 75 | goto Error; 76 | } 77 | /* do the daemon task */ 78 | while(1) { sleep(3); syslog(LOG_ERR, "Hello"); } 79 | ret = 0; 80 | Error: 81 | return ret; 82 | } 83 | -------------------------------------------------------------------------------- /docs/notes/c_macro.rst: -------------------------------------------------------------------------------- 1 | ================== 2 | C Macro cheatsheet 3 | ================== 4 | 5 | .. contents:: Table of Contents 6 | :backlinks: none 7 | 8 | Predefined Macros 9 | ------------------ 10 | 11 | ============ ================================================ 12 | Macro descriptions 13 | ============ ================================================ 14 | __FILE__ current file name 15 | __DATE__ current compile date in "MMM DD YYYY"" format. 16 | __TIME__ current compile time in "HH:MM:SS" format. 17 | __LINE__ current line number 18 | __func__ current function name 19 | ============ ================================================ 20 | 21 | .. code-block:: c 22 | 23 | #include 24 | 25 | int main(int argc, char *argv[]) 26 | { 27 | int ret = -1; 28 | 29 | printf("__FILE__: %s\n" 30 | "__DATE__: %s\n" 31 | "__TIME__: %s\n" 32 | "__LINE__: %d\n" 33 | "__func__: %s\n", 34 | __FILE__, __DATE__, __TIME__, __LINE__, __func__); 35 | 36 | ret = 0; 37 | return ret; 38 | } 39 | 40 | output: 41 | 42 | .. code-block:: bash 43 | 44 | $ cc -g -Wall -o test test.c 45 | $ ./test 46 | __FILE__: test.c 47 | __DATE__: Sep 28 2016 48 | __TIME__: 10:01:59 49 | __LINE__: 16 50 | __func__: main 51 | 52 | 53 | ``DEBUG`` switch 54 | ------------------ 55 | 56 | .. code-block:: c 57 | 58 | #include 59 | 60 | int main(int argc, char *argv[]) 61 | { 62 | int ret = -1; 63 | 64 | #ifdef DEBUG 65 | printf("debug version\n"); 66 | #else 67 | printf("release version\n"); 68 | #endif 69 | 70 | ret = 0; 71 | return ret; 72 | } 73 | 74 | output: 75 | 76 | .. code-block:: bash 77 | 78 | $ cc -g -Wall -o test test.c 79 | $ ./test 80 | release version 81 | $ cc -g -Wall -DDEBUG -o test test.c 82 | $ ./test 83 | debug version 84 | 85 | 86 | ARRAYSIZE 87 | ---------- 88 | 89 | .. code-block:: c 90 | 91 | #include 92 | 93 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 94 | 95 | /* 96 | * Entry point 97 | */ 98 | int main(int argc, char *argv[]) 99 | { 100 | int ret = -1; 101 | char *pszArr[] = {"Hello", "World", NULL}; 102 | 103 | printf("array size: %lu\n", ARRAY_SIZE(pszArr)); 104 | ret = 0; 105 | return ret; 106 | } 107 | 108 | output: 109 | 110 | .. code-block:: bash 111 | 112 | $ cc -g -Wall -o test test.c 113 | $ ./test 114 | array size: 3 115 | 116 | 117 | FOREACH 118 | -------- 119 | 120 | .. code-block:: c 121 | 122 | #include 123 | 124 | #define FOREACH(item, arr) \ 125 | for (item=arr; *item; item++) 126 | 127 | /* 128 | * Entry point 129 | */ 130 | int main(int argc, char *argv[]) 131 | { 132 | int ret = -1; 133 | char *pszArr[] = {"Hello", "World", NULL}; 134 | char **str = NULL; 135 | 136 | FOREACH (str, pszArr) { 137 | printf("%s ", *str); 138 | } 139 | printf("\n"); 140 | 141 | ret = 0; 142 | return ret; 143 | } 144 | 145 | output: 146 | 147 | .. code-block:: bash 148 | 149 | $ cc -g -Wall -o test test.c 150 | $ ./test 151 | Hello World 152 | 153 | 154 | ALLOC_STRUCT 155 | ------------- 156 | 157 | .. code-block:: c 158 | 159 | #include 160 | #include 161 | #include 162 | #include 163 | 164 | #define ALLOC_STRUCT(s) ((s *) malloc(sizeof(s))) 165 | #define EXPECT_NOT_NULL(i, ...) \ 166 | if (i == NULL) { __VA_ARGS__ } 167 | #define EXPECT_ALLOC_SUCCESS(i, fmt, ...) \ 168 | EXPECT_NOT_NULL(i, printf(fmt, ##__VA_ARGS__); goto End;) 169 | 170 | typedef struct _foo { 171 | int hello; 172 | int world; 173 | } foo; 174 | 175 | int main(int argc, char *argv[]) 176 | { 177 | int ret = -1; 178 | foo *f = NULL; 179 | f = ALLOC_STRUCT(foo); 180 | EXPECT_ALLOC_SUCCESS(f, "err: %s", strerror(errno)); 181 | printf("alloc foo success\n"); 182 | ret = 0; 183 | End: 184 | return ret; 185 | } 186 | 187 | output: 188 | 189 | .. code-block:: bash 190 | 191 | $ gcc -g -Wall -o test test.c 192 | $ ./test 193 | alloc foo success 194 | 195 | 196 | lambda 197 | ------- 198 | 199 | .. code-block:: c 200 | 201 | #define lambda(return_type, ...) \ 202 | __extension__ \ 203 | ({ \ 204 | return_type __fn__ __VA_ARGS__ \ 205 | __fn__; \ 206 | }) 207 | 208 | /* 209 | * Entry point 210 | */ 211 | int main(int argc, char *argv[]) 212 | { 213 | int ret = -1; 214 | int (*max) (int, int) = 215 | lambda (int, (int x, int y) { return x > y ? x : y; }); 216 | 217 | printf("lambda: %d\n", max(2,3)); 218 | 219 | ret = 0; 220 | return ret; 221 | } 222 | 223 | output: 224 | 225 | .. code-block:: bash 226 | 227 | $ gcc -g -Wall -o test test.c 228 | $ ./test 229 | lambda: 3 230 | 231 | 232 | EXPECT_* 233 | ----------- 234 | 235 | .. code-block:: c 236 | 237 | #include [19/1840] 238 | #include 239 | #include 240 | #include 241 | #include 242 | #include 243 | 244 | #define EXPECT_TRUE(i, ...) \ 245 | if (i != 1) { __VA_ARGS__ } 246 | 247 | #define EXPECT_FALSE(i, ...) \ 248 | if (i != 0) { __VA_ARGS__ } 249 | 250 | #define EXPECT_EQ(i, e, ...) \ 251 | if (i != e) { __VA_ARGS__ } 252 | 253 | #define EXPECT_NEQ(i, e, ...) \ 254 | if (i == e) { __VA_ARGS__ } 255 | 256 | #define EXPECT_LT(i, e, ...) \ 257 | if (i >= e) { __VA_ARGS__ } 258 | 259 | #define EXPECT_LE(i, e, ...) \ 260 | if (i > e) { __VA_ARGS__ } 261 | 262 | #define EXPECT_GT(i, e, ...) \ 263 | if (i <= e) { __VA_ARGS__ } 264 | 265 | #define EXPECT_GE(i, e, ...) \ 266 | if (i < e) { __VA_ARGS__ } 267 | 268 | #define EXPECT_SUCCESS(ret, fmt, ...) \ 269 | EXPECT_GT(ret, 0, \ 270 | printf(fmt, ##__VA_ARGS__); \ 271 | goto End; \ 272 | ) 273 | 274 | /* 275 | * Entry point 276 | */ 277 | int main(int argc, char *argv[]) 278 | { 279 | int ret = -1; 280 | 281 | EXPECT_TRUE(1); 282 | EXPECT_FALSE(0); 283 | EXPECT_LT(1, 0, printf("check less then fail\n");); 284 | EXPECT_GT(0, 1, printf("check great then fail\n");); 285 | EXPECT_SUCCESS(ret, "ret = %d\n", ret); 286 | ret = 0; 287 | End: 288 | return ret; 289 | } 290 | 291 | output: 292 | 293 | .. code-block:: bash 294 | 295 | $ cc -g -Wall -o checkerr checkerr.c 296 | $ ./checkerr 297 | check less then fail 298 | check great then fail 299 | ret = -1 300 | 301 | 302 | Get struct member `GET_FIELD_PTR` 303 | ---------------------------------- 304 | 305 | .. code-block:: c 306 | 307 | #include 308 | 309 | #define _GET_FIELD_OFFSET(s, field ) \ 310 | ((short)(long)(&((s *)NULL)->field)) 311 | 312 | #define _GET_FIELD_PTR(ps, offset) \ 313 | ((void *)(((char *)ps) + (offset))) 314 | 315 | #define GET_FIELD_PTR(s, ps, field) \ 316 | _GET_FIELD_PTR(ps, _GET_FIELD_OFFSET(s, field)) 317 | 318 | typedef struct _foo { 319 | char name[16]; 320 | int age; 321 | int gender; 322 | } foo; 323 | 324 | /* 325 | * Entry point 326 | */ 327 | int main(int argc, char *argv[]) 328 | { 329 | int ret = -1; 330 | char *name = NULL; 331 | int *age = NULL, *gender = NULL; 332 | foo f = {.name="c", .age=44, .gender=0}; 333 | 334 | name = GET_FIELD_PTR(foo, &f, name); 335 | age = GET_FIELD_PTR(foo, &f, age); 336 | gender = GET_FIELD_PTR(foo, &f, gender); 337 | 338 | printf("name: %s\n" 339 | "age: %d\n" 340 | "gender: %d\n", name, *age, *gender); 341 | 342 | ret = 0; 343 | return ret; 344 | } 345 | 346 | output: 347 | 348 | .. code-block:: bash 349 | 350 | $ cc -g -Wall -o test test.c 351 | $ ./test 352 | name: c 353 | age: 44 354 | gender: 0 355 | 356 | 357 | define ``__attribute__ ((*))`` 358 | -------------------------------- 359 | 360 | .. code-block:: c 361 | 362 | #if __GNUC__ >= 3 363 | #undef inline 364 | #define inline inline __attribute__ ((always_inline)) 365 | #define __noinline __attribute__ ((noinline)) 366 | #define __pure __attribute__ ((pure)) 367 | #define __const __attribute__ ((const)) 368 | #define __noreturn __attribute__ ((noreturn)) 369 | #define __malloc __attribute__ ((malloc)) 370 | #define __must_check __attribute__ ((warn_unused_result)) 371 | #define __deprecated __attribute__ ((deprecated)) 372 | #define __used __attribute__ ((used)) 373 | #define __unused __attribute__ ((unused)) 374 | #define __packed __attribute__ ((packed)) 375 | #define __align(x) __attribute__ ((aligned, (x))) 376 | #define __align_max __attribute__ ((aligned)) 377 | #define likely(x) __builtin_expect (!!(x), 1) 378 | #define unlikely(x) __builtin_expect (!!(x), 0) 379 | #else 380 | #undef inline 381 | #define __noinline /* no noinline */ 382 | #define __pure /* no pure */ 383 | #define __const /* no const */ 384 | #define __noreturn /* no noreturn */ 385 | #define __malloc /* no malloc */ 386 | #define __must_check /* no warn_unused_result */ 387 | #define __deprecated /* no deprecated */ 388 | #define __used /* no used */ 389 | #define __unused /* no unused */ 390 | #define __packed /* no packed */ 391 | #define __align(x) /* no aligned */ 392 | #define __align_max /* no align_max */ 393 | #define likely(x) (x) 394 | #define unlikely(x) (x) 395 | #endif 396 | -------------------------------------------------------------------------------- /docs/notes/c_signal.rst: -------------------------------------------------------------------------------- 1 | ============================= 2 | C signal operation cheatsheet 3 | ============================= 4 | 5 | .. contents:: Table of Contents 6 | :backlinks: none 7 | 8 | Print signal expression 9 | ----------------------- 10 | 11 | .. code-block:: c 12 | 13 | #include 14 | #include 15 | 16 | #define ARRAYLEN(arr) sizeof(arr) / sizeof((arr)[0]) 17 | 18 | static int signo_arr[] = { 19 | SIGABRT , SIGALRM , SIGBUS, 20 | SIGCHLD , SIGCONT , SIGFPE, 21 | SIGHUP , SIGILL , SIGINT, 22 | SIGIO , SIGKILL , SIGPIPE, 23 | SIGPROF , SIGQUIT , SIGSEGV, 24 | SIGSYS , SIGTERM , SIGTRAP, 25 | SIGTSTP , SIGTTIN , SIGTTOU, 26 | SIGURG , SIGVTALRM, SIGUSR1, 27 | SIGUSR2 , SIGXCPU , SIGXFSZ 28 | }; 29 | 30 | int main(int argc, char *argv[]) 31 | { 32 | int i = 0; 33 | int signo = -1; 34 | char *msg = "SIGNAL"; 35 | 36 | for (i=0; i < ARRAYLEN(signo_arr); i++) { 37 | signo = signo_arr[i]; 38 | printf("Signal[%d]: %s\n", signo, sys_siglist[signo]); 39 | } 40 | 41 | return 0; 42 | } 43 | 44 | output: 45 | 46 | .. code-block:: console 47 | 48 | $ ./a.out 49 | Signal[6]: Abort trap 50 | Signal[14]: Alarm clock 51 | Signal[10]: Bus error 52 | Signal[20]: Child exited 53 | Signal[19]: Continued 54 | Signal[8]: Floating point exception 55 | Signal[1]: Hangup 56 | Signal[4]: Illegal instruction 57 | Signal[2]: Interrupt 58 | Signal[23]: I/O possible 59 | Signal[9]: Killed 60 | Signal[13]: Broken pipe 61 | Signal[27]: Profiling timer expired 62 | Signal[3]: Quit 63 | Signal[11]: Segmentation fault 64 | Signal[12]: Bad system call 65 | Signal[15]: Terminated 66 | Signal[5]: Trace/BPT trap 67 | Signal[18]: Suspended 68 | Signal[21]: Stopped (tty input) 69 | Signal[22]: Stopped (tty output) 70 | Signal[16]: Urgent I/O condition 71 | Signal[26]: Virtual timer expired 72 | Signal[30]: User defined signal 1 73 | Signal[31]: User defined signal 2 74 | Signal[24]: Cputime limit exceeded 75 | Signal[25]: Filesize limit exceeded 76 | 77 | 78 | Basic signal event handler 79 | -------------------------- 80 | 81 | .. code-block:: c 82 | 83 | #include 84 | #include 85 | #include 86 | #include 87 | #include 88 | #include 89 | 90 | /** singal handler prototype : 91 | * 92 | * type void (*sighandler_t) (int) 93 | */ 94 | 95 | void sig_handler(int signo) 96 | { 97 | printf("[%d] Get signal: %s\n", getpid(), strsignal(signo)); 98 | } 99 | 100 | int main(int argc, char *argv[]) 101 | { 102 | int ret = -1; 103 | 104 | /* overwrite default signal handler */ 105 | if (SIG_ERR == signal(SIGHUP, sig_handler)) { 106 | printf("Get error: %s\n", strerror(errno)); 107 | goto Error; 108 | } 109 | if (SIG_ERR == signal(SIGINT, sig_handler)) { 110 | printf("Get error: %s\n", strerror(errno)); 111 | goto Error; 112 | } 113 | if (SIG_ERR == signal(SIGALRM, sig_handler)) { 114 | printf("Get error: %s\n", strerror(errno)); 115 | goto Error; 116 | } 117 | /* ignore signal */ 118 | if (SIG_ERR == signal(SIGUSR1, SIG_IGN)) { 119 | printf("Get error: %s\n", strerror(errno)); 120 | goto Error; 121 | } 122 | while(1) { sleep(3); } 123 | ret = 0; 124 | Error: 125 | return ret; 126 | } 127 | 128 | output: 129 | 130 | .. code-block:: console 131 | 132 | $ ./a.out 133 | ^C[54652] Get signal: Interrupt: 2 134 | [54652] Get signal: Hangup: 1 135 | [54652] Get signal: Alarm clock: 14 136 | 137 | 138 | A pthread signal handler 139 | ------------------------ 140 | 141 | .. code-block:: c 142 | 143 | #include 144 | #include 145 | #include 146 | #include 147 | #include 148 | #include 149 | 150 | static void *sig_thread(void *arg) 151 | { 152 | sigset_t *set = (sigset_t *)arg; 153 | int err = -1, signo = -1; 154 | 155 | for(;;) { 156 | if(0 != (err = sigwait(set, &signo))) { 157 | printf("sigwait error\n"); 158 | goto Error; 159 | } 160 | printf("Get signal[%d]: %s\n", 161 | signo, sys_siglist[signo]); 162 | } 163 | Error: 164 | return; 165 | } 166 | 167 | int main(int argc, char *argv[]) 168 | { 169 | pthread_t thread; 170 | sigset_t sig_set; 171 | int err = -1; 172 | 173 | sigemptyset(&sig_set); 174 | sigaddset(&sig_set, SIGQUIT); 175 | sigaddset(&sig_set, SIGUSR1); 176 | /* set signal handler thread sigmask */ 177 | err = pthread_sigmask(SIG_BLOCK, &sig_set, NULL) 178 | if(0 != err) { 179 | printf("set pthread_sigmask error\n"); 180 | goto Error; 181 | } 182 | /* create signal thread */ 183 | err = pthread_create(&thread, NULL, 184 | &sig_thread, (void *)&sig_set)) 185 | if (0 != err) { 186 | printf("create pthread error\n"); 187 | goto Error; 188 | } 189 | 190 | pause(); 191 | Error: 192 | return err; 193 | } 194 | 195 | output: 196 | 197 | .. code-block:: console 198 | 199 | $ ./a.out & 200 | [1] 21258 201 | $ kill -USR1 %1 202 | Get signal[10]: User defined signal 1 203 | $ kill -QUIT %1 204 | Get signal[3]: Quit 205 | $ kill -TERM %1 206 | [1]+ Terminated ./a.out 207 | 208 | 209 | Check child process alive 210 | ------------------------- 211 | 212 | .. code-block:: c 213 | 214 | #include 215 | #include 216 | #include 217 | 218 | void handler(int signo) 219 | { 220 | pid_t pid = getpid(); 221 | printf("[%i] Got signal[%d]: %s\n", 222 | pid, signo, sys_siglist[signo]); 223 | } 224 | 225 | int main(int argc, char *argv[]) 226 | { 227 | int ret = -1; 228 | pid_t pid = -1; 229 | 230 | pid = fork(); 231 | signal(SIGCHLD, handler); 232 | if (pid < 0) { 233 | printf("Fork failed\n"); 234 | goto Error; 235 | } else if (pid == 0) { 236 | /* child */ 237 | printf("Child[%i]\n", getpid()); 238 | sleep(3); 239 | } else { 240 | printf("Parent[%i]\n", getpid()); 241 | pause(); 242 | } 243 | ret = 0; 244 | Error: 245 | return ret; 246 | } 247 | 248 | .. code-block:: console 249 | 250 | $ ./a.out 251 | Parent[59113] 252 | Child[59114] 253 | [59113] Got signal[20]: Child exited 254 | 255 | 256 | Basic sigaction usage 257 | --------------------- 258 | 259 | .. code-block:: c 260 | 261 | #include 262 | #include 263 | #include 264 | #include 265 | 266 | void handler(int signo) 267 | { 268 | printf("Get Signal: %s\n",sys_siglist[signo]); 269 | } 270 | 271 | int main(int argc, char *argv[]) 272 | { 273 | pid_t pid = -1; 274 | struct sigaction new_sa = {0}; 275 | struct sigaction old_sa = {0}; 276 | 277 | new_sa.sa_handler = handler; 278 | sigemptyset(&new_sa.sa_mask); 279 | new_sa.sa_flags = 0; 280 | 281 | pid = getpid(); 282 | printf("Process PID: %i\n", pid); 283 | /* if signal not ignore, overwrite its handler */ 284 | sigaction(SIGINT, NULL, &old_sa); 285 | if (old_sa.sa_handler != SIG_IGN) { 286 | sigaction(SIGINT, &new_sa, NULL); 287 | } 288 | 289 | sigaction(SIGHUP, NULL, &old_sa); 290 | if (old_sa.sa_handler != SIG_IGN) { 291 | sigaction(SIGHUP, &new_sa, NULL); 292 | } 293 | while (1) { sleep(3); } 294 | return 0; 295 | } 296 | 297 | output: 298 | 299 | .. code-block:: console 300 | 301 | # bash 1 302 | kill -1 57140 303 | kill -2 57140 304 | 305 | # bash 2 306 | $ ./a.out 307 | Process PID: 57140 308 | Get Signal: Hangup 309 | Get Signal: Interrupt 310 | 311 | 312 | Block & Unblock signal 313 | ---------------------- 314 | 315 | .. code-block:: c 316 | 317 | #include 318 | #include 319 | #include 320 | #include 321 | #include 322 | #include 323 | 324 | static sigjmp_buf jmpbuf; 325 | 326 | void handler(int signo) 327 | { 328 | printf("Get signal[%d]: %s\n", signo, sys_siglist[signo]); 329 | if (SIGUSR1 == signo) { 330 | siglongjmp(jmpbuf, 1); 331 | } 332 | } 333 | 334 | int main(int argc, char *argv[]) 335 | { 336 | int ret = -1; 337 | sigset_t new_mask, old_mask; 338 | 339 | sigemptyset(&new_mask); 340 | sigaddset(&new_mask, SIGHUP); 341 | 342 | if (SIG_ERR == signal(SIGHUP, handler)) { 343 | printf("Set signal get %s error", strerror(errno)); 344 | goto Error; 345 | } 346 | if (SIG_ERR == signal(SIGALRM, handler)) { 347 | printf("Set signal get %s error", strerror(errno)); 348 | goto Error; 349 | } 350 | if (SIG_ERR == signal(SIGUSR1, handler)) { 351 | printf("Set signal get %s error", strerror(errno)); 352 | goto Error; 353 | } 354 | /* block SIGHUP */ 355 | if (sigsetjmp(jmpbuf, 1)) { 356 | /* unblock SIGHUP */ 357 | sigprocmask(SIG_UNBLOCK, &new_mask, &old_mask); 358 | } else { 359 | /* block SIGHUP */ 360 | sigprocmask(SIG_BLOCK, &new_mask, &old_mask); 361 | } 362 | while (1) sleep(3); 363 | ret = 0; 364 | Error: 365 | return ret; 366 | } 367 | 368 | output: 369 | 370 | .. code-block:: console 371 | 372 | $ kill -HUP %1 373 | $ kill -ALRM %1 374 | Get signal[14]: Alarm clock 375 | $ kill -USR1 %1 376 | Get signal[10]: User defined signal 1 377 | Get signal[1]: Hangup 378 | -------------------------------------------------------------------------------- /docs/notes/cmake_basic.rst: -------------------------------------------------------------------------------- 1 | ===== 2 | cmake 3 | ===== 4 | 5 | .. contents:: Table of Contents 6 | :backlinks: none 7 | 8 | Minimal CMakeLists.txt 9 | ---------------------- 10 | 11 | .. code-block:: cmake 12 | 13 | cmake_minimum_required(VERSION 3.10) 14 | set(CMAKE_CXX_STANDARD 17) 15 | set(CMAKE_CXX_STANDARD_REQUIRED True) 16 | project(example) 17 | add_executable(a.out a.cpp b.cpp) 18 | 19 | 20 | Wildcard Sourse Files 21 | --------------------- 22 | 23 | .. code-block:: cmake 24 | 25 | cmake_minimum_required(VERSION 3.10) 26 | set(CMAKE_CXX_STANDARD 17) 27 | set(CMAKE_CXX_STANDARD_REQUIRED True) 28 | file(GLOB src "*.cpp") 29 | 30 | project(example) 31 | add_executable(a.out ${src}) 32 | 33 | Set CXXFLAGS 34 | ------------ 35 | 36 | .. code-block:: cmake 37 | 38 | cmake_minimum_required(VERSION 3.10) 39 | set(CMAKE_CXX_STANDARD 17) 40 | set(CMAKE_CXX_STANDARD_REQUIRED True) 41 | file(GLOB src "*.cc") 42 | 43 | project(example) 44 | set(CMAKE_CXX_FLAGS "-Wall -Werror -O3") 45 | add_executable(a.out ${src}) 46 | 47 | .. code-block:: cmake 48 | 49 | cmake_minimum_required(VERSION 3.10) 50 | set(CMAKE_CXX_STANDARD 17) 51 | set(CMAKE_CXX_STANDARD_REQUIRED True) 52 | file(GLOB src "*.cc") 53 | 54 | project(example) 55 | add_executable(a.out ${src}) 56 | target_compile_options(a.out PRIVATE -Werror) 57 | 58 | Set CXXFLAGS with Build Type 59 | ---------------------------- 60 | 61 | .. code-block:: cmake 62 | 63 | # common 64 | set(CMAKE_CXX_FLAGS "-Wall -Werror -O3") 65 | # debug 66 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} -g") 67 | # release 68 | set(CMAKE_C_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -O3 -pedantic") 69 | 70 | Build Debug/Release 71 | ------------------- 72 | 73 | .. code-block:: bash 74 | 75 | $ cmake -DCMAKE_BUILD_TYPE=Release ../ 76 | $ cmake -DCMAKE_BUILD_TYPE=Debug ../ 77 | 78 | Build with Type 79 | --------------- 80 | 81 | .. code-block:: cmake 82 | 83 | cmake_minimum_required(VERSION 3.10) 84 | set(CMAKE_CXX_STANDARD 17) 85 | set(CMAKE_CXX_STANDARD_REQUIRED True) 86 | project(example) 87 | add_executable(a.out a.cc) 88 | 89 | if(CMAKE_BUILD_TYPE STREQUAL "Debug") 90 | target_compile_options(a.out PRIVATE -g -O0 -Wall) 91 | else() 92 | target_compile_options(a.out PRIVATE -O3 -Wall -Werror) 93 | endif() 94 | 95 | Instead of checking ``CMAKE_BUILD_TYPE``, modern CMake prefers to use *generator 96 | expressions* to examine conditions. 97 | 98 | .. code-block:: cmake 99 | 100 | cmake_minimum_required(VERSION 3.10) 101 | set(CMAKE_CXX_STANDARD 17) 102 | set(CMAKE_CXX_STANDARD_REQUIRED True) 103 | project(example) 104 | add_executable(a.out a.cc) 105 | target_compile_options(a.out PRIVATE 106 | $, -g -O0 -Wall, -O3 -Wall -Werror> 107 | ) 108 | 109 | Version File 110 | ------------ 111 | 112 | .. code-block:: cmake 113 | 114 | cmake_minimum_required(VERSION 3.10) 115 | set(CMAKE_CXX_STANDARD 17) 116 | set(CMAKE_CXX_STANDARD_REQUIRED True) 117 | file(GLOB src "*.cpp") 118 | 119 | project(example VERSION 1.0) 120 | configure_file(version.h.in version.h) 121 | 122 | add_executable(a.out ${src}) 123 | target_include_directories(a.out PUBLIC "${PROJECT_BINARY_DIR}") 124 | 125 | version.h.in 126 | 127 | .. code-block:: cpp 128 | 129 | #pragma once 130 | 131 | #define VERSION_MAJOR @example_VERSION_MAJOR@ 132 | #define VERSION_MINOR @example_VERSION_MINOR@ 133 | 134 | Build/Link a static library 135 | --------------------------- 136 | 137 | .. code-block:: cmake 138 | 139 | cmake_minimum_required(VERSION 3.10) 140 | set(CMAKE_CXX_STANDARD 17) 141 | set(CMAKE_CXX_STANDARD_REQUIRED True) 142 | file(GLOB src "*.cpp") 143 | 144 | project(example VERSION 1.0) 145 | configure_file(version.h.in version.h) 146 | 147 | add_executable(a.out ${src}) 148 | add_library(b b.cpp) 149 | target_link_libraries(a.out PUBLIC b) 150 | target_include_directories(a.out PUBLIC "${PROJECT_BINARY_DIR}") 151 | 152 | Build/Link a shared library 153 | --------------------------- 154 | 155 | .. code-block:: cmake 156 | 157 | 158 | cmake_minimum_required(VERSION 3.10) 159 | set(CMAKE_CXX_STANDARD 17) 160 | set(CMAKE_CXX_STANDARD_REQUIRED True) 161 | file(GLOB src "*.cpp") 162 | 163 | project(example VERSION 1.0) 164 | configure_file(version.h.in version.h) 165 | 166 | add_executable(a.out ${src}) 167 | add_library(b SHARED b.cpp) 168 | target_link_libraries(a.out PUBLIC b) 169 | target_include_directories(a.out PUBLIC "${PROJECT_BINARY_DIR}") 170 | 171 | Subdirectory 172 | ------------ 173 | 174 | subdirectory fib/ 175 | 176 | .. code-block:: cmake 177 | 178 | cmake_minimum_required(VERSION 3.10) 179 | set(CMAKE_CXX_STANDARD 17) 180 | set(CMAKE_CXX_STANDARD_REQUIRED True) 181 | file(GLOB src "*.cpp") 182 | add_library(b SHARED b.cpp) 183 | target_include_directories(b PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}") 184 | 185 | project dir 186 | 187 | .. code-block:: cmake 188 | 189 | cmake_minimum_required(VERSION 3.10) 190 | set(CMAKE_CXX_STANDARD 17) 191 | set(CMAKE_CXX_STANDARD_REQUIRED True) 192 | file(GLOB src "*.cpp") 193 | 194 | project(example VERSION 1.0) 195 | configure_file(version.h.in version.h) 196 | 197 | add_executable(a.out ${src}) 198 | add_subdirectory(fib) 199 | target_link_libraries(a.out PUBLIC b) 200 | target_include_directories(a.out PUBLIC 201 | "${PROJECT_BINARY_DIR}" 202 | "${PROJECT_BINARY_DIR/fib}" 203 | ) 204 | 205 | PUBLIC & PRIVATE 206 | ---------------- 207 | 208 | - PUBLIC - only affect the current target, not dependencies 209 | - INTERFACE - only needed for dependencies 210 | 211 | .. code-block:: cmake 212 | 213 | cmake_minimum_required(VERSION 3.10) 214 | 215 | project(example) 216 | set(CMAKE_CXX_STANDARD 17) 217 | set(CMAKE_CXX_STANDARD_REQUIRED True) 218 | find_package(Boost) 219 | 220 | add_executable(a.out a.cpp) 221 | add_library(b STATIC b.cpp b.h) 222 | 223 | target_include_directories(a.out PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") 224 | target_include_directories(b PRIVATE "${Boost_INCLUDE_DIR}") 225 | target_link_libraries(a.out INTERFACE b) # link b failed 226 | 227 | Generator Expression 228 | -------------------- 229 | 230 | .. code-block:: cmake 231 | 232 | cmake_minimum_required(VERSION 3.10) 233 | set(CMAKE_CXX_STANDARD 17) 234 | set(CMAKE_CXX_STANDARD_REQUIRED True) 235 | project(example) 236 | 237 | set(target fib) 238 | add_library(${target} src/fib.cc) 239 | target_compile_options(${target} PRIVATE -Wall -Werror -Wextra) 240 | target_include_directories(${target} 241 | PUBLIC 242 | $ 243 | $ 244 | PRIVATE 245 | ${CMAKE_CURRENT_SOURCE_DIR}/src 246 | ) 247 | 248 | Install 249 | ------- 250 | 251 | .. code-block:: cmake 252 | 253 | cmake_minimum_required(VERSION 3.10) 254 | project(a) 255 | add_library(b_static STATIC b.cc) 256 | add_library(b_shared SHARED b.cc) 257 | add_executable(a a.cc b.cc) 258 | 259 | include(GNUInstallDirs) 260 | set(INSTALL_TARGETS a b_static b_shared) 261 | install(TARGETS ${INSTALL_TARGETS} 262 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 263 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 264 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 265 | ) 266 | install(FILES b.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 267 | 268 | Run a command at configure time 269 | ------------------------------- 270 | 271 | .. code-block:: cmake 272 | 273 | execute_process( 274 | COMMAND git submodule update --init --recursive 275 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 276 | RESULT_VARIABLE GIT_SUBMOD_RESULT 277 | ) 278 | 279 | Option 280 | ------ 281 | 282 | .. code-block:: cmake 283 | 284 | # $ make -p build 285 | # $ cd build 286 | # $ cmake -DBUILD_TEST=ON ../ 287 | 288 | option(BUILD_TEST "Build test" OFF) 289 | if (BUILD_TEST) 290 | message("Build tests.") 291 | else() 292 | message("Ignore tests.") 293 | endif() 294 | 295 | Alias a Library 296 | --------------- 297 | 298 | When a ``CMakeLists.txt`` export Foo in namespace ``Foo::``, it also need to 299 | create an alias ``Foo::Foo``. 300 | 301 | .. code-block:: cmake 302 | 303 | add_library(Foo::Foo ALIAS Foo) 304 | -------------------------------------------------------------------------------- /docs/notes/cmake_external.rst: -------------------------------------------------------------------------------- 1 | ================ 2 | External Project 3 | ================ 4 | 5 | .. contents:: Table of Contents 6 | :backlinks: none 7 | 8 | 9 | Add an External Project 10 | ----------------------- 11 | 12 | .. code-block:: cmake 13 | 14 | include (ExternalProject) 15 | ExternalProject_Add(fmt 16 | GIT_REPOSITORY "https://github.com/fmtlib/fmt.git" 17 | GIT_TAG "7.1.3" 18 | GIT_CONFIG advice.detachedHead=false 19 | PREFIX "${CMAKE_BINARY_DIR}/fmt" 20 | CMAKE_CACHE_ARGS 21 | "-DFMT_INSTALL:BOOL=ON" 22 | "-DFMT_DOC:BOOL=OFF" 23 | "-DFMT_TEST:BOOL=OFF" 24 | "-DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_BINARY_DIR}" 25 | ) 26 | 27 | Download Only 28 | ------------- 29 | 30 | .. code-block:: cmake 31 | 32 | include (ExternalProject) 33 | ExternalProject_Add(fmt 34 | GIT_REPOSITORY "https://github.com/fmtlib/fmt.git" 35 | GIT_TAG "7.1.3" 36 | GIT_CONFIG advice.detachedHead=false 37 | PREFIX "${CMAKE_BINARY_DIR}/fmt" 38 | CONFIGURE_COMMAND "" 39 | BUILD_COMMAND "" 40 | INSTALL_COMMAND "" 41 | ) 42 | 43 | Build via GNU Autotool 44 | ---------------------- 45 | 46 | .. code-block:: cmake 47 | 48 | include (ExternalProject) 49 | ExternalProject_Add(curl 50 | URL "https://github.com/curl/curl/releases/download/curl-7_74_0/curl-7.74.0.tar.gz" 51 | URL_MD5 "45f468aa42c4af027c4c6ddba58267f0" # md5sum curl_7.74.0.tar.gz 52 | BUILD_IN_SOURCE 1 53 | SOURCE_DIR ${CMAKE_BINARY_DIR}/curl 54 | CONFIGURE_COMMAND ${CMAKE_BINARY_DIR}/curl/configure --prefix=${CMAKE_BINARY_DIR} 55 | BUILD_COMMAND make 56 | INSTALL_COMMAND make install 57 | ) 58 | -------------------------------------------------------------------------------- /docs/notes/cmake_package.rst: -------------------------------------------------------------------------------- 1 | ======= 2 | Package 3 | ======= 4 | 5 | .. contents:: Table of Contents 6 | :backlinks: none 7 | 8 | Support ``find_package`` 9 | ------------------------ 10 | 11 | .. code-block:: cmake 12 | 13 | # fib 14 | # ├── CMakeLists.txt 15 | # ├── cmake 16 | # │   └── FibConfig.cmake 17 | # ├── include 18 | # │   └── fib 19 | # │   └── fib.h 20 | # └── src 21 | # └── fib.cc 22 | 23 | cmake_minimum_required(VERSION 3.10) 24 | set(CMAKE_CXX_STANDARD 17) 25 | set(CMAKE_CXX_STANDARD_REQUIRED True) 26 | project(example) 27 | 28 | set(target fib) 29 | add_library(${target} src/fib.cc) 30 | target_compile_options(${target} PRIVATE -Wall -Werror -Wextra) 31 | target_include_directories(${target} 32 | PUBLIC 33 | $ 34 | $ 35 | PRIVATE 36 | ${CMAKE_CURRENT_SOURCE_DIR}/src 37 | ) 38 | 39 | include(GNUInstallDirs) 40 | install(TARGETS ${target} EXPORT FibTargets 41 | LIBRARY DESTINATION lib 42 | ARCHIVE DESTINATION lib 43 | RUNTIME DESTINATION bin 44 | INCLUDES DESTINATION include 45 | ) 46 | 47 | install(DIRECTORY include/fib 48 | DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} 49 | ) 50 | install(EXPORT FibTargets 51 | FILE FibTargets.cmake 52 | NAMESPACE Fib:: 53 | DESTINATION lib/cmake/Fib 54 | ) 55 | include(CMakePackageConfigHelpers) 56 | write_basic_package_version_file("FibConfigVersion.cmake" 57 | VERSION 1.0.0 58 | COMPATIBILITY SameMajorVersion 59 | ) 60 | install(FILES "cmake/FibConfig.cmake" 61 | "${PROJECT_BINARY_DIR}/FibConfigVersion.cmake" 62 | DESTINATION lib/cmake/Fib 63 | ) 64 | 65 | cmake/FibConfig.cmake 66 | 67 | .. code-block:: cmake 68 | 69 | include(CMakeFindDependencyMacro) 70 | find_dependency(Boost) 71 | include("${CMAKE_CURRENT_LIST_DIR}/FibTargets.cmake") 72 | 73 | CPack 74 | ----- 75 | 76 | .. code-block:: cmake 77 | 78 | # $ cd build 79 | # $ cmake .. 80 | # $ make -j 2 81 | # $ cpack -G TGZ . 82 | 83 | cmake_minimum_required(VERSION 3.10) 84 | set(CMAKE_CXX_STANDARD 17) 85 | set(CMAKE_CXX_STANDARD_REQUIRED True) 86 | project(a) 87 | 88 | add_executable(a a.cc) 89 | add_library(b b.cc) 90 | target_link_libraries(a PRIVATE b) 91 | include(GNUInstallDirs) 92 | install(TARGETS a b 93 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 94 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 95 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 96 | ) 97 | install(FILES b.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 98 | 99 | set(CPACK_GENERATOR "ZIP;TGZ") 100 | SET(CPACK_DEBIAN_PACKAGE_MAINTAINER "crazyguitar") 101 | include(CPack) 102 | -------------------------------------------------------------------------------- /docs/notes/cpp_algorithm.rst: -------------------------------------------------------------------------------- 1 | ========================== 2 | Data Structure & Algorithm 3 | ========================== 4 | 5 | .. contents:: Table of Contents 6 | :backlinks: none 7 | 8 | Remove elements by conditions 9 | ----------------------------- 10 | 11 | .. code-block:: cpp 12 | 13 | #include 14 | 15 | int main(int argc, char *argv[]) 16 | { 17 | std::vector v{1, 2, 3, 4, 5, 6}; 18 | for (auto it = v.begin(); it != v.end();) { 19 | if (*it > 3) { 20 | it = v.erase(it); 21 | } else { 22 | ++it; 23 | } 24 | } 25 | } 26 | 27 | Remove keys by conditions 28 | ------------------------- 29 | 30 | .. code-block:: cpp 31 | 32 | #include 33 | #include 34 | 35 | int main(int argc, char *argv[]) 36 | { 37 | std::map m{{1, "1"}, {2, "2"}, {3, "3"}}; 38 | for (auto it = m.begin(); it != m.end();) { 39 | if (it->first > 1) { 40 | it = m.erase(it); 41 | } else { 42 | ++it; 43 | } 44 | } 45 | } 46 | 47 | ``std::map`` sort by key 48 | ------------------------ 49 | 50 | .. code-block:: cpp 51 | 52 | // g++ -std=c++17 -Wall -Werror -O3 a.cc 53 | 54 | #include 55 | #include 56 | 57 | int main(int argc, char *argv[]) 58 | { 59 | // ascending 60 | std::map> a{{3, 3}, {2, 2}, {1, 1}}; 61 | // descending 62 | std::map> d{{3, 3}, {2, 2}, {1, 1}}; 63 | 64 | auto print = [](auto &m) { 65 | for (const auto &[k, v] : m) { 66 | std::cout << k << " " << v << "\n"; 67 | } 68 | }; 69 | print(a); // 1, 2, 3 70 | print(d); // 3, 2, 1 71 | } 72 | 73 | ``std::map`` with object as key 74 | ------------------------------- 75 | 76 | .. code-block:: cpp 77 | 78 | #include 79 | #include 80 | 81 | struct Data { 82 | int a; 83 | int b; 84 | }; 85 | 86 | int main(int argc, char *argv[]) 87 | { 88 | auto cmp = [](auto &x, auto &y) { return x.a < y.b; }; 89 | std::map m{cmp}; 90 | m[Data{1, 2}] = 1; 91 | m[Data{3, 4}] = 4; 92 | 93 | for (const auto &[k, v] : m) { 94 | std::cout << k.a << " " << k.b << " " << v << "\n"; 95 | } 96 | } 97 | 98 | ``std::foreach`` 99 | ---------------- 100 | 101 | .. code-block:: cpp 102 | 103 | #include 104 | #include 105 | #include 106 | 107 | int main(int argc, char *argv[]) 108 | { 109 | std::vector v{1, 2, 3}; 110 | std::for_each(v.begin(), v.end(), [](auto &i) { i = i * 2; }); 111 | std::for_each(v.begin(), v.end(), [](auto &i) { std::cout << i << "\n"; }); 112 | } 113 | 114 | ``std::find`` 115 | ------------- 116 | 117 | ``std::find`` returns an iterator to the first element in an array like object. 118 | 119 | .. code-block:: cpp 120 | 121 | #include 122 | #include 123 | #include 124 | 125 | int main(int argc, char *argv[]) 126 | { 127 | std::vector v{1, 2, 3}; 128 | 129 | // complexity O(n) 130 | auto it = std::find(v.begin(), v.end(), 2); 131 | std::cout << *it << "\n"; 132 | } 133 | 134 | ``std::find_if`` & ``std::find_if_not`` 135 | --------------------------------------- 136 | 137 | .. code-block:: cpp 138 | 139 | #include 140 | #include 141 | #include 142 | 143 | int main(int argc, char *argv[]) 144 | { 145 | std::vector v{1, 2, 3}; 146 | auto x = find_if(v.begin(), v.end(), [](auto &i) { return i == 2; }); 147 | std::cout << *x << "\n"; 148 | 149 | auto y = find_if_not(v.begin(), v.end(), [](auto &i) { return i == 2; }); 150 | std::cout << *y << "\n"; 151 | } 152 | 153 | ``std::transform`` 154 | ------------------ 155 | 156 | .. code-block:: cpp 157 | 158 | #include 159 | #include 160 | #include 161 | 162 | int main(int argc, char *argv[]) 163 | { 164 | std::string s = "Hello World"; 165 | 166 | // transform elements in place 167 | std::transform(s.begin(), s.end(), s.begin(), ::toupper); 168 | std::cout << s << "\n"; 169 | 170 | // transform elements and store in another object 171 | std::string o(s.size(), 0); 172 | std::transform(s.begin(), s.end(), o.begin(), ::tolower); 173 | std::cout << o << "\n"; 174 | } 175 | 176 | 177 | ``std::generate`` 178 | ----------------- 179 | 180 | .. code-block:: cpp 181 | 182 | #include 183 | #include 184 | #include 185 | #include 186 | 187 | int main(int argc, char *argv[]) 188 | { 189 | std::random_device dev; 190 | std::mt19937 rng(dev()); 191 | std::uniform_int_distribution dist(1,10); 192 | 193 | // generate a sequence 194 | std::vector v(5); 195 | std::generate(v.begin(), v.end(), [&] { return dist(rng); }); 196 | for (const auto &i : v) { 197 | std::cout << i << std::endl; 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /docs/notes/cpp_basic.rst: -------------------------------------------------------------------------------- 1 | ================ 2 | Basic cheatsheet 3 | ================ 4 | 5 | .. contents:: Table of Contents 6 | :backlinks: none 7 | 8 | C Linkage 9 | --------- 10 | 11 | .. code-block:: cpp 12 | 13 | #include 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | int fib(int n) { 20 | int a = 0, b = 1; 21 | for (int i = 0; i < n; ++i) { 22 | auto x = b; 23 | b = a + b; 24 | a = x; 25 | } 26 | return a; 27 | } 28 | 29 | #ifdef __cplusplus 30 | } 31 | #endif 32 | 33 | int main(int argc, char *argv[]) { 34 | std::cout << fib(10) << "\n"; 35 | } 36 | // $ g++ -std=c++17 -Wall -Werror -O3 a.cc 37 | // $ nm -g a.out | grep fib 38 | // 0000000100003a58 T _fib 39 | 40 | .. code-block:: cpp 41 | 42 | #include 43 | 44 | int fib(int n) { 45 | int a = 0, b = 1; 46 | for (int i = 0; i < n; ++i) { 47 | auto x = b; 48 | b = a + b; 49 | a = x; 50 | } 51 | return a; 52 | } 53 | 54 | int main(int argc, char *argv[]) { 55 | std::cout << fib(10) << "\n"; 56 | } 57 | // $ g++ -std=c++17 -Wall -Werror -O3 a.cc 58 | // nm -g a.out | grep fib 59 | // 0000000100003a58 T __Z3fibi 60 | 61 | .. code-block:: cpp 62 | 63 | #include 64 | #include 65 | 66 | __BEGIN_DECLS 67 | 68 | int fib(int n) { 69 | int a = 0, b = 1; 70 | for (int i = 0; i < n; ++i) { 71 | auto x = b; 72 | b = a + b; 73 | a = x; 74 | } 75 | return a; 76 | } 77 | 78 | __END_DECLS 79 | 80 | int main(int argc, char *argv[]) { 81 | std::cout << fib(10) << "\n"; 82 | } 83 | // $ g++ -std=c++17 -Wall -Werror -O3 a.cc 84 | // $ nm -g a.out | grep fib 85 | // 0000000100003a58 T _fib 86 | 87 | Uniform Initialization 88 | ---------------------- 89 | 90 | *Uniform Initialization* is also called braced initialization, which unifies 91 | constructing an object using a brace. However, there are some pitfalls in using 92 | syntax. For example, the compiler prefers to call ``std::initializer_list`` to 93 | initialize an object even with a matched constructor. The following snippet shows 94 | that ``x{10, 5.0}`` will call ``Foo(std::initializer_list)`` to 95 | construct an object event though ``Foo(int a, double b)`` is the more suitable one. 96 | 97 | .. code-block:: cpp 98 | 99 | #include 100 | #include 101 | 102 | class Foo { 103 | public: 104 | Foo(int a, double b) { 105 | std::cout << "without initializer_list\n"; 106 | } 107 | 108 | Foo(std::initializer_list il) { 109 | std::cout << "with initializer_list\n"; 110 | } 111 | }; 112 | 113 | int main(int argc, char *argv[]) { 114 | Foo x{10, 5.0}; 115 | // output: with initializer_list 116 | } 117 | 118 | 119 | Moreover, *uniform initialization* does not support narrowing conversion. 120 | Therefore, the following snippet will compile errors because ``int`` and 121 | ``double`` need to do narrowing conversion ``bool``. 122 | 123 | .. code-block:: cpp 124 | 125 | #include 126 | #include 127 | 128 | class Foo { 129 | public: 130 | Foo(int a, double b) { 131 | std::cout << "without initializer_list\n"; 132 | } 133 | 134 | // compile error 135 | Foo(std::initializer_list il) { 136 | std::cout << "with initializer_list\n"; 137 | } 138 | }; 139 | 140 | int main(int argc, char *argv[]) { 141 | Foo x{10, 5.0}; 142 | } 143 | 144 | Note that when types cannot convert, the compiler does not use ``std::initializer_list`` 145 | to initialize an object. For example, ``int`` and ``double`` cannot convert to 146 | ``std::string``, so the compiler will call ``Foo(int, double)`` to create an object. 147 | 148 | .. code-block:: cpp 149 | 150 | #include 151 | #include 152 | #include 153 | 154 | class Foo { 155 | public: 156 | Foo(int a, double b) { 157 | std::cout << "without initializer_list\n"; 158 | } 159 | 160 | Foo(std::initializer_list il) { 161 | std::cout << "with initializer_list\n"; 162 | } 163 | }; 164 | 165 | int main(int argc, char *argv[]) { 166 | Foo x{10, 5.0}; 167 | // output: without initializer_list 168 | } 169 | 170 | 171 | Negative Array index 172 | -------------------- 173 | 174 | .. code-block:: cpp 175 | 176 | #include 177 | 178 | int main(int argc, char *argv[]) { 179 | // note: arr[i] = *(a + i) 180 | int arr[] = {1, 2, 3}; 181 | int *ptr = &arr[1]; 182 | 183 | std::cout << ptr[-1] << "\n"; 184 | std::cout << ptr[0] << "\n"; 185 | std::cout << ptr[1] << "\n"; 186 | } 187 | 188 | 189 | Reference 190 | --------- 191 | 192 | .. code-block:: cpp 193 | 194 | #include 195 | 196 | template 197 | void f(T& param) noexcept {} 198 | // param is a reference 199 | 200 | int main(int argc, char *argv[]) 201 | { 202 | int x = 123; 203 | const int cx = x; 204 | const int &rx = x; 205 | 206 | f(x); // type(param) = int& 207 | f(cx); // type(param) = const int& 208 | f(rx); // type(param) = const int& 209 | 210 | return 0; 211 | } 212 | 213 | 214 | .. code-block:: cpp 215 | 216 | #include 217 | 218 | template 219 | void f(T&& param) noexcept {} 220 | // param is a universal reference 221 | 222 | int main(int argc, char *argv[]) 223 | { 224 | int x = 123; 225 | const int cx = x; 226 | const int &rx = x; 227 | 228 | f(x); // x is a lvalue, type(param) = int& 229 | f(cx); // cx is a lvalue, type(param) = const int& 230 | f(rx); // rx is a lvalue, type(param) = const int& 231 | f(12); // 12 is a rvalue, type(param) = int&& 232 | 233 | return 0; 234 | } 235 | 236 | .. code-block:: cpp 237 | 238 | #include 239 | 240 | template 241 | void f(T param) noexcept {} 242 | // param is neither a pointer nor a reference. 243 | 244 | int main(int argc, char *argv[]) 245 | { 246 | int x = 123; 247 | const int cx = x; 248 | const int &rx = x; 249 | 250 | f(x); // type(param) = int 251 | f(cx); // type(param) = int 252 | f(rx); // type(param) = int 253 | f(12); // type(param) = int 254 | 255 | return 0; 256 | } 257 | 258 | auto 259 | ---- 260 | 261 | .. code-block:: cpp 262 | 263 | auto x = 123; // type(x) = int 264 | const auto cx = x; // type(cx) = const int 265 | const auto &rx = x; // type(rx) = const int& 266 | 267 | auto &&urx = x; // type(urx) = int& 268 | auto &&urcx = cx; // type(urcx) = const int& 269 | auto &&urrx = rx; // type(urrx) = const int& 270 | auto &&urrv = 12; // type(urrv) = int&& 271 | 272 | decltype(auto) 273 | -------------- 274 | 275 | The ``decltype(auto)`` is similar to auto, which decudes type via compiler. 276 | However, ``decltype(auto)`` preserves types reference and cv-qualifiers, while 277 | auto does not. 278 | 279 | .. code-block:: cpp 280 | 281 | #include 282 | 283 | int main(int argc, char *argv[]) { 284 | int x; 285 | const int cx = x; 286 | const int &crx = x; 287 | int &&z = 0; 288 | 289 | // decltype(auto) preserve cv-qualifiers 290 | decltype(auto) y1 = crx; 291 | static_assert(std::is_same::value == 1); 292 | // auto does not preserve cv-qualifiers 293 | auto y2 = crx; 294 | static_assert(std::is_same::value == 1); 295 | // decltype(auto) preserve rvalue reference 296 | decltype(auto) z1 = std::move(z); 297 | static_assert(std::is_same::value == 1); 298 | } 299 | 300 | ``decltype(auto)`` is especially useful for writing a generic function's return. 301 | 302 | .. code-block:: cpp 303 | 304 | #include 305 | 306 | auto foo(const int &x) { 307 | return x; 308 | } 309 | 310 | decltype(auto) bar(const int &x) { 311 | return x; 312 | } 313 | 314 | int main(int argc, char *argv[]) { 315 | static_assert(std::is_same::value == 1); 316 | static_assert(std::is_same::value == 1); 317 | } 318 | 319 | Reference Collapsing 320 | -------------------- 321 | 322 | .. code-block:: cpp 323 | 324 | // T& & -> T& 325 | // T& && -> T& 326 | // T&& & -> T& 327 | // T&& && -> T&& 328 | // note & always wins. that is T& && == T&& & == T& & == T& 329 | // only T&& && == T&& 330 | 331 | Perfect Forwarding 332 | ------------------ 333 | 334 | .. code-block:: cpp 335 | 336 | #include 337 | #include 338 | #include 339 | 340 | template 341 | T&& forward(typename std::remove_reference::type& t) noexcept { 342 | std::cout << std::is_lvalue_reference::value << std::endl; 343 | return static_cast(t); 344 | } 345 | 346 | template 347 | T&& forward(typename std::remove_reference::type&& t) noexcept { 348 | static_assert( 349 | !std::is_lvalue_reference::value, 350 | "Can not forward an rvalue as an lvalue." 351 | ); 352 | std::cout << std::is_lvalue_reference::value << std::endl; 353 | return static_cast(t); 354 | } 355 | 356 | int main (int argc, char *argv[]) 357 | { 358 | int a = 0; 359 | forward(a); // forward lvalues to rvalues 360 | forward(9527); // forward rvalues to rvalues 361 | return 0; 362 | } 363 | 364 | .. code-block:: cpp 365 | 366 | #include 367 | #include 368 | #include 369 | 370 | template 371 | void wrapper(T &&a, Func fn) { 372 | fn(std::forward(a)); // forward lvalue to lvalues or rvalues 373 | } 374 | 375 | struct Foo { 376 | Foo(int a1, int a2) : a(a1), b(a2), ret(0) {} 377 | int a, b, ret; 378 | }; 379 | 380 | int main (int argc, char *argv[]) 381 | { 382 | Foo foo{1, 2}; 383 | Foo &bar = foo; 384 | Foo &&baz = Foo(5, 6); 385 | 386 | wrapper(foo, [](Foo foo) { 387 | foo.ret = foo.a + foo.b; 388 | return foo.ret; 389 | }); 390 | std::cout << foo.ret << std::endl; 391 | 392 | wrapper(bar, [](Foo &foo) { 393 | foo.ret = foo.a - foo.b; 394 | return foo.ret; 395 | }); 396 | std::cout << bar.ret << std::endl; 397 | 398 | // move an rvalue to lvalue 399 | wrapper(std::move(baz), [](Foo &&foo) { 400 | foo.ret = foo.a * foo.b; 401 | return foo.ret; 402 | }); 403 | std::cout << baz.ret << std::endl; 404 | return 0; 405 | } 406 | 407 | Bit Manipulation 408 | ---------------- 409 | 410 | .. code-block:: cpp 411 | 412 | #include 413 | #include 414 | 415 | int main(int argc, char *argv[]) { 416 | std::bitset<4> b{8}; 417 | 418 | // show number of bits set 419 | std::cout << b.count() << "\n"; 420 | // compare with int 421 | std::cout << (b == 8) << "\n"; 422 | } 423 | 424 | Using ``std::addressof`` 425 | ------------------------ 426 | 427 | Because C++ allows the overloading of ``operator &``, accessing the address of 428 | an reference will result in infinite recusion. Therefore, when it is necessary 429 | to access the address of reference, it would be safer by using ``std::addressof``. 430 | 431 | .. code-block:: cpp 432 | 433 | #include 434 | #include 435 | 436 | struct A { 437 | int x; 438 | }; 439 | 440 | const A *operator &(const A& a) { 441 | // return &a; <- infinite recursion 442 | return std::addressof(a); 443 | } 444 | 445 | int main(int argc, char *argv[]) { 446 | A a; 447 | std::cout << &a << "\n"; 448 | } 449 | -------------------------------------------------------------------------------- /docs/notes/cpp_casting.rst: -------------------------------------------------------------------------------- 1 | ======= 2 | Casting 3 | ======= 4 | 5 | .. contents:: Table of Contents 6 | :backlinks: none 7 | 8 | C Style Casting 9 | --------------- 10 | 11 | .. code-block:: cpp 12 | 13 | #include 14 | #include 15 | 16 | int main(int argc, char *argv[]) { 17 | double x = M_PI; 18 | int xx = (int) x; 19 | std::cout << xx << "\n"; 20 | 21 | long z = LONG_MAX; 22 | int zz = (int) z; // dangerous. overflow 23 | std::cout << zz << "\n"; 24 | } 25 | 26 | Const Casting 27 | ------------- 28 | 29 | .. code-block:: cpp 30 | 31 | #include 32 | 33 | void f(const int &x) { 34 | const_cast(x) = 0; 35 | } 36 | 37 | int main(int argc, char *argv[]) { 38 | int x = 123; 39 | f(x); 40 | std::cout << x << "\n"; 41 | } 42 | 43 | Reinterpret Casting 44 | ------------------- 45 | 46 | .. code-block:: cpp 47 | 48 | #include 49 | #include 50 | 51 | struct A { int x; int y; }; 52 | 53 | int main(int argc, char *argv[]) { 54 | A a{1, 2}; 55 | 56 | // convert a struct to a byte array 57 | char *buf = reinterpret_cast(&a); 58 | for (int i = 0; i < sizeof(A); ++i) { 59 | std::cout << static_cast(buf[i]) << " "; 60 | } 61 | // output: 1 0 0 0 2 0 0 0 62 | } 63 | 64 | Static Casting 65 | -------------- 66 | 67 | .. code-block:: cpp 68 | 69 | #include 70 | #include 71 | 72 | struct A { 73 | virtual void f() { std::cout << __func__ << "\n"; } 74 | virtual ~A() = default; 75 | }; 76 | 77 | struct B : public A {; 78 | B(int *x) : x_{x} {} 79 | int *g() { return x_; } 80 | int *x_; 81 | }; 82 | 83 | int main(int argc, char *argv[]) { 84 | auto a = std::make_unique(); 85 | // downcasting may be dangerous 86 | auto b = static_cast(a.get()); 87 | auto x = b->g(); 88 | std::cout << *x << "\n"; 89 | } 90 | 91 | Dynamic Casting 92 | --------------- 93 | 94 | .. code-block:: cpp 95 | 96 | #include 97 | #include 98 | 99 | struct A { 100 | virtual void f() { std::cout << __func__ << "\n"; } 101 | }; 102 | 103 | struct B : public A { 104 | void f() override { std::cout << __PRETTY_FUNCTION__ << "\n"; } 105 | }; 106 | 107 | int main(int argc, char *argv[]) { 108 | auto a = std::make_unique(); 109 | auto b = std::make_unique(); 110 | 111 | // downcast 112 | auto bb = dynamic_cast(a.get()); 113 | std::cout << "Is dynamic_cast(*a) to *b success? " << !!bb << "\n"; 114 | // output: Is dynamic_cast(*a) to *b success? 0 115 | 116 | // upcast 117 | auto aa = dynamic_cast(b.get()); 118 | std::cout << "Is dynamic_cast(*b) to *a success? " << !!aa << "\n"; 119 | // output: Is dynamic_cast(*a) to *b success? 1 120 | } 121 | 122 | -------------------------------------------------------------------------------- /docs/notes/cpp_constexpr.rst: -------------------------------------------------------------------------------- 1 | ========= 2 | constexpr 3 | ========= 4 | 5 | .. contents:: Table of Contents 6 | :backlinks: none 7 | 8 | constexpr Function 9 | ------------------ 10 | 11 | .. code-block:: cpp 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | class Timer { 18 | public: 19 | inline void start() { 20 | start_ = std::chrono::system_clock::now(); 21 | } 22 | 23 | inline void end() { 24 | end_ = std::chrono::system_clock::now(); 25 | } 26 | 27 | inline void out() { 28 | std::chrono::duration d = end_ - start_; 29 | std::cout << "Time cost: " << d.count() << "\n"; 30 | } 31 | private: 32 | std::chrono::time_point start_; 33 | std::chrono::time_point end_; 34 | }; 35 | 36 | constexpr long fib(long n) { 37 | return (n < 2) ? 1 : fib(n-1) + fib(n-2); 38 | } 39 | 40 | int main() { 41 | Timer timer; 42 | long n = 40; 43 | 44 | timer.start(); 45 | int r1 = fib(n); 46 | timer.end(); 47 | timer.out(); 48 | 49 | timer.start(); 50 | constexpr long r2 = fib(40); 51 | timer.end(); 52 | timer.out(); 53 | 54 | return 0; 55 | } 56 | 57 | output: 58 | 59 | .. code-block:: bash 60 | 61 | $ g++ -std=c++14 -g -O3 a.cpp 62 | $ ./a.out 63 | Time cost: 0.268229 64 | Time cost: 8e-06 65 | 66 | Compare to Metaprogramming 67 | -------------------------- 68 | 69 | .. code-block:: cpp 70 | 71 | #include 72 | #include 73 | #include "timer.h" 74 | 75 | template 76 | struct Fib { 77 | static long const v = Fib::v + Fib::v; 78 | }; 79 | 80 | template <> 81 | struct Fib<0> { 82 | static long const v = 1; 83 | }; 84 | 85 | template <> 86 | struct Fib<1> { 87 | static long const v = 1; 88 | }; 89 | 90 | constexpr long fib(long n) 91 | { 92 | return (n < 2) ? 1 : fib(n-1) + fib(n-2); 93 | } 94 | 95 | int main() { 96 | 97 | Timer timer; 98 | 99 | timer.start(); 100 | constexpr long r1 = Fib<40>::v; 101 | timer.end(); 102 | timer.out(); 103 | 104 | timer.start(); 105 | constexpr long r2 = fib(40); 106 | timer.end(); 107 | timer.out(); 108 | 109 | return 0; 110 | } 111 | 112 | output: 113 | 114 | .. code-block:: bash 115 | 116 | g++ -std=c++14 -g -O3 a.cpp 117 | $ ./a.out 118 | Time cost: 9.7e-06 119 | Time cost: 9.2e-06 120 | 121 | After C++14, constexpr functions can 122 | 123 | - invoke other constexpr functions. 124 | - have variables with a constant expression. 125 | - include conditional expressions or loops. 126 | - be implicit inline. 127 | - not have static or thread_local data. 128 | -------------------------------------------------------------------------------- /docs/notes/cpp_constructor.rst: -------------------------------------------------------------------------------- 1 | =========== 2 | constructor 3 | =========== 4 | 5 | .. contents:: Table of Contents 6 | :backlinks: none 7 | 8 | Constructors 9 | ------------ 10 | 11 | .. code-block:: cpp 12 | 13 | #include 14 | #include 15 | 16 | class C { 17 | public: 18 | // constructor 19 | C(int x) : x_(x) {} 20 | 21 | // default constructor 22 | C() = default; 23 | 24 | // copy constructor 25 | C(const C &other) : C(other.x_) { 26 | std::cout << "copy constructor\n"; 27 | } 28 | 29 | // copy assignment 30 | C &operator=(const C &other) { 31 | std::cout << "copy assignment\n"; 32 | x_ = other.x_; 33 | return *this; 34 | } 35 | 36 | // move constructor 37 | C(C &&other) : x_(std::move(other.x_)) { 38 | std::cout << "move constructor\n"; 39 | other.x_ = 0; 40 | } 41 | 42 | // move assignment 43 | C &operator=(C &&other) { 44 | std::cout << "move assignment\n"; 45 | x_ = std::move(other.x_); 46 | return *this; 47 | } 48 | 49 | private: 50 | int x_; 51 | }; 52 | 53 | int main(int argc, char *argv[]) { 54 | C c1; // call default constructor 55 | C c2(1); // call constructor 56 | C c3 = C(2); // call constructor 57 | C c4(c2); // call copy constructor 58 | C c5(std::move(C(2))); // call move constructor 59 | C c6 = c1; // call copy constructor 60 | C c7 = std::move(C(2)); // call move constructor 61 | C c8 = std::move(c3); // call move constructor 62 | 63 | C c9; 64 | C c10; 65 | 66 | c9 = c2; // call copy assignment 67 | c10 = std::move(c4); // call move assignment 68 | c10 = C(2); // call move assignment 69 | } 70 | 71 | Rule of three 72 | ------------- 73 | 74 | .. code-block:: cpp 75 | 76 | #include 77 | #include 78 | #include 79 | #include 80 | 81 | class RuleOfThree { 82 | public: 83 | RuleOfThree(const char *s, size_t n) 84 | : cstr_(new char[n]) 85 | , n_(n) { 86 | memcpy(cstr_, s, n); 87 | } 88 | 89 | // if we have a user-defined destructor 90 | ~RuleOfThree() { delete[] cstr_; } 91 | // we need one a user-defined copy constructor 92 | RuleOfThree(const RuleOfThree &other) 93 | : RuleOfThree(other.cstr_, other.n_) {} 94 | // and user-defined copy assignment 95 | RuleOfThree &operator=(const RuleOfThree &other) { 96 | if (this == std::addressof(other)) { 97 | return *this; 98 | } 99 | delete[] cstr_; 100 | n_ = other.n_; 101 | cstr_ = new char[other.n_]; 102 | memcpy(cstr_, other.cstr_, n_); 103 | return *this; 104 | } 105 | 106 | friend std::ostream &operator<<(std::ostream &os, const RuleOfThree &); 107 | 108 | private: 109 | char *cstr_; 110 | size_t n_; 111 | }; 112 | 113 | std::ostream &operator<<(std::ostream &os, const RuleOfThree &r) { 114 | return os << r.cstr_; 115 | } 116 | 117 | int main(int argc, char *argv[]) { 118 | std::string s = "Rule of three"; 119 | RuleOfThree r3(s.c_str(), s.size() + 1); 120 | std::cout << r3 << "\n"; 121 | } 122 | 123 | Rule of five 124 | ------------ 125 | 126 | .. code-block:: cpp 127 | 128 | #include 129 | #include 130 | #include 131 | #include 132 | #include 133 | 134 | class RuleOfFive { 135 | public: 136 | RuleOfFive(const char *s, int n) : cstr_(new char[n]) { 137 | std::memcpy(cstr_, s, n); 138 | } 139 | 140 | // if there is a user-defined destructor including default or delete 141 | ~RuleOfFive() { delete[] cstr_; } 142 | // a user-defined copy constructor 143 | RuleOfFive(const RuleOfFive &other) 144 | : RuleOfFive(other.cstr_, strlen(other.cstr_) + 1) {} 145 | // a user-defined move constructor 146 | RuleOfFive(RuleOfFive &&other) 147 | : cstr_(std::exchange(other.cstr_, nullptr)) {} 148 | // a user-define copy assignment 149 | RuleOfFive &operator=(const RuleOfFive &other) { 150 | return *this = RuleOfFive(other); 151 | } 152 | // a user-defined move assignment have to declare explicitly. 153 | RuleOfFive &operator=(RuleOfFive &&other) { 154 | std::swap(cstr_, other.cstr_); 155 | return *this; 156 | } 157 | 158 | friend std::ostream &operator<<(std::ostream &os, const RuleOfFive &); 159 | 160 | private: 161 | char *cstr_; 162 | }; 163 | 164 | std::ostream &operator<<(std::ostream &os, const RuleOfFive &r5) { 165 | return os << r5.cstr_; 166 | } 167 | 168 | int main(int argc, char *argv[]) { 169 | std::string s = "Rule of five"; 170 | RuleOfFive r5(s.c_str(), s.size() + 1); 171 | std::cout << r5 << "\n"; 172 | } 173 | 174 | Rule of zero 175 | ------------ 176 | 177 | .. code-block:: cpp 178 | 179 | #include 180 | #include 181 | 182 | class RuleOfZero { 183 | public: 184 | RuleOfZero(const std::string &s) : s_(s) {} 185 | // if we don't have a user-defined destructor, we should not have 186 | // user-defined copy/move constructors or copy/move assignment. 187 | friend std::ostream &operator<<(std::ostream &os, const RuleOfZero &r0); 188 | private: 189 | const std::string s_; 190 | }; 191 | 192 | std::ostream &operator<<(std::ostream &os, const RuleOfZero &r0) { 193 | return os << r0.s_; 194 | } 195 | 196 | int main(int argc, char *argv[]) { 197 | RuleOfZero r0("Rule of zero"); 198 | std::cout << r0 << "\n"; 199 | } 200 | 201 | Note that a polymorphic class should supress public copy/move. 202 | 203 | .. code-block:: cpp 204 | 205 | #include 206 | #include 207 | #include 208 | 209 | // bad 210 | class A { 211 | public: 212 | virtual std::string f() { return "a"; } 213 | }; 214 | 215 | class B : public A { 216 | public: 217 | std::string f() override { return "b"; } 218 | }; 219 | 220 | void func(A &a) { 221 | auto c = a; 222 | std::cout << c.f() << "\n"; 223 | } 224 | 225 | int main(int argc, char *argv[]) { 226 | B b; 227 | func(b); 228 | } 229 | 230 | .. code-block:: cpp 231 | 232 | #include 233 | #include 234 | #include 235 | 236 | class A { 237 | public: 238 | A() = default; 239 | A(const A&) = delete; 240 | A &operator=(const A&) = delete; 241 | virtual std::string f() { return "a"; } 242 | }; 243 | 244 | class B : public A { 245 | public: 246 | std::string f() override { return "b"; } 247 | }; 248 | 249 | void func(A &a) { 250 | auto c = a; // compile error here! 251 | std::cout << c.f() << "\n"; 252 | } 253 | 254 | int main(int argc, char *argv[]) { 255 | B b; 256 | func(b); 257 | } 258 | -------------------------------------------------------------------------------- /docs/notes/cpp_container.rst: -------------------------------------------------------------------------------- 1 | ========= 2 | Container 3 | ========= 4 | 5 | Priority Queue 6 | -------------- 7 | 8 | .. contents:: Table of Contents 9 | :backlinks: none 10 | 11 | Priority Queue 12 | -------------- 13 | 14 | .. code-block:: cpp 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | template 22 | void dump(Q &q) { 23 | while(!q.empty()) { 24 | std::cout << q.top() << " "; 25 | q.pop(); 26 | } 27 | std::cout << "\n"; 28 | } 29 | 30 | void foo() { 31 | std::vector data{1, 5, 2, 1, 3}; 32 | std::priority_queue queue; 33 | for (auto & x : data) { queue.push(x); } 34 | dump(queue); 35 | } 36 | 37 | void bar() { 38 | std::vector data{1, 5, 2, 1, 3}; 39 | std::priority_queue, std::greater> queue; 40 | for (auto & x : data) { queue.push(x); } 41 | dump(queue); 42 | } 43 | 44 | void baz() { 45 | std::vector data{1, 5, 2, 1, 3}; 46 | auto cmp = [](int x, int y) { return x < y; }; 47 | std::priority_queue, decltype(cmp)> queue(cmp); 48 | for (auto & x : data) { queue.push(x); } 49 | dump(queue); 50 | } 51 | 52 | int main(int argc, char *argv[]) { 53 | foo(); 54 | bar(); 55 | baz(); 56 | // 5 3 2 1 1 57 | // 1 1 2 3 5 58 | // 1 1 2 3 5 59 | } 60 | 61 | 62 | Priority queue is useful when a programmer need to merge multiple lists of data 63 | in order. 64 | 65 | .. code-block:: cpp 66 | 67 | #include 68 | #include 69 | #include 70 | 71 | template 72 | void dump(Q &q) { 73 | while(!q.empty()) { 74 | std::cout << q.top() << " "; 75 | q.pop(); 76 | } 77 | std::cout << "\n"; 78 | } 79 | 80 | int main(int argc, char *argv[]) { 81 | std::priority_queue queue; 82 | std::vector x{9, 7, 8}; 83 | std::vector y{0, 5, 3}; 84 | for (auto &e : x) { queue.push(e); } 85 | for (auto &e : y) { queue.push(e); } 86 | dump(queue); 87 | // 9 8 7 5 3 0 88 | } 89 | 90 | Profiling 91 | --------- 92 | 93 | .. code-block:: cpp 94 | 95 | // profile.h 96 | #include 97 | #include 98 | 99 | using milliseconds = std::chrono::milliseconds; 100 | 101 | template 102 | void profile(T &t, F &func) { 103 | const auto start = std::chrono::steady_clock::now(); 104 | func(t); 105 | const auto end = std::chrono::steady_clock::now(); 106 | const auto d = end - start; 107 | const auto mill = std::chrono::duration_cast(d).count(); 108 | std::cout << mill << " ms\n"; 109 | } 110 | 111 | Push Front 112 | `````````` 113 | 114 | .. code-block:: cpp 115 | 116 | // g++ -O3 -std=c++17 -Wall -Werror -I${HDR} a.cpp 117 | 118 | #include 119 | #include 120 | #include 121 | #include 122 | #include "profile.h" 123 | 124 | template 125 | void insert(T &t) { 126 | for (auto i : ranges::views::iota(0, 300000)) { 127 | t.insert(t.begin(), i); 128 | } 129 | } 130 | 131 | int main(int argc, char *argv[]) { 132 | std::vector v; 133 | std::deque q; 134 | std::list l; 135 | profile(v, insert); 136 | profile(q, insert); 137 | profile(l, insert); 138 | } 139 | 140 | .. code-block:: bash 141 | 142 | $ ./a.out 143 | 16045 ms 144 | 1 ms 145 | 6 ms 146 | 147 | 148 | Push Back 149 | ````````` 150 | 151 | .. code-block:: cpp 152 | 153 | #include 154 | #include 155 | #include 156 | #include 157 | #include "profile.h" 158 | 159 | template 160 | void insert(T &t) { 161 | for (auto i : ranges::views::iota(0, 1000000)) { 162 | t.push_back(i); 163 | } 164 | } 165 | 166 | int main(int argc, char *argv[]) { 167 | std::vector v; 168 | std::deque q; 169 | std::list l; 170 | profile(v, insert); 171 | profile(q, insert); 172 | profile(l, insert); 173 | } 174 | 175 | .. code-block:: bash 176 | 177 | ./a.out 178 | 7 ms 179 | 2 ms 180 | 39 ms 181 | 182 | Pop Front 183 | ````````` 184 | 185 | .. code-block:: cpp 186 | 187 | #include 188 | #include 189 | #include 190 | #include 191 | #include "profile.h" 192 | 193 | template 194 | void insert(T &t) { 195 | for (auto i : ranges::views::iota(0, 300000)) { 196 | t.push_back(i); 197 | } 198 | } 199 | 200 | template 201 | void pop_front(T &t) { 202 | while (!t.empty()) { 203 | t.pop_front(); 204 | } 205 | } 206 | 207 | template 208 | void erase(T &v) { 209 | while(!v.empty()) { 210 | v.erase(v.begin()); 211 | } 212 | } 213 | 214 | int main(int argc, char *argv[]) { 215 | std::vector v; 216 | std::deque q; 217 | std::list l; 218 | insert(v); insert(q); insert(l); 219 | profile(v, erase); 220 | profile(q, pop_front); 221 | profile(l, pop_front); 222 | } 223 | 224 | 225 | .. code-block:: bash 226 | 227 | $ ./a.out 228 | 22923 ms 229 | 0 ms 230 | 12 ms 231 | 232 | Pop Back 233 | ```````` 234 | 235 | .. code-block:: cpp 236 | 237 | #include 238 | #include 239 | #include 240 | #include 241 | #include "profile.h" 242 | 243 | template 244 | void insert(T &t) { 245 | for (auto i : ranges::views::iota(0, 1000000)) { 246 | t.push_back(i); 247 | } 248 | } 249 | 250 | template 251 | void pop_back(T &t) { 252 | while (!t.empty()) { 253 | t.pop_back(); 254 | } 255 | } 256 | 257 | int main(int argc, char *argv[]) { 258 | std::vector v; 259 | std::deque q; 260 | std::list l; 261 | insert(v); insert(q); insert(l); 262 | profile(v, pop_back); 263 | profile(q, pop_back); 264 | profile(l, pop_back); 265 | } 266 | 267 | .. code-block:: bash 268 | 269 | $ ./a.out 270 | 0 ms 271 | 0 ms 272 | 30 ms 273 | -------------------------------------------------------------------------------- /docs/notes/cpp_coroutine.rst: -------------------------------------------------------------------------------- 1 | ========= 2 | coroutine 3 | ========= 4 | 5 | .. contents:: Table of Contents 6 | :backlinks: none 7 | 8 | Generator 9 | --------- 10 | 11 | .. code-block:: cpp 12 | 13 | // g++ -O3 -std=c++20 -Wall -Werror co.cc 14 | 15 | #include 16 | #include 17 | 18 | template 19 | class generator { 20 | public: 21 | struct promise_type; 22 | using handle_type = std::coroutine_handle; 23 | handle_type h_; 24 | 25 | struct promise_type { 26 | T value_; 27 | std::exception_ptr exception_; 28 | generator get_return_object() { 29 | return { handle_type::from_promise(*this) }; 30 | } 31 | void unhandled_exception() { exception_ = std::current_exception(); } 32 | void return_void() {} 33 | std::suspend_always initial_suspend() noexcept { return {}; } 34 | std::suspend_always final_suspend() noexcept { return {}; } 35 | std::suspend_always yield_value(T v) noexcept { 36 | value_ = std::move(v); 37 | return {}; 38 | } 39 | }; 40 | 41 | public: 42 | 43 | generator(handle_type h) : h_(h) {} 44 | ~generator() { h_.destroy(); } 45 | explicit operator bool() { 46 | next(); 47 | return !h_.done(); 48 | } 49 | 50 | T operator() () { 51 | next(); 52 | cached_ = false; 53 | return std::move(h_.promise().value_); 54 | } 55 | 56 | private: 57 | bool cached_ = false; 58 | void next() { 59 | if (cached_) { 60 | return; 61 | } 62 | h_(); 63 | if (h_.promise().exception_) { 64 | std::rethrow_exception(h_.promise().exception_); 65 | } 66 | cached_ = true; 67 | } 68 | }; 69 | 70 | generator fib(uint64_t n) { 71 | uint64_t a = 0, b = 1; 72 | for (uint64_t i = 0; i <= n; ++i) { 73 | co_yield a; 74 | uint64_t t = b; 75 | b = a + b; 76 | a = t; 77 | } 78 | } 79 | 80 | int main(int argc, char *argv[]) { 81 | auto g = fib(10); 82 | while (g) { 83 | std::cout << g() << " "; 84 | } 85 | // ./a.out 86 | // 0 1 1 2 3 5 8 13 21 34 55 87 | } 88 | 89 | Boost ASIO Echo Server 90 | ---------------------- 91 | 92 | .. code-block:: cpp 93 | 94 | #include 95 | #include 96 | #include 97 | #include 98 | #include 99 | #include 100 | #include 101 | 102 | using boost::asio::ip::tcp; 103 | using boost::asio::awaitable; 104 | using boost::asio::co_spawn; 105 | using boost::asio::detached; 106 | using boost::asio::use_awaitable; 107 | namespace this_coro = boost::asio::this_coro; 108 | 109 | constexpr uint64_t BUFSIZE = 1024; 110 | 111 | awaitable echo(tcp::socket &socket) { 112 | for (;;) { 113 | char data[BUFSIZE] = {0}; 114 | auto n = co_await socket.async_read_some(boost::asio::buffer(data), use_awaitable); 115 | co_await async_write(socket, boost::asio::buffer(data, n), use_awaitable); 116 | } 117 | } 118 | 119 | awaitable handle(tcp::socket socket) { 120 | try { 121 | co_await echo(socket); 122 | } catch(const std::exception &e) { 123 | std::cerr << e.what(); 124 | } 125 | } 126 | 127 | awaitable listener() { 128 | auto e = co_await this_coro::executor; 129 | tcp::acceptor acceptor(e, {tcp::v4(), 8888}); 130 | for (;;) { 131 | tcp::socket socket = co_await acceptor.async_accept(use_awaitable); 132 | co_spawn(e, handle(std::move(socket)), detached); 133 | } 134 | } 135 | 136 | int main(int argc, char *argv[]) { 137 | boost::asio::io_context io_context; 138 | boost::asio::signal_set signals(io_context, SIGINT, SIGTERM); 139 | signals.async_wait([&](auto, auto){ io_context.stop(); }); 140 | co_spawn(io_context, listener(), detached); 141 | io_context.run(); 142 | } 143 | 144 | .. code-block:: cmake 145 | 146 | # CMakeLists.txt 147 | cmake_minimum_required(VERSION 3.10) 148 | set(target a.out) 149 | set(CMAKE_CXX_STANDARD 20) 150 | set(CMAKE_CXX_STANDARD_REQUIRED True) 151 | project(example) 152 | find_package(Boost) 153 | add_executable(${target} a.cc) 154 | target_include_directories(${target} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") 155 | target_include_directories(${target} PRIVATE "${Boost_INCLUDE_DIR}") 156 | target_link_libraries(${target} ${Boost_LIBRARIES}) 157 | target_link_libraries(${target} INTERFACE Boost::coroutine) 158 | -------------------------------------------------------------------------------- /docs/notes/cpp_forwarding.rst: -------------------------------------------------------------------------------- 1 | ================== 2 | Perfect Forwarding 3 | ================== 4 | 5 | .. contents:: Table of Contents 6 | :backlinks: none 7 | 8 | Perfect forwarding is a way for a programmer to design a generic wrapper 9 | function in their C++ programs. However, few examples show how to use it in a 10 | real scenario. Instead of explaining what a C++ `perfect forwarding` is, this 11 | article tries to collect use cases about using it. 12 | 13 | Decorator Pattern 14 | ----------------- 15 | 16 | .. code-block:: cpp 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | template 23 | auto Decorator(Func &&f, Args&&... args) { 24 | 25 | const auto s = std::chrono::system_clock::now(); 26 | auto ret = f(std::forward(args)...); 27 | const auto e = std::chrono::system_clock::now(); 28 | std::chrono::duration d = e - s; 29 | 30 | std::cout << "Time Cost: " << d.count() << std::endl; 31 | return ret; 32 | } 33 | 34 | long fib(long n) { 35 | return n < 2 ? 1 : fib(n-1) + fib(n-2); 36 | } 37 | 38 | int main() { 39 | Decorator(fib, 35); 40 | return 0; 41 | } 42 | 43 | Profiling 44 | --------- 45 | 46 | .. code-block:: cpp 47 | 48 | #include 49 | #include 50 | #include 51 | 52 | class Timer { 53 | public: 54 | Timer() : s_(std::chrono::system_clock::now()) {} 55 | ~Timer() { 56 | e_ = std::chrono::system_clock::now(); 57 | std::chrono::duration d = e_ - s_; 58 | std::cout << "Time Cost: " << d.count() << std::endl; 59 | } 60 | private: 61 | std::chrono::time_point s_; 62 | std::chrono::time_point e_; 63 | }; 64 | 65 | template 66 | auto Profile(Func f, Args&&... args) { 67 | Timer timer; 68 | return f(std::forward(args)...); 69 | } 70 | 71 | long fib1(long n) { 72 | return (n < 2) ? 1 : fib1(n-1) + fib1(n-2); 73 | } 74 | 75 | template 76 | struct f { 77 | static constexpr long v = f::v + f::v; 78 | }; 79 | 80 | template<> 81 | struct f<0> { 82 | static constexpr long v = 0; 83 | }; 84 | 85 | template<> 86 | struct f<1> { 87 | static constexpr long v = 1; 88 | }; 89 | 90 | int main() { 91 | long ret = -1; 92 | ret = Profile(fib1, 35); 93 | std::cout << ret << std::endl; 94 | 95 | ret = Profile([](){ return f<35>::v; }); 96 | std::cout << ret << std::endl; 97 | return 0; 98 | } 99 | 100 | Factory Pattern 101 | --------------- 102 | 103 | .. code-block:: cpp 104 | 105 | #include 106 | #include 107 | #include 108 | #include 109 | 110 | struct PostgresqlConfig { /* implementation */ }; 111 | struct MysqlConfig { /* implementation */ }; 112 | 113 | template 114 | class Session { 115 | public: 116 | void connect(const std::string url) { 117 | static_cast(this)->connect(url); 118 | } 119 | }; 120 | 121 | class Postgresql : public Session { 122 | private: 123 | PostgresqlConfig config_; 124 | public: 125 | Postgresql(PostgresqlConfig c) : config_(c) {} 126 | 127 | void connect(const std::string url) { 128 | std::cout << "Connecting to Postgresql..." << std::endl; 129 | // connecting 130 | } 131 | }; 132 | 133 | class Mysql : public Session { 134 | private: 135 | MysqlConfig config_; 136 | public: 137 | Mysql(MysqlConfig c) : config_(c) {} 138 | 139 | void connect(const std::string url) { 140 | std::cout << "Connecting to Mysql..." << std::endl; 141 | // connecting 142 | } 143 | }; 144 | 145 | /** 146 | * An example of Perfect Forwarding 147 | */ 148 | template 149 | std::shared_ptr SessionFactory(C&& c) { 150 | return std::make_shared(std::forward(c)); 151 | } 152 | 153 | using PostgresSession = Session; 154 | using MysqlSession = Session; 155 | using PostgresPtr = std::shared_ptr; 156 | using MysqlPtr = std::shared_ptr; 157 | 158 | int main(int argc, char *argv[]) { 159 | 160 | PostgresqlConfig pc; 161 | MysqlConfig mc; 162 | 163 | PostgresPtr ps = SessionFactory(pc); 164 | MysqlPtr ms = SessionFactory(mc); 165 | 166 | ps->connect("postgresql://..."); 167 | ms->connect("mysql://..."); 168 | return 0; 169 | } 170 | -------------------------------------------------------------------------------- /docs/notes/cpp_initialization.rst: -------------------------------------------------------------------------------- 1 | ============== 2 | Initialization 3 | ============== 4 | 5 | .. contents:: Table of Contents 6 | :backlinks: none 7 | 8 | Initializer lists 9 | ----------------- 10 | 11 | .. code-block:: cpp 12 | 13 | #include 14 | #include 15 | 16 | template 17 | decltype(auto) sum(const std::initializer_list &v) { 18 | T s = 0; 19 | for (const auto &i : v) { 20 | s += i; 21 | } 22 | return s; 23 | } 24 | 25 | int main(int argc, char *argv[]) { 26 | sum({1,2,3,4,5}); 27 | } 28 | -------------------------------------------------------------------------------- /docs/notes/cpp_iterator.rst: -------------------------------------------------------------------------------- 1 | ======== 2 | Iterator 3 | ======== 4 | 5 | .. contents:: Table of Contents 6 | :backlinks: none 7 | 8 | Upper Bound 9 | ----------- 10 | 11 | Note that `std::upper_bound(x.begin(), x.end(), val)` finds an element which 12 | is *greater than the val*. However, `std::lower_bound(x.begin(), x.end(), val)`, 13 | finds an element which is *greater or equal to the val*. 14 | 15 | .. code-block:: cpp 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | int main(int argc, char *argv[]) { 22 | std::deque v{1,2,3,4,5,7,10}; 23 | 24 | auto x = 5; 25 | auto pos1 = std::upper_bound(v.begin(), v.end(), x); 26 | std::cout << *pos1 << "\n"; 27 | 28 | auto pos2 = std::lower_bound(v.begin(), v.end(), x); 29 | std::cout << *pos2 << "\n"; 30 | 31 | // 7 32 | // 5 33 | } 34 | 35 | Insert an Element into a Sorted List 36 | ------------------------------------ 37 | 38 | .. code-block:: cpp 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | 46 | int main(int argc, char *argv[]) { 47 | std::deque v{1,2,3,4,5,7,10}; 48 | 49 | auto x = 8; 50 | auto pos = std::upper_bound(v.begin(), v.end(), x); 51 | v.insert(pos, x); 52 | std::cout << ranges::views::all(v) << "\n"; 53 | // [1,2,3,4,5,7,8,10] 54 | } 55 | 56 | Erase an Element in a Sorted List 57 | --------------------------------- 58 | 59 | .. code-block:: cpp 60 | 61 | #include 62 | #include 63 | #include 64 | #include 65 | 66 | 67 | int main(int argc, char *argv[]) { 68 | std::deque v{1,2,3,4,5,7,10}; 69 | 70 | auto x = 7; 71 | auto pos = std::lower_bound(v.begin(), v.end(), x); 72 | v.erase(pos); 73 | std::cout << ranges::views::all(v) << "\n"; 74 | // [1,2,3,4,5,10] 75 | } 76 | 77 | Reverse Range-based for Loop 78 | ---------------------------- 79 | 80 | .. code-block:: cpp 81 | 82 | // via boost 83 | // $ g++ --std=c++14 -Wall -Werror -g -O3 reverse.cpp 84 | // $ ./a.out 85 | // dlrow olleh 86 | 87 | #include 88 | #include 89 | #include 90 | 91 | using namespace boost; 92 | 93 | int main(int argc, char *argv[]) { 94 | std::string in = "hello world"; 95 | std::string out; 96 | for (const auto &c : adaptors::reverse(in)) { 97 | out += c; 98 | } 99 | std::cout << out << "\n"; 100 | } 101 | 102 | Customize an Iterator 103 | --------------------- 104 | 105 | .. code-block:: cpp 106 | 107 | // $ g++ -std=c++17 -Wall -Werror -g -O3 a.cc 108 | 109 | #include 110 | #include 111 | 112 | template 113 | class Array 114 | { 115 | public: 116 | class iterator 117 | { 118 | public: 119 | iterator(T *ptr) : ptr_{ptr} {} 120 | iterator operator++() { auto i = *this; ++ptr_; return i; } 121 | iterator operator++(int) { ++ptr_; return *this;}; 122 | T &operator*() { return *ptr_; } 123 | T *operator->() { return ptr_; } 124 | bool operator==(const iterator &rhs) { return ptr_ == rhs.ptr_; } 125 | bool operator!=(const iterator &rhs) { return ptr_ != rhs.ptr_; } 126 | private: 127 | T *ptr_; 128 | }; 129 | 130 | class const_iterator 131 | { 132 | public: 133 | const_iterator(T *ptr) : ptr_{ptr} {} 134 | const_iterator operator++() { auto i = *this; ++ptr_; return i; } 135 | const_iterator operator++(int) { ++ptr_; return *this; } 136 | const T &operator*() const { return *ptr_; } 137 | const T *operator->() const { return ptr_; } 138 | bool operator==(const const_iterator &rhs) { return ptr_ == rhs.ptr_; } 139 | bool operator!=(const const_iterator &rhs) { return ptr_ != rhs.ptr_; } 140 | private: 141 | T *ptr_; 142 | }; 143 | 144 | Array(size_t size) : size_(size), data_{std::make_unique(size)} {} 145 | size_t size() const { return size_; } 146 | T &operator[](size_t i) { return data_[i]; }; 147 | const T &operator[](size_t i) const { return data_[i]; } 148 | iterator begin() { return iterator(data_.get()); } 149 | iterator end() { return iterator(data_.get() + size_); } 150 | const_iterator cbegin() const { return const_iterator(data_.get()); } 151 | const_iterator cend() const { return const_iterator(data_.get() + size_); } 152 | 153 | private: 154 | size_t size_; 155 | std::unique_ptr data_; 156 | }; 157 | 158 | 159 | 160 | int main(int argc, char *argv[]) 161 | { 162 | Array points(2); 163 | points[0] = 55.66; 164 | points[1] = 95.27; 165 | for (auto &e : points) { 166 | std::cout << e << "\n"; 167 | } 168 | for (auto it = points.cbegin(); it != points.cend(); ++it) { 169 | std::cout << *it << "\n"; 170 | } 171 | } 172 | 173 | Iterate an Internal Vector 174 | -------------------------- 175 | 176 | .. code-block:: cpp 177 | 178 | #include 179 | #include 180 | #include 181 | 182 | template 183 | class Vector { 184 | public: 185 | using iterator = typename std::vector::iterator; 186 | using const_iterator = typename std::vector::const_iterator; 187 | 188 | inline iterator begin() noexcept {return v.begin();} 189 | inline iterator end() noexcept {return v.end();} 190 | inline const_iterator cbegin() const noexcept {return v.cbegin();} 191 | inline const_iterator cend() const noexcept {return v.cend();} 192 | 193 | template 194 | auto emplace_back(Args&&... args) { 195 | return v.emplace_back(std::forward(args)...); 196 | } 197 | private: 198 | std::vector v; 199 | }; 200 | 201 | 202 | int main(int argc, char *argv[]) { 203 | Vector v; 204 | v.emplace_back(1); 205 | v.emplace_back(2); 206 | v.emplace_back(3); 207 | 208 | for (auto &it : v) { 209 | std::cout << it << std::endl; 210 | } 211 | return 0; 212 | } 213 | 214 | Iterate a file 215 | -------------- 216 | 217 | .. code-block:: cpp 218 | 219 | // $ g++ -std=c++17 -Wall -Werror -g -O3 a.cc 220 | // $ ./a.out file 221 | 222 | #include 223 | #include 224 | #include 225 | #include 226 | 227 | class line : public std::string {}; 228 | 229 | std::istream &operator>>(std::istream &is, line &l) 230 | { 231 | std::getline(is, l); 232 | return is; 233 | } 234 | 235 | class FileReader 236 | { 237 | public: 238 | using iterator = std::istream_iterator; 239 | inline iterator begin() noexcept { return begin_; } 240 | inline iterator end() noexcept { return end_; } 241 | 242 | public: 243 | FileReader(const std::string path) : f_{path}, begin_{f_} {} 244 | friend std::istream &operator>>(std::istream &, std::string &); 245 | 246 | private: 247 | std::ifstream f_; 248 | iterator begin_; 249 | iterator end_; 250 | }; 251 | 252 | int main(int argc, char *argv[]) 253 | { 254 | FileReader reader(argv[1]); 255 | for (auto &line : reader) { 256 | std::cout << line << "\n"; 257 | } 258 | } 259 | 260 | Position after Erasing 261 | ---------------------- 262 | 263 | .. code-block:: cpp 264 | 265 | // deque 266 | #include 267 | #include 268 | #include 269 | 270 | int main(int argc, char *argv[]) { 271 | std::deque q{1, 2, 3, 4, 5}; 272 | auto it = q.begin() + 2; 273 | 274 | std::cout << *it << "\n"; 275 | std::cout << ranges::views::all(q) << "\n"; 276 | 277 | q.erase(it); 278 | std::cout << *it << "\n"; 279 | std::cout << ranges::views::all(q) << "\n"; 280 | 281 | // output 282 | // 3 283 | // [1,2,3,4,5] 284 | // 4 285 | // [1,2,4,5] 286 | } 287 | 288 | .. code-block:: cpp 289 | 290 | #include 291 | #include 292 | #include 293 | 294 | int main(int argc, char *argv[]) { 295 | std::vector v{1, 2, 3, 4, 5}; 296 | auto it = v.begin() + 2; 297 | 298 | std::cout << *it << "\n"; 299 | std::cout << ranges::views::all(v) << "\n"; 300 | 301 | v.erase(it); 302 | std::cout << *it << "\n"; 303 | std::cout << ranges::views::all(v) << "\n"; 304 | 305 | // output 306 | // 3 307 | // [1,2,3,4,5] 308 | // 4 309 | // [1,2,4,5] 310 | } 311 | 312 | 313 | .. code-block:: cpp 314 | 315 | #include 316 | #include 317 | #include 318 | 319 | int main(int argc, char *argv[]) { 320 | std::list l{1, 2, 3, 4, 5}; 321 | auto it = l.begin(); 322 | ++it; 323 | 324 | std::cout << *it << "\n"; 325 | std::cout << ranges::views::all(l) << "\n"; 326 | 327 | // Note that Iterators, pointers and references referring to elements 328 | // removed by the function are invalidated. This is an example to show 329 | // that an iterator do not point to the next element after erasing. 330 | l.erase(it); 331 | std::cout << *it << "\n"; 332 | std::cout << ranges::views::all(l) << "\n"; 333 | // output 334 | // 2 335 | // [1,2,3,4,5] 336 | // 2 337 | // [1,3,4,5] 338 | } 339 | 340 | 341 | Vector Comparision 342 | ------------------ 343 | 344 | Note that the comparision operators are removed in C++20 (see [doc](https://en.cppreference.com/w/cpp/container/vector)). 345 | Therefore, using a lambda function as compare function is better than using 346 | default comparision when elements are not builtin types or has its own comparision 347 | operators. 348 | 349 | .. code-block:: cpp 350 | 351 | #include 352 | #include 353 | 354 | int main(int argc, char *argv[]) { 355 | std::vector v1{5,2}; 356 | std::vector v2{2,3,4}; 357 | std::cout << (v1 < v2) << "\n"; 358 | // output: 0 359 | } 360 | -------------------------------------------------------------------------------- /docs/notes/cpp_lambda.rst: -------------------------------------------------------------------------------- 1 | ====== 2 | Lambda 3 | ====== 4 | 5 | .. contents:: Table of Contents 6 | :backlinks: none 7 | 8 | Callable Objects 9 | ---------------- 10 | 11 | .. code-block:: cpp 12 | 13 | #include 14 | 15 | class Fib { 16 | public: 17 | long operator() (const long n) { 18 | return (n <= 2) ? 1 : operator()(n-1) + operator()(n-2); 19 | } 20 | }; 21 | 22 | int main() { 23 | Fib fib; 24 | std::cout << fib(10) << "\n"; 25 | return 0; 26 | } 27 | 28 | Lambda version 29 | 30 | .. code-block:: cpp 31 | 32 | #include 33 | #include 34 | 35 | int main() { 36 | std::function fib = [&](long n) { 37 | return (n <= 2) ? 1 : fib(n-1) + fib(n-2); 38 | }; 39 | std::cout << fib(10) << "\n"; 40 | return 0; 41 | } 42 | 43 | Default Arguments 44 | ----------------- 45 | 46 | .. code-block:: cpp 47 | 48 | #include 49 | 50 | int main(int argc, char *argv[]) { 51 | auto fib = [](long n=0) { 52 | long a = 0, b = 1; 53 | for (long i = 0; i < n; ++i) { 54 | long tmp = b; 55 | b = a + b; 56 | a = tmp; 57 | } 58 | return a; 59 | }; 60 | std::cout << fib() << "\n"; 61 | std::cout << fib(10) << "\n"; 62 | return 0; 63 | } 64 | 65 | Captureless 66 | ----------- 67 | 68 | .. code-block:: cpp 69 | 70 | #include 71 | 72 | int main() { 73 | long (*fib)(long) = [](long n) { 74 | long a = 0, b = 1; 75 | for (long i = 0; i < n; ++i) { 76 | long tmp = b; 77 | b = a + b; 78 | a = tmp; 79 | } 80 | return a; 81 | }; 82 | std::cout << fib(10) << "\n"; 83 | return 0; 84 | } 85 | 86 | Lambda capture initializers 87 | --------------------------- 88 | 89 | .. code-block:: cpp 90 | 91 | // g++ -std=c++17 -Wall -Werror -O3 a.cc 92 | 93 | #include 94 | #include 95 | #include 96 | 97 | int main(int argc, char *argv[]) 98 | { 99 | std::unique_ptr p = std::make_unique(5566); 100 | auto f = [x = std::move(p)]() { std::cout << *x << std::endl; }; 101 | f(); 102 | } 103 | 104 | Capture by ``std::move`` 105 | ------------------------ 106 | 107 | .. code-block:: cpp 108 | 109 | #include 110 | #include 111 | 112 | struct Foo { 113 | Foo() { std::cout << "Constructor" << "\n"; } 114 | ~Foo() { std::cout << "Destructor" << "\n"; } 115 | Foo(const Foo&) { std::cout << "Copy Constructor" << "\n"; } 116 | Foo(Foo &&) { std::cout << "Move Constructor" << "\n";} 117 | 118 | Foo& operator=(const Foo&) { 119 | std::cout << "Copy Assignment" << "\n"; 120 | return *this; 121 | } 122 | Foo& operator=(Foo &&){ 123 | std::cout << "Move Assignment" << "\n"; 124 | return *this; 125 | } 126 | }; 127 | 128 | int main(int argc, char *argv[]) { 129 | Foo foo; 130 | [f=std::move(foo)] { /* do some tasks here...*/ }(); 131 | } 132 | 133 | 134 | Copy a Global into a Capture 135 | ---------------------------- 136 | 137 | .. code-block:: cpp 138 | 139 | #include 140 | 141 | int g = 1; 142 | 143 | // copy a global to a capture 144 | auto bar = [g=g]() { return g + 1; }; 145 | 146 | int main(int argc, char *argv[]) { 147 | int g = 10; 148 | std::cout << bar() << "\n"; 149 | } 150 | 151 | constexpr by Default 152 | -------------------- 153 | 154 | .. code-block:: cpp 155 | 156 | #include 157 | 158 | int main() { 159 | auto fib = [](long n) { 160 | long a = 0, b = 1; 161 | for (long i = 0; i < n; ++i) { 162 | long tmp = b; 163 | b = a + b; 164 | a = tmp; 165 | } 166 | return a; 167 | }; 168 | 169 | // constexpr by default is new in c++17 170 | static_assert(fib(10) == 55); 171 | return 0; 172 | } 173 | 174 | output: 175 | 176 | .. code-block:: bash 177 | 178 | $ g++ -std=c++17 -g -O3 a.cpp 179 | 180 | Generic Lambda 181 | -------------- 182 | 183 | .. code-block:: cpp 184 | 185 | #include 186 | #include 187 | 188 | // g++ -std=c++17 -g -O3 a.cpp 189 | 190 | class Sum { 191 | public: 192 | template 193 | constexpr auto operator()(Args&& ...args) { 194 | // Fold expression (since c++17) 195 | return (std::forward(args) + ...); 196 | } 197 | }; 198 | 199 | int main() { 200 | Sum sum; 201 | constexpr int ret = sum(1,2,3,4,5); 202 | std::cout << ret << std::endl; 203 | return 0; 204 | } 205 | 206 | The snippet is equal to the following example 207 | 208 | .. code-block:: cpp 209 | 210 | #include 211 | #include 212 | 213 | int main() { 214 | auto sum = [](auto&& ...args) { 215 | return (std::forward(args) + ...); 216 | }; 217 | constexpr int ret = sum(1,2,3,4,5); 218 | std::cout << ret << std::endl; 219 | return 0; 220 | } 221 | 222 | In c+20, lambda supports explicit template paramter list allowing a programmer 223 | to utilize parameters' type instead of using `decltype`. 224 | 225 | .. code-block:: cpp 226 | 227 | #include 228 | 229 | // g++ -std=c++2a -g -O3 a.cpp 230 | 231 | int main(int argc, char *argv[]) 232 | { 233 | auto sum = [](Args&&... args) { 234 | return (std::forward(args) + ...); 235 | }; 236 | constexpr int ret = sum(1,2,3,4,5); 237 | std::cout << ret << std::endl; 238 | return 0; 239 | } 240 | 241 | Comparison Function 242 | ------------------- 243 | 244 | .. code-block:: cpp 245 | 246 | #include 247 | #include 248 | #include 249 | 250 | struct Cmp { 251 | template 252 | bool operator() (const T &lhs, const T &rhs) const { 253 | return lhs < rhs; 254 | } 255 | }; 256 | 257 | int main(int argc, char *argv[]) { 258 | 259 | // sort by keys 260 | std::map m; 261 | 262 | m[3] = "Foo"; 263 | m[2] = "Bar"; 264 | m[1] = "Baz"; 265 | 266 | for (auto it : m) { 267 | std::cout << it.first << ", " << it.second << "\n"; 268 | } 269 | return 0; 270 | } 271 | 272 | .. code-block:: cpp 273 | 274 | #include 275 | #include 276 | #include 277 | 278 | bool cmp(const int &lhs, const int &rhs) { 279 | return lhs < rhs; 280 | } 281 | 282 | int main(int argc, char *argv[]) { 283 | 284 | // sort by keys 285 | std::map m(cmp); 286 | 287 | m[3] = "Foo"; 288 | m[2] = "Bar"; 289 | m[1] = "Baz"; 290 | 291 | for (auto it : m) { 292 | std::cout << it.first << ", " << it.second << "\n"; 293 | } 294 | return 0; 295 | } 296 | 297 | .. code-block:: cpp 298 | 299 | #include 300 | #include 301 | #include 302 | #include 303 | 304 | template 305 | using Cmp = std::function; 306 | 307 | template 308 | bool cmp(const T &lhs, const T &rhs) { 309 | return lhs < rhs; 310 | } 311 | 312 | int main(int argc, char *argv[]) { 313 | 314 | // sort by keys 315 | std::map> m(cmp); 316 | 317 | m[3] = "Foo"; 318 | m[2] = "Bar"; 319 | m[1] = "Baz"; 320 | 321 | for (auto it : m) { 322 | std::cout << it.first << ", " << it.second << "\n"; 323 | } 324 | return 0; 325 | } 326 | 327 | 328 | .. code-block:: cpp 329 | 330 | #include 331 | #include 332 | #include 333 | 334 | int main(int argc, char *argv[]) { 335 | 336 | auto cmp = [](auto &lhs, auto &rhs) { 337 | return lhs < rhs; 338 | }; 339 | 340 | // sort by keys 341 | std::map m(cmp); 342 | 343 | m[3] = "Foo"; 344 | m[2] = "Bar"; 345 | m[1] = "Baz"; 346 | 347 | for (auto it : m) { 348 | std::cout << it.first << ", " << it.second << "\n"; 349 | } 350 | return 0; 351 | } 352 | 353 | 354 | Break Loops 355 | ----------- 356 | 357 | .. code-block:: cpp 358 | 359 | #include 360 | 361 | int main(int argc, char *argv[]) { 362 | bool is_stoped = false; 363 | for (int i = 0; i < 5; ++i) { 364 | for (int j = 0; j < 5; ++j) { 365 | std::cout << i + j << " "; 366 | if (i + j == 5) { 367 | is_stoped = true; 368 | break; 369 | } 370 | } 371 | if (is_stoped) { 372 | break; 373 | } 374 | } 375 | std::cout << std::endl; 376 | return 0; 377 | } 378 | 379 | The previous example shows a common way to break multiple loops via a flag. 380 | However, the drawback is a programmer requires to maintain flags if code 381 | includes nested loops. By using a lambda function, it is convenient for 382 | developers to break nested loops through the return. 383 | 384 | .. code-block:: cpp 385 | 386 | #include 387 | 388 | int main(int argc, char *argv[]) { 389 | [&] { 390 | for (int i = 0; i < 5; ++i) { 391 | for (int j = 0; j < 5; ++j) { 392 | std::cout << i + j << " "; 393 | if (i + j == 5) { 394 | return; 395 | } 396 | } 397 | } 398 | }(); 399 | std::cout << std::endl; 400 | return 0; 401 | } 402 | 403 | Callback 404 | -------- 405 | 406 | .. code-block:: cpp 407 | 408 | #include 409 | 410 | template 411 | long fib(long n, F f) { 412 | long a = 0, b = 1; 413 | for (long i = 0; i < n; ++i) { 414 | long tmp = b; 415 | b = a + b; 416 | a = tmp; 417 | f(a); 418 | } 419 | return a; 420 | } 421 | 422 | int main(int argc, char *argv[]) { 423 | fib(10, [](long res) { 424 | std::cout << res << " "; 425 | }); 426 | std::cout << "\n"; 427 | return 0; 428 | } 429 | 430 | .. code-block:: cpp 431 | 432 | #include 433 | #include 434 | 435 | using fibcb = std::function; 436 | 437 | long fib(long n, fibcb f) { 438 | long a = 0, b = 1; 439 | for (long i = 0; i < n; ++i) { 440 | long tmp = b; 441 | b = a + b; 442 | a = tmp; 443 | f(a); 444 | } 445 | return a; 446 | } 447 | 448 | int main(int argc, char *argv[]) { 449 | fib(10, [](long res) { 450 | std::cout << res << " "; 451 | }); 452 | std::cout << "\n"; 453 | return 0; 454 | } 455 | 456 | Programmers can also use function pointers to define a functino's callback 457 | parameter. However, function pointers are only suitable for captureless lambda 458 | functions. 459 | 460 | .. code-block:: cpp 461 | 462 | #include 463 | #include 464 | 465 | using fibcb = void(*)(long n); 466 | 467 | long fib(long n, fibcb f) { 468 | long a = 0, b = 1; 469 | for (long i = 0; i < n; ++i) { 470 | long tmp = b; 471 | b = a + b; 472 | a = tmp; 473 | f(a); 474 | } 475 | return a; 476 | } 477 | 478 | int main(int argc, char *argv[]) { 479 | fib(10, [](long res) { 480 | std::cout << res << " "; 481 | }); 482 | std::cout << "\n"; 483 | return 0; 484 | } 485 | 486 | Recursion 487 | --------- 488 | 489 | There are two ways to run a lambda function recursively. The first one is using 490 | ``std::function``. However, this solution is slower than normal recursive function. 491 | 492 | .. code-block:: cpp 493 | 494 | #include 495 | #include 496 | #include 497 | 498 | int main(int argc, char *argv[]) { 499 | using namespace std::chrono; 500 | std::function fib; 501 | fib = [&](auto n) { return n <= 1 ? 1 : (fib(n - 1) + fib(n - 2)); }; 502 | auto s = system_clock::now(); 503 | fib(30); 504 | auto e = system_clock::now(); 505 | std::cout << duration_cast(e - s).count() << "\n"; 506 | } 507 | 508 | Another way is making lamdbda as an input arguemnt. The performance approaches 509 | the normal function. 510 | 511 | .. code-block:: cpp 512 | 513 | #include 514 | #include 515 | 516 | 517 | int main(int argc, char *argv[]) { 518 | using namespace std::chrono; 519 | auto fib = [&](auto &&n, auto &&fib) -> int { 520 | return n <= 1 ? 1 : (fib(n - 1, fib) + fib(n - 2, fib)); 521 | }; 522 | auto s = system_clock::now(); 523 | fib(30, fib); 524 | auto e = system_clock::now(); 525 | std::cout << duration_cast(e - s).count() << "\n"; 526 | } 527 | 528 | Reference 529 | --------- 530 | 531 | 1. `Back to Basics: Lambdas from Scratch`_ 532 | 2. `Demystifying C++ lambdas`_ 533 | 534 | .. _Back to Basics\: Lambdas from Scratch: https://youtu.be/3jCOwajNch0 535 | .. _Demystifying C++ lambdas: https://blog.feabhas.com/2014/03/demystifying-c-lambdas/ 536 | -------------------------------------------------------------------------------- /docs/notes/cpp_rvo.rst: -------------------------------------------------------------------------------- 1 | =============================== 2 | Return Value Optimization (RVO) 3 | =============================== 4 | 5 | .. contents:: Table of Contents 6 | :backlinks: none 7 | 8 | 9 | Before starting 10 | --------------- 11 | 12 | .. code-block:: cpp 13 | 14 | // foo.h 15 | 16 | #include 17 | 18 | struct Foo { 19 | Foo() { 20 | std::cout << "Constructor" << "\n"; 21 | } 22 | ~Foo() { 23 | std::cout << "Destructor" << "\n"; 24 | } 25 | Foo(const Foo&) { 26 | std::cout << "Copy Constructor" << "\n"; 27 | } 28 | Foo(Foo &&) { 29 | std::cout << "Move Constructor" << "\n"; 30 | } 31 | Foo& operator=(const Foo&) { 32 | std::cout << "Copy Assignment" << "\n"; 33 | return *this; 34 | } 35 | Foo& operator=(Foo &&){ 36 | std::cout << "Move Assignment" << "\n"; 37 | return *this; 38 | } 39 | }; 40 | 41 | Return Value Optimization 42 | ------------------------- 43 | 44 | .. code-block:: cpp 45 | 46 | #include "foo.h" 47 | 48 | Foo FooRVO() { 49 | return Foo(); 50 | } 51 | 52 | int main(int argc, char *argv[]) { 53 | Foo f = FooRVO(); 54 | } 55 | 56 | 57 | Named Return Value Optimization 58 | ------------------------------- 59 | 60 | .. code-block:: cpp 61 | 62 | #include "foo.h" 63 | 64 | Foo FooNRVO() { 65 | Foo foo; 66 | return foo; 67 | } 68 | 69 | int main(int argc, char *argv[]) { 70 | Foo f = FooNRVO(); 71 | } 72 | 73 | Copy Elision 74 | ------------ 75 | 76 | .. code-block:: cpp 77 | 78 | #include "foo.h" 79 | 80 | void CopyElision(Foo foo) {} 81 | 82 | int main(int argc, char *argv[]) { 83 | CopyElision(Foo()); 84 | } 85 | 86 | Return a Global (w/o RVO) 87 | ------------------------- 88 | 89 | .. code-block:: cpp 90 | 91 | #include "foo.h" 92 | 93 | const Foo foo; 94 | 95 | Foo ReturnGlobal() { 96 | return foo; 97 | } 98 | 99 | int main(int argc, char *argv[]) { 100 | Foo f = ReturnGlobal(); 101 | } 102 | 103 | Return a Parameter (w/o RVO) 104 | ---------------------------- 105 | 106 | .. code-block:: cpp 107 | 108 | #include "foo.h" 109 | 110 | Foo ReturnParam(Foo foo) { 111 | return foo; 112 | } 113 | 114 | int main(int argc, char *argv[]) { 115 | Foo f = ReturnParam(Foo()); 116 | } 117 | 118 | Runtime Decision (w/ RVO) 119 | ------------------------- 120 | 121 | .. code-block:: cpp 122 | 123 | #include "foo.h" 124 | 125 | Foo FooRVO(bool is_x) { 126 | return is_x ? Foo() : Foo(); 127 | } 128 | 129 | int main(int argc, char *argv[]) { 130 | Foo foo = FooRVO(true); 131 | } 132 | 133 | Runtime Decision (w/ RVO, w/o NRVO) 134 | ----------------------------------- 135 | 136 | .. code-block:: cpp 137 | 138 | #include "foo.h" 139 | 140 | Foo RVOButNoNRVO(bool is_x) { 141 | Foo x; 142 | return is_x ? x : Foo(); 143 | } 144 | 145 | int main(int argc, char *argv[]) { 146 | Foo f = RVOButNoNRVO(false); 147 | } 148 | 149 | Runtime Decision (w/o NRVO) 150 | --------------------------- 151 | 152 | .. code-block:: cpp 153 | 154 | #include "foo.h" 155 | 156 | Foo FooNoNRVO(bool is_x) { 157 | Foo x, y; 158 | return is_x ? x : y; 159 | } 160 | 161 | int main(int argc, char *argv[]) { 162 | Foo foo = FooNoNRVO(true); 163 | } 164 | 165 | Return by ``std::move`` (w/o RVO) 166 | --------------------------------- 167 | 168 | .. code-block:: cpp 169 | 170 | #include "foo.h" 171 | 172 | #include 173 | 174 | Foo FooMove() { 175 | return std::move(Foo()); 176 | } 177 | 178 | int main(int argc, char *argv[]) { 179 | Foo foo = FooMove(); 180 | } 181 | 182 | Return by ``std::move`` (w/o NRVO) 183 | ---------------------------------- 184 | 185 | .. code-block:: cpp 186 | 187 | #include "foo.h" 188 | 189 | #include 190 | 191 | Foo FooMove() { 192 | Foo foo; 193 | return std::move(foo); 194 | } 195 | 196 | int main(int argc, char *argv[]) { 197 | Foo foo = FooMove(); 198 | } 199 | 200 | Return a Member (w/o RVO) 201 | ------------------------- 202 | 203 | .. code-block:: cpp 204 | 205 | #include "foo.h" 206 | 207 | struct Bar { 208 | Foo foo; 209 | }; 210 | 211 | Foo ReturnMember() { 212 | return Bar().foo; 213 | } 214 | 215 | int main(int argc, char *argv[]) { 216 | Foo f = ReturnMember(); 217 | } 218 | -------------------------------------------------------------------------------- /docs/notes/cpp_smartpointers.rst: -------------------------------------------------------------------------------- 1 | ============== 2 | Smart Pointers 3 | ============== 4 | 5 | .. contents:: Table of Contents 6 | :backlinks: none 7 | 8 | Custom Deleters 9 | --------------- 10 | 11 | .. code-block:: cpp 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | using FilePtr = std::unique_ptr; 23 | 24 | constexpr void assert_that(bool statement, const char *msg) { 25 | if (!statement) { 26 | throw std::runtime_error(msg); 27 | } 28 | } 29 | 30 | int main(int argc, char *argv[]) { 31 | 32 | assert_that(argc == 2, "Usage: command [path]"); 33 | 34 | FILE *f = nullptr; 35 | f = fopen(argv[1], "r+"); 36 | assert_that(f, strerror(errno)); 37 | 38 | // assign FILE* to a unique_ptr 39 | FilePtr fptr{f, fclose}; 40 | assert_that(!!fptr, strerror(errno)); 41 | assert_that(fseek(fptr.get(), 0, SEEK_END) == 0, strerror(errno)); 42 | 43 | long size = ftell(fptr.get()); 44 | assert_that(size >=0, strerror(errno)); 45 | rewind(fptr.get()); 46 | 47 | // using unique_ptr to create a buffer instead of using malloc 48 | std::unique_ptr buf{ new char[size + 1]{0} }; 49 | assert_that(!!buf, strerror(errno)); 50 | 51 | size_t r = fread(buf.get(), 1, size, fptr.get()); 52 | assert_that(r == size, "Reading error"); 53 | std::cout << buf.get(); 54 | end: 55 | return 0; 56 | } 57 | 58 | ``std::make_shared`` and ``std::make_unique`` 59 | --------------------------------------------- 60 | 61 | ``std::make_shared`` and ``std::make_unique`` are the recommended ways to 62 | create smart pointers because compilers do guarantee the order of executions, 63 | which may introduce memory leaks when an exception is thrown. For example, the 64 | compilers may call ``new T``, then ``raise()``, and so on before ``foo`` is 65 | called. In this case, ``std::unique_ptr`` does not know the pointer ``T`` yet, 66 | so it is still on the heap. 67 | 68 | .. code-block:: cpp 69 | 70 | using uptr = std::unique_ptr; 71 | 72 | bool raise() { 73 | throw std::exception(); 74 | return true; 75 | } 76 | 77 | foo(uptr(new T), raise(), uptr(new T)); 78 | -------------------------------------------------------------------------------- /docs/notes/cpp_string.rst: -------------------------------------------------------------------------------- 1 | ====== 2 | String 3 | ====== 4 | 5 | .. contents:: Table of Contents 6 | :backlinks: none 7 | 8 | Char to a string 9 | ---------------- 10 | 11 | .. code-block:: cpp 12 | 13 | #include 14 | 15 | int main(int argc, char *argv[]) { 16 | // string(size_t n, char c) 17 | std::string a(1, 'a'); 18 | } 19 | 20 | .. code-block:: cpp 21 | 22 | #include 23 | 24 | int main(int argc, char *argv[]) { 25 | std::string s; 26 | s += 'a'; 27 | } 28 | 29 | .. code-block:: cpp 30 | 31 | #include 32 | 33 | int main(int argc, char *argv[]) { 34 | std::string s; 35 | s = 'a'; 36 | } 37 | 38 | C String to a String 39 | -------------------- 40 | 41 | .. code-block:: cpp 42 | 43 | #include 44 | 45 | int main(int argc, char *argv[]) { 46 | char cstr[] = "hello cstr"; 47 | std::string s = cstr; 48 | } 49 | 50 | Split a String 51 | -------------- 52 | 53 | .. code-block:: cpp 54 | 55 | // $ g++ --std=c++14 -Wall -Werror -g -O3 split.cpp 56 | // $ ./a.out 57 | // abc 58 | // def 59 | // ghi 60 | 61 | #include 62 | #include 63 | #include 64 | 65 | using namespace std; 66 | 67 | vector split(const string &str, char delimeter) { 68 | 69 | string s = str; 70 | vector out; 71 | size_t pos = 0; 72 | 73 | while((pos = s.find(delimeter)) != string::npos) { 74 | string token = s.substr(0, pos); 75 | out.emplace_back(token); 76 | s.erase(0, pos + 1); 77 | } 78 | out.emplace_back(s); 79 | return out; 80 | } 81 | 82 | int main(int argc, char *argv[]) { 83 | 84 | string s = "abc,def,ghi"; 85 | vector v = split(s, ','); 86 | for (const auto &c : v) { 87 | cout << c << "\n"; 88 | } 89 | } 90 | 91 | Using istream 92 | 93 | .. code-block:: cpp 94 | 95 | #include 96 | #include 97 | #include 98 | #include 99 | 100 | using namespace std; 101 | 102 | template 103 | class String : public string 104 | { 105 | friend istream &operator>>( istream &is, String &out) { 106 | std::getline(is, out, delimiter); 107 | return is; 108 | } 109 | }; 110 | 111 | int main(int argc, char *argv[]) { 112 | std::string text = "abc,def,ghi"; 113 | 114 | istringstream iss(text); 115 | vector out((istream_iterator>(iss)), 116 | istream_iterator>()); 117 | 118 | for (const auto &c : out) { 119 | cout << c << "\n"; 120 | } 121 | } 122 | 123 | 124 | 125 | Using ``std::getline`` 126 | 127 | .. code-block:: cpp 128 | 129 | #include 130 | #include 131 | #include 132 | #include 133 | 134 | using namespace std; 135 | 136 | int main(int argc, char *argv[]) 137 | { 138 | string in = "abc,def,ghi"; 139 | vector out; 140 | string token; 141 | std::istringstream stream(in); 142 | 143 | while (std::getline(stream, token, ',')) { 144 | out.emplace_back(token); 145 | } 146 | for (const auto &c : out) { 147 | cout << c << "\n"; 148 | } 149 | } 150 | 151 | Using boost 152 | 153 | .. code-block:: cpp 154 | 155 | #include 156 | #include 157 | #include 158 | #include 159 | 160 | using namespace std; 161 | 162 | int main(int argc, char *argv[]) { 163 | string in = "abc,def,ghi"; 164 | vector out; 165 | 166 | boost::split(out, in, [](char c) { return c == ','; }); 167 | for (const auto &s : out) { 168 | cout << s << "\n"; 169 | } 170 | } 171 | 172 | Upper & Lower 173 | ------------- 174 | 175 | .. code-block:: cpp 176 | 177 | // cc -std=c++17 -Wall -Werror -O3 a.cpp 178 | 179 | #include 180 | #include 181 | #include 182 | 183 | int main(int argc, char *argv[]) 184 | { 185 | std::string s = "Hello World"; 186 | // to upper 187 | std::transform(s.begin(), s.end(), s.begin(), ::toupper); 188 | std::cout << s << "\n"; 189 | 190 | // to lower 191 | std::transform(s.begin(), s.end(), s.begin(), ::tolower); 192 | std::cout << s << "\n"; 193 | } 194 | 195 | String Concat 196 | ------------- 197 | 198 | Note that concatenating a string at the beginning is much slower than appending 199 | in the end. Although reserving space can speed up inserting a string in front of 200 | another one, the performance is still much slower than appending a string at the 201 | back. 202 | 203 | .. code-block:: cpp 204 | 205 | #include 206 | #include 207 | 208 | constexpr int total = 100000; 209 | using milliseconds = std::chrono::milliseconds; 210 | 211 | template 212 | void profile(F &&func) { 213 | const auto start = std::chrono::steady_clock::now(); 214 | func(); 215 | const auto end = std::chrono::steady_clock::now(); 216 | const auto d = end - start; 217 | const auto mill = std::chrono::duration_cast(d).count(); 218 | std::cout << mill << " ms\n"; 219 | } 220 | 221 | int main(int argc, char *argv[]) { 222 | 223 | profile([] { 224 | std::string s; 225 | for (int i = 0; i < total; ++i) { 226 | s += 'a'; 227 | } 228 | }); 229 | 230 | profile([] { 231 | std::string s; 232 | for (int i = 0; i < total; ++i) { 233 | s = std::string(1, 'a') + s; 234 | } 235 | }); 236 | 237 | profile([] { 238 | std::string s; 239 | s.reserve(total+1); 240 | for (int i = 0; i < total; ++i) { 241 | s = std::string(1, 'a') + s; 242 | } 243 | }); 244 | } 245 | 246 | // $ g++ -std=c++17 -Wall -Werror a.cc 247 | // 0 ms 248 | // 143 ms 249 | // 110 ms 250 | 251 | String Literals 252 | --------------- 253 | 254 | .. code-block:: cpp 255 | 256 | #include 257 | #include 258 | #include 259 | 260 | int main(int argc, char *argv[]) { 261 | using namespace std::literals; 262 | 263 | auto s1 = "c string"; 264 | auto s2 = "std::string"s; 265 | auto s3 = "std::string_view"sv; 266 | 267 | std::cout << s1 << "\n"; 268 | std::cout << s2 << "\n"; 269 | std::cout << s3 << "\n"; 270 | } 271 | 272 | String View 273 | ----------- 274 | 275 | .. code-block:: cpp 276 | 277 | #include 278 | #include 279 | 280 | void f(std::string_view s) { 281 | std::cout << s << "\n"; 282 | } 283 | 284 | int main(int argc, char *argv[]) { 285 | const std::string s = "foo"; 286 | // pass a const string is ok 287 | f(s); 288 | } 289 | 290 | .. code-block:: cpp 291 | 292 | #include 293 | #include 294 | 295 | void f(std::string s) { 296 | std::cout << s << "\n"; 297 | } 298 | 299 | int main(int argc, char *argv[]) { 300 | std::string_view s = "foo"; 301 | f(s); // compile error. cannot convert a string_view to a string 302 | } 303 | 304 | .. code-block:: cpp 305 | 306 | #include 307 | #include 308 | 309 | void f(std::string s) { 310 | std::cout << s << "\n"; 311 | } 312 | 313 | int main(int argc, char *argv[]) { 314 | std::string_view s = "foo"; 315 | // we can cast a string_view to a string 316 | f(static_cast(s)); 317 | } 318 | 319 | .. code-block:: cpp 320 | 321 | // string_view is not alway has null-terminated 322 | #include 323 | #include 324 | #include 325 | 326 | int main(int argc, char *argv[]) { 327 | char array[3] = {'B', 'a', 'r'}; 328 | std::string_view s(array, sizeof array); 329 | // Dangerous!! ptr will access memory address larger than array+3 330 | for (auto ptr = s.data(); !!ptr; ++ptr) { 331 | std::cout << *ptr << "\n"; 332 | } 333 | } 334 | -------------------------------------------------------------------------------- /docs/notes/cpp_template.rst: -------------------------------------------------------------------------------- 1 | ======== 2 | Template 3 | ======== 4 | 5 | .. contents:: Table of Contents 6 | :backlinks: none 7 | 8 | Instantiate a Template 9 | ---------------------- 10 | 11 | .. code-block:: cpp 12 | 13 | #include 14 | 15 | struct A {}; 16 | struct B {}; 17 | 18 | template 19 | struct Foo { 20 | Foo(T t, U u) : t_(t), u_(u) {} 21 | 22 | T t_; 23 | U u_; 24 | }; 25 | 26 | template 27 | struct Bar { 28 | Bar(T t, U u) : f_(t, u) {} 29 | 30 | F f_; 31 | }; 32 | 33 | // instantiate template Foo 34 | template class Foo; 35 | 36 | int main() { 37 | Bar, A, B>(A(), B()); 38 | return 0; 39 | } 40 | 41 | Template Specialization 42 | ----------------------- 43 | 44 | .. code-block:: cpp 45 | 46 | #include 47 | 48 | template 49 | class Base 50 | { 51 | private: 52 | T m_a; 53 | U m_b; 54 | 55 | public: 56 | 57 | Base(T a, U b) : m_a(a), m_b(b) {}; 58 | 59 | T foo() { return m_a; } 60 | U bar() { return m_b; } 61 | }; 62 | 63 | // partial specialization 64 | template 65 | class Base 66 | { 67 | private: 68 | T m_a; 69 | int m_b; 70 | public: 71 | Base(T a, int b) : m_a(a), m_b(b) {} 72 | T foo() { return m_a; } 73 | int bar() { return m_b; } 74 | }; 75 | 76 | // full specialization 77 | template<> 78 | class Base 79 | { 80 | private: 81 | double d_a; 82 | double d_b; 83 | public: 84 | Base(double a, double b) : d_a(a), d_b(b) {} 85 | double foo() { return d_a; } 86 | double bar() { return d_b; } 87 | }; 88 | 89 | 90 | int main (int argc, char *argv[]) 91 | { 92 | Base foo(3.33, 1); 93 | Base bar(55.66, 95.27); 94 | std::cout << foo.foo() << std::endl; 95 | std::cout << foo.bar() << std::endl; 96 | std::cout << bar.foo() << std::endl; 97 | std::cout << bar.bar() << std::endl; 98 | return 0; 99 | } 100 | 101 | Class Template 102 | -------------- 103 | 104 | .. code-block:: cpp 105 | 106 | #include 107 | 108 | template 109 | class Area 110 | { 111 | protected: 112 | T w; 113 | T h; 114 | public: 115 | Area(T a, T b) : w(a), h(b) {} 116 | T get() { return w * h; } 117 | }; 118 | 119 | class Rectangle : public Area 120 | { 121 | public: 122 | Rectangle(int a, int b) : Area(a, b) {} 123 | }; 124 | 125 | template 126 | class GenericRectangle : public Area 127 | { 128 | public: 129 | GenericRectangle(T a, T b) : Area(a, b){} 130 | }; 131 | 132 | 133 | int main (int argc, char *argv[]) 134 | { 135 | Rectangle r(2, 5); 136 | GenericRectangle g1(2.5, 3.); 137 | GenericRectangle g2(2, 3); 138 | 139 | std::cout << r.get() << std::endl; 140 | std::cout << g1.get() << std::endl; 141 | std::cout << g2.get() << std::endl; 142 | return 0; 143 | } 144 | 145 | Variadic Template (Parameter Pack) 146 | ---------------------------------- 147 | 148 | .. code-block:: cpp 149 | 150 | #include 151 | #include 152 | #include 153 | 154 | template 155 | class Vector { 156 | protected: 157 | std::vector v; 158 | public: 159 | 160 | template 161 | Vector(Args&&... args) { 162 | (v.emplace_back(std::forward(args)), ...); 163 | } 164 | 165 | using iterator = typename std::vector::iterator; 166 | iterator begin() noexcept { return v.begin(); } 167 | iterator end() noexcept { return v.end(); } 168 | }; 169 | 170 | 171 | int main(int argc, char *argv[]) { 172 | 173 | Vector v{1,2,3}; 174 | for (const auto &x : v) 175 | { 176 | std::cout << x << "\n"; 177 | } 178 | } 179 | 180 | Fold expressions 181 | ---------------- 182 | 183 | .. code-block:: cpp 184 | 185 | // g++ -std=c++17 -Wall -Werror -O3 a.cc 186 | 187 | #include 188 | #include 189 | 190 | template 191 | decltype(auto) f(Args&& ...args) { 192 | auto l = [](auto &&x) { return x * 2; }; 193 | return (l(std::forward(args)) + ...); 194 | } 195 | 196 | int main(int argc, char *argv[]) { 197 | std::cout << f(1, 2, 3, 4, 5) << std::endl; 198 | } 199 | 200 | Limit a Template Types 201 | ---------------------- 202 | 203 | .. code-block:: cpp 204 | 205 | #include 206 | #include 207 | #include 208 | 209 | template::type 214 | >::value 215 | >::type 216 | > 217 | void Foo(S s) { 218 | std::cout << s << "\n"; 219 | } 220 | 221 | 222 | int main(int argc, char *argv[]) { 223 | std::string s1 = "Foo"; 224 | const std::string s2 = "Bar"; 225 | Foo(s1); 226 | Foo(s2); 227 | 228 | // Foo(123); compile error 229 | // Foo("Baz"); compile error 230 | } 231 | 232 | Specialize Types 233 | ---------------- 234 | 235 | .. code-block:: cpp 236 | 237 | #include 238 | #include 239 | #include 240 | 241 | template 242 | void Foo(S s) { 243 | if (std::is_integral::value) { 244 | std::cout << "do a task for integer..." << "\n"; 245 | return; 246 | } 247 | if (std::is_same::type>::value) 248 | { 249 | std::cout << "do a task for string..." << "\n"; 250 | return; 251 | } 252 | } 253 | 254 | int main(int argc, char *argv[]) { 255 | std::string s1 = "Foo"; 256 | Foo(s1); 257 | Foo(123); 258 | } 259 | 260 | Template Specialization approach 261 | 262 | .. code-block:: cpp 263 | 264 | #include 265 | #include 266 | #include 267 | 268 | template 269 | void Foo(S s) {} 270 | 271 | template <> 272 | void Foo(int s) { 273 | std::cout << "do a task for integer..." << "\n"; 274 | } 275 | template<> 276 | void Foo(std::string s) { 277 | std::cout << "do a task for string..." << "\n"; 278 | } 279 | 280 | 281 | int main(int argc, char *argv[]) { 282 | std::string s1 = "Foo"; 283 | Foo(s1); 284 | Foo(123); 285 | } 286 | 287 | 288 | Curiously recurring template pattern 289 | ------------------------------------ 290 | 291 | .. code-block:: cpp 292 | 293 | #include 294 | 295 | // Curiously Recurring Template Pattern (CRTP) 296 | 297 | template 298 | class Base 299 | { 300 | public: 301 | void interface() { 302 | static_cast(this)->implement(); 303 | } 304 | 305 | static void static_interface() { 306 | D::static_interface(); 307 | } 308 | 309 | void implement() { 310 | std::cout << "Base" << std::endl; 311 | } 312 | }; 313 | 314 | class DerivedFoo : public Base 315 | { 316 | public: 317 | void implement() { 318 | std::cout << "Foo" << std::endl; 319 | } 320 | static void static_interface() { 321 | std::cout << "Static Foo" << std::endl; 322 | } 323 | }; 324 | 325 | class DerivedBar : public Base {}; 326 | 327 | int main (int argc, char *argv[]) 328 | { 329 | DerivedFoo foo; 330 | DerivedBar bar; 331 | 332 | foo.interface(); 333 | foo.static_interface(); 334 | bar.interface(); 335 | 336 | return 0; 337 | } 338 | 339 | Parametric Expressions 340 | ---------------------- 341 | 342 | .. code-block:: cpp 343 | 344 | #include 345 | 346 | // g++ -std=c++17 -fconcepts -g -O3 a.cpp 347 | 348 | decltype(auto) min(auto&& lhs, auto&& rhs) { 349 | return lhs < rhs ? lhs : rhs; 350 | } 351 | 352 | int main(int argc, char *argv[]) { 353 | std::cout << min(1, 2) << "\n"; 354 | std::cout << min(3.14, 2.718) << "\n"; 355 | } 356 | 357 | .. code-block:: cpp 358 | 359 | #include 360 | 361 | template 362 | decltype(auto) min(T&& lhs,T&& rhs) { 363 | return lhs < rhs ? lhs : rhs; 364 | } 365 | 366 | int main(int argc, char *argv[]) { 367 | std::cout << min(1, 2) << "\n"; 368 | std::cout << min(3.14, 2.718) << "\n"; 369 | } 370 | 371 | .. code-block:: cpp 372 | 373 | #include 374 | 375 | auto min = [](auto&& lhs, auto&& rhs) { 376 | return lhs < rhs ? lhs : rhs; 377 | }; 378 | 379 | int main(int argc, char *argv[]) { 380 | std::cout << min(1, 2) << "\n"; 381 | std::cout << min(3.14, 2.718) << "\n"; 382 | } 383 | 384 | Reference 385 | 386 | _ `Parametric Expressions`_ 387 | 388 | .. _Parametric Expressions: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1221r0.html 389 | 390 | Template Template Parameters 391 | ---------------------------- 392 | 393 | .. code-block:: cpp 394 | 395 | #include 396 | #include 397 | 398 | template class V, class T, class A> 399 | void f(V &v) { 400 | v.pop_back(); 401 | } 402 | 403 | int main(int argc, char *argv[]) { 404 | std::vector v{0}; 405 | std::deque q{1}; 406 | f(v); 407 | f(q); 408 | } 409 | 410 | Access Protected Membors in Sub-Template 411 | ---------------------------------------- 412 | 413 | Accessing protected members by pulling the names into the current scope via ``using``. 414 | 415 | .. code-block:: cpp 416 | 417 | #include 418 | 419 | template 420 | class A { 421 | public: 422 | A(T p) : p_{p} {} 423 | decltype(auto) f() { std::cout << p_ << "\n"; } 424 | protected: 425 | T p_; 426 | }; 427 | 428 | template 429 | class B : A { 430 | using A::p_; 431 | public: 432 | B(T p) : A(p) {} 433 | decltype(auto) g() { std::cout << p_ << "\n"; } 434 | }; 435 | 436 | int main(int argc, char *argv[]) { 437 | A a(0); 438 | B b(0); 439 | a.f(); 440 | b.g(); 441 | } 442 | 443 | Another option is qualifying name via the ``this`` pointer. 444 | 445 | .. code-block:: cpp 446 | 447 | #include 448 | 449 | template 450 | class A { 451 | public: 452 | A(T p) : p_{p} {} 453 | decltype(auto) f() { std::cout << p_ << "\n"; } 454 | protected: 455 | T p_; 456 | }; 457 | 458 | template 459 | class B : A { 460 | public: 461 | B(T p) : A{p} {} 462 | decltype(auto) g() { std::cout << this->p_ << "\n"; } 463 | }; 464 | 465 | int main(int argc, char *argv[]) { 466 | A a(0); 467 | B b(0); 468 | a.f(); 469 | b.g(); 470 | } 471 | -------------------------------------------------------------------------------- /docs/notes/cpp_time.rst: -------------------------------------------------------------------------------- 1 | ==== 2 | Time 3 | ==== 4 | 5 | .. contents:: Table of Contents 6 | :backlinks: none 7 | 8 | Timestamp 9 | --------- 10 | 11 | .. code-block:: cpp 12 | 13 | // g++ -std=c++17 -Wall -Werror -O3 a.cc 14 | 15 | #include 16 | #include 17 | 18 | using milliseconds = std::chrono::milliseconds; 19 | namespace chrono = std::chrono; 20 | 21 | int main(int argc, char *argv[]) 22 | { 23 | auto now = std::chrono::system_clock::now(); 24 | auto t = now.time_since_epoch(); 25 | std::cout << chrono::duration_cast(t).count() << "\n"; 26 | } 27 | 28 | To ``chrono::chrono::time_point`` 29 | --------------------------------- 30 | 31 | .. code-block:: cpp 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | namespace chrono = std::chrono; 39 | using ms = std::chrono::milliseconds; 40 | 41 | int main(int argc, char *argv[]) 42 | { 43 | using namespace std::literals; 44 | auto s = 1602207217323ms; 45 | chrono::system_clock::time_point tp(s); 46 | std::time_t t = chrono::system_clock::to_time_t(tp); 47 | std::cout << std::put_time(std::gmtime(&t), "%FT%TZ") << "\n"; 48 | } 49 | 50 | Duration 51 | -------- 52 | 53 | .. code-block:: cpp 54 | 55 | #include 56 | #include 57 | 58 | int main(int argc, char *argv[]) { 59 | using seconds = std::chrono::seconds; 60 | using namespace std::chrono_literals; 61 | auto now = std::chrono::system_clock::now(); 62 | auto future = now + 1ms; 63 | auto t = std::chrono::system_clock::to_time_t(future); 64 | std::cout << "timestamp: " << std::ctime(&t); 65 | 66 | auto start = std::chrono::system_clock::now(); 67 | auto end = std::chrono::system_clock::now() + 10s; 68 | auto duration = duration_cast(end - start); 69 | std::cout << duration.count() << " sec\n"; 70 | 71 | // output: 72 | // timestamp: Thu Oct 6 12:39:35 2022 73 | // 10 sec 74 | } 75 | 76 | Profiling 77 | --------- 78 | 79 | .. code-block:: cpp 80 | 81 | #include 82 | #include 83 | 84 | #include 85 | 86 | using milliseconds = std::chrono::milliseconds; 87 | namespace chrono = std::chrono; 88 | 89 | int main(int argc, char *argv[]) 90 | { 91 | auto start = std::chrono::steady_clock::now(); 92 | sleep(3); 93 | auto end = std::chrono::steady_clock::now(); 94 | auto d = end - start; 95 | std::cout << chrono::duration_cast(d).count() << "\n"; 96 | } 97 | 98 | Literals 99 | -------- 100 | 101 | .. code-block:: cpp 102 | 103 | #include 104 | #include 105 | 106 | using ms = std::chrono::milliseconds; 107 | namespace chrono = std::chrono; 108 | 109 | int main(int argc, char *argv[]) 110 | { 111 | using namespace std::literals; 112 | auto t = 1602207217323ms; 113 | std::cout << std::chrono::duration_cast(t).count() << "\n"; 114 | } 115 | 116 | Format Time 117 | ----------- 118 | 119 | .. code-block:: cpp 120 | 121 | #include 122 | #include 123 | #include 124 | #include 125 | 126 | int main(int argc, char *argv[]) 127 | { 128 | std::time_t t = std::time(nullptr); 129 | constexpr char fmt[] = "%c %Z"; 130 | std::cout << "UTC " << std::put_time(std::gmtime(&t), fmt) << "\n"; 131 | std::cout << "Local " << std::put_time(std::localtime(&t), fmt) << "\n"; 132 | 133 | std::string tz = "America/Chicago"; 134 | putenv(tz.data()); 135 | std::cout << "Chicago " << std::put_time(std::localtime(&t), fmt) << "\n"; 136 | } 137 | 138 | To ``time_t`` 139 | ------------- 140 | 141 | .. code-block:: cpp 142 | 143 | #include 144 | #include 145 | #include 146 | #include 147 | 148 | namespace chrono = std::chrono; 149 | 150 | int main(int argc, char *argv[]) 151 | { 152 | auto now = chrono::system_clock::now(); 153 | std::time_t t = std::chrono::system_clock::to_time_t(now); 154 | std::cout << std::put_time(std::gmtime(&t), "%FT%TZ") << "\n"; 155 | } 156 | 157 | ISO 8601 format 158 | --------------- 159 | 160 | .. code-block:: cpp 161 | 162 | #include 163 | #include 164 | #include 165 | #include 166 | 167 | namespace chrono = std::chrono; 168 | 169 | int main(int argc, char *argv[]) 170 | { 171 | auto now = chrono::system_clock::now(); 172 | std::time_t t = std::chrono::system_clock::to_time_t(now); 173 | std::cout << std::put_time(std::gmtime(&t), "%Y-%m-%dT%H:%M:%SZ") << "\n"; 174 | std::cout << std::put_time(std::gmtime(&t), "%FT%TZ") << "\n"; 175 | std::cout << std::put_time(std::gmtime(&t), "%FT%TZ%z") << "\n"; 176 | } 177 | -------------------------------------------------------------------------------- /docs/notes/cpp_variadic.rst: -------------------------------------------------------------------------------- 1 | ======== 2 | Variadic 3 | ======== 4 | 5 | .. contents:: Table of Contents 6 | :backlinks: none 7 | 8 | Variadic Function 9 | ----------------- 10 | 11 | .. code-block:: cpp 12 | 13 | #include 14 | 15 | template 16 | int sum(T x) 17 | { 18 | return x; 19 | } 20 | 21 | template 22 | int sum(T x, Args ...args) 23 | { 24 | return x + sum(args...); 25 | } 26 | 27 | int main(int argc, char *argv[]) 28 | { 29 | std::cout << sum(1, 2, 3, 4, 5) << std::endl; 30 | } 31 | 32 | By using C++17 or above, Fold expression can simplify the previous snippet. 33 | 34 | .. code-block:: cpp 35 | 36 | #include 37 | 38 | template 39 | int sum(Args ...args) 40 | { 41 | return (args + ...); 42 | } 43 | 44 | int main(int argc, char *argv[]) 45 | { 46 | std::cout << sum(1, 2, 3, 4, 5) << std::endl; 47 | } 48 | 49 | Generic lambda expressions 50 | -------------------------- 51 | 52 | C++14 allows lambda function using ``auto`` type-specifier in the arguments, 53 | which is similar to a template function. 54 | 55 | .. code-block:: cpp 56 | 57 | #include 58 | 59 | template 60 | auto sum(T x) 61 | { 62 | return x; 63 | } 64 | 65 | template 66 | auto sum(T x, Args ...args) 67 | { 68 | return x + sum(args...); 69 | } 70 | 71 | int main(int argc, char *argv[]) 72 | { 73 | auto s = [](auto ...args) { return sum(args...); }; 74 | std::cout << s(1, 2, 3, 4, 5) << std::endl; 75 | } 76 | 77 | By using C++17 or above, a programmer can simplify the previous code as following 78 | snippet. 79 | 80 | .. code-block:: cpp 81 | 82 | // g++ -std=c++17 -Wall -Werror -O3 a.cc 83 | 84 | #include 85 | 86 | int main(int argc, char *argv[]) 87 | { 88 | auto sum = [](auto ...args) { return (args + ...); }; 89 | std::cout << sum(1, 2, 3, 4, 5) << std::endl; 90 | } 91 | 92 | Variadic constructor 93 | -------------------- 94 | 95 | .. code-block:: cpp 96 | 97 | #include 98 | #include 99 | 100 | class Foo { 101 | public: 102 | 103 | template 104 | Foo(Args ...args) 105 | { 106 | Sum(args...); 107 | } 108 | 109 | template 110 | void Sum(T t) 111 | { 112 | sum += t; 113 | } 114 | 115 | template 116 | void Sum(T t, Args ...args) 117 | { 118 | sum += t; 119 | Sum(args...); 120 | } 121 | 122 | void Print() 123 | { 124 | std::cout << sum << std::endl; 125 | } 126 | 127 | private: 128 | int sum = 0; 129 | }; 130 | 131 | int main(int argc, char *argv[]) 132 | { 133 | auto f = Foo(1, 2, 3, 4, 5); 134 | f.Print(); 135 | } 136 | 137 | .. code-block:: cpp 138 | 139 | #include 140 | #include 141 | 142 | class Foo { 143 | public: 144 | 145 | template 146 | Foo(T t) 147 | { 148 | sum += t; 149 | } 150 | 151 | template 152 | Foo(T t, Args ...args) : Foo(args...) 153 | { 154 | sum += t; 155 | } 156 | 157 | void Print() 158 | { 159 | std::cout << sum << std::endl; 160 | } 161 | 162 | private: 163 | int sum = 0; 164 | }; 165 | 166 | int main(int argc, char *argv[]) 167 | { 168 | auto f = Foo(1, 2, 3, 4, 5); 169 | f.Print(); 170 | } 171 | 172 | 173 | .. warning:: 174 | 175 | Please don't invoke a template constructor in a contructor because a new object 176 | will be created instead of updating the current object's status. 177 | 178 | .. code-block:: cpp 179 | 180 | #include 181 | #include 182 | 183 | class Foo { 184 | public: 185 | template 186 | Foo(T t) 187 | { 188 | sum += t; 189 | } 190 | 191 | template 192 | Foo(T t, Args ...args) 193 | { 194 | sum += t; 195 | Foo(args...); 196 | } 197 | 198 | void Print() 199 | { 200 | std::cout << sum << std::endl; 201 | } 202 | 203 | private: 204 | int sum = 0; 205 | }; 206 | 207 | int main(int argc, char *argv[]) 208 | { 209 | auto f = Foo(1, 2, 3, 4, 5); 210 | f.Print(); 211 | } 212 | 213 | .. code-block:: cpp 214 | 215 | #include 216 | #include 217 | 218 | class Foo { 219 | public: 220 | template 221 | Foo(Args ...args) 222 | { 223 | sum = (args + ...); 224 | } 225 | 226 | void Print() 227 | { 228 | std::cout << sum << std::endl; 229 | } 230 | 231 | private: 232 | int sum = 0; 233 | }; 234 | 235 | int main(int argc, char *argv[]) 236 | { 237 | auto f = Foo(1, 2, 3, 4, 5); 238 | f.Print(); 239 | } 240 | 241 | Static Loop unrolling 242 | --------------------- 243 | 244 | .. code-block:: cpp 245 | 246 | #include 247 | #include 248 | 249 | template 250 | struct Loop { 251 | template 252 | static void run(F &&f, Args&& ...args) 253 | { 254 | Loop::run(std::forward(f),std::forward(args)...); 255 | f(args..., N-1); 256 | } 257 | }; 258 | 259 | template <> 260 | struct Loop<0> { 261 | template 262 | static void run(F &&f, Args&& ...args) {} 263 | }; 264 | 265 | int main(int argc, char *argv[]) 266 | { 267 | size_t counter = 0; 268 | // for (int i = 0; i < 5; ++i) { counter += i; } 269 | Loop<5>::run([&](auto i) { counter += i; }); 270 | std::cout << counter << std::endl; 271 | } 272 | 273 | Fold expression 274 | --------------- 275 | 276 | .. code-block:: cpp 277 | 278 | #include 279 | #include 280 | 281 | int main(int argc, char *argv[]) 282 | { 283 | [](auto ...args) { 284 | return (args + ...); 285 | }(1, 2, 3 ,4 ,5); 286 | 287 | std::vector v; 288 | [](auto &&v, auto ...args) { 289 | (v.emplace_back(args), ...); 290 | }(v); 291 | 292 | [](auto ...args) { 293 | (std::cout << ... << args) << "\n"; 294 | }(1, 2, 3, 4, 5); 295 | 296 | [](auto &&f, auto ...args) { 297 | return (... + f(args)); 298 | }([](auto x) { return x * 2; }, 1, 2, 3, 4, 5); 299 | } 300 | 301 | -------------------------------------------------------------------------------- /docs/notes/gdb_debug.rst: -------------------------------------------------------------------------------- 1 | Debug with GDB 2 | ============== 3 | 4 | .. contents:: Table of Contents 5 | :backlinks: none 6 | 7 | Load an Executable 8 | ------------------ 9 | 10 | 11 | Using GDB to debug requires it recognizes a program's debug symbols. By 12 | compiling with ``-g`` option, GDB will understand what source code looks like 13 | after loading an executable file: 14 | 15 | .. code-block:: bash 16 | 17 | $ gcc -g -Wall -Werror foo.c # compile with -g option 18 | $ gdb ./a.out # load all symbols of a.out into GDB 19 | 20 | 21 | Text User Interface 22 | ------------------- 23 | 24 | Text User Interface (TUI) allows developers to visualize source code and to 25 | debug like using the Integrated Development Environment (IDE) to trace problems. 26 | For a beginner, entering the TUI mode is more understandable than the command 27 | line mode. The following key bindings are the most common usages for interacting 28 | with TUI. 29 | 30 | 1. Ctrl x + a - Enter or leave the TUI mode 31 | 2. Ctrl x + o - Switch the active window 32 | 3. Ctrl x + 1 - Display one window (e.g., source code + GDB shell) 33 | 4. Ctrl x + 2 - Display two windows (e.g., source code + GDB shell + assembly) 34 | 5. Ctrl l - Refresh window 35 | 36 | 37 | Basic Commands 38 | -------------- 39 | 40 | **Start/Stop a program** 41 | 42 | 1. start - Run an executable file and stop at the beginning 43 | 2. run / r - Run an executable file until finish or stop at a breakpoint 44 | 3. step / s - Run a program step by step with entering a function 45 | 4. next / n - Run a program step by step without entering a function 46 | 5. continue / c - Run a program until finish or stop at a breakpoint 47 | 6. finish - Step out of the current function 48 | 49 | **Set Breakpoints** 50 | 51 | 1. b line - Set a breakpoint at the given line in the current file 52 | 2. b file: line - Set a breakpoint at the given line in a given file 53 | 3. b ... if cond - Set a breakpoint when the condition is true 54 | 4. clear line - Delete a breakpoint at the given line in the current file 55 | 5. clear file: line - Delete a breakpoint at giving a line in a given file 56 | 6. info breakpoints - Display breakpoints status 57 | 7. enable breakpoints - Enable breakpoints 58 | 8. disable breakpoints - Disable breakpoints 59 | 9. watch cond - Set a watchpoint for inspecting a value 60 | 61 | 62 | **Display Stack** 63 | 64 | 1. backtrace / bt - Display current stack 65 | 2. frame / f framenum - Select a frame and inspect its status 66 | 3. where - Display the current stack and the line 67 | 68 | **Print Variables** 69 | 70 | 1. print / p var - Print value of the given variable 71 | 2. ptype var - Print type info of the given variable 72 | 3. info args - Print function arguments 73 | 4. info locals - Print all local variables 74 | 75 | **Reverse Run** 76 | 77 | 1. record - Start recording each instruction step 78 | 2. record stop - Stop recording 79 | 3. rn - Reverse next 80 | 4. rs - Reverse step 81 | 82 | .. code-block:: cpp 83 | 84 | int main(int argc, char *argv[]) { 85 | int out = 0; 86 | for (int i = 0; i < 10; ++i) { 87 | out = i * i; 88 | } 89 | return out; 90 | } 91 | 92 | .. code-block:: bash 93 | 94 | (gdb) b main 95 | (gdb) r 96 | Starting program: /home/ubuntu/a.out 97 | 98 | Breakpoint 1, main (argc=21845, argv=0x0) at test.cc:2 99 | 2 { 100 | (gdb) record 101 | ... 102 | (gdb) n 103 | (gdb) p out 104 | $1 = 1 105 | (gdb) rn 106 | (gdb) rn 107 | (gdb) p out 108 | $2 = 0 109 | 110 | **Define a Function** 111 | 112 | GDB provides an original way for developers to define a customized function. 113 | The following snippet shows how to define a function to display the information 114 | of the current stack. 115 | 116 | .. code-block:: bash 117 | 118 | (gdb) define sf 119 | Type commands for definition of "sf". 120 | End with a line saying just "end". 121 | >where 122 | >info args 123 | >info locals 124 | >end 125 | 126 | Display Memory Contents 127 | ----------------------- 128 | 129 | .. code-block:: cpp 130 | 131 | int main() { 132 | char arr[100] = "1234567890abcdefghijklmnopqrstuvwxyz"; 133 | return 0; 134 | } 135 | 136 | .. code-block:: bash 137 | 138 | (gdb) " x/[format] [address expression] 139 | (gdb) " x/[len][format] [address expression] 140 | (gdb) x/s arr 141 | 0x7fffffffe620: "1234567890abcdefghijklmnopqrstuvwxyz" 142 | (gdb) x/10c arr 143 | (gdb) x/5c arr 144 | 0x7fffffffe620: 49 '1' 50 '2' 51 '3' 52 '4' 53 '5' 145 | (gdb) x/5b arr 146 | 0x7fffffffe620: 0x31 0x32 0x33 0x34 0x35 147 | -------------------------------------------------------------------------------- /docs/notes/perf.rst: -------------------------------------------------------------------------------- 1 | =============== 2 | Perf Cheatsheet 3 | =============== 4 | 5 | .. contents:: Table of Contents 6 | :backlinks: none 7 | 8 | 9 | Perf Top 10 | -------- 11 | 12 | .. code-block:: bash 13 | 14 | # show top symbols which CPU sample rate is 99 Hertz. 15 | perf top -F 99 16 | 17 | # show top process name and arguments 18 | perf top -ns comm,dso 19 | 20 | # count system call by process. refreshing 1 sec 21 | perf top -e raw_syscalls:sys_enter -ns comm -d 1 22 | -------------------------------------------------------------------------------- /docs/notes/systemd.rst: -------------------------------------------------------------------------------- 1 | ======= 2 | Systemd 3 | ======= 4 | 5 | .. contents:: Table of Contents 6 | :backlinks: none 7 | 8 | Services Management 9 | ------------------- 10 | 11 | .. code-block:: bash 12 | 13 | # start 14 | $ systemctl start app.service 15 | 16 | # stop 17 | $ systemctl stop app.service 18 | 19 | # restart 20 | $ systemctl restart app.service 21 | 22 | # reload 23 | $ systemctl reload app.service 24 | 25 | # reload a daemon after modifying a unit 26 | $ systemctl daemon-reload 27 | 28 | # enable a service 29 | $ systemctl enable app.service 30 | 31 | # disable a service 32 | $ systemctl disable app.service 33 | 34 | # check status 35 | $ systemctl status app.service 36 | 37 | # check is active 38 | $ systemctl is-active app.service 39 | 40 | # check is enabled 41 | $ systemctl is-enabled app.service 42 | 43 | # list all units 44 | $ systemctl list-units 45 | 46 | # list all timers 47 | $ systemctl list-timers 48 | 49 | User Services 50 | ------------- 51 | 52 | .. code-block:: bash 53 | 54 | $ sudo loginctl enable-linger $USER 55 | $ mkdir -p ~/.config/systemd/user/ 56 | 57 | # allow journalctl --user -xe -f --all 58 | $ vim /etc/systemd/journald.conf 59 | 60 | [Journal] 61 | Storage=persistent 62 | 63 | # move app.service to ~/.config/systemd/user/ 64 | $ systemctl --user start app.service 65 | 66 | Service Unit 67 | ------------ 68 | 69 | .. code-block:: bash 70 | 71 | # app.service 72 | # 73 | # $ systemctl enable app.service 74 | # $ systemctl start app.service 75 | # $ systemctl status app.service 76 | 77 | [Unit] 78 | Description=Run an application 79 | 80 | [Service] 81 | Type=simple 82 | Restart=always 83 | RestartSec=30 84 | WorkingDirectory=/path/to/app 85 | ExecStart=/bin/bash run.sh 86 | 87 | [Install] 88 | WantedBy=multi-user.target 89 | 90 | Timer Unit 91 | ---------- 92 | 93 | .. code-block:: bash 94 | 95 | # job.timer 96 | # 97 | # $ systemctl enable job.timer 98 | # $ systemctl start job.timer 99 | # $ systemctl list-timers 100 | 101 | [Unit] 102 | Description=Run a timer 103 | 104 | [Timer] 105 | OnBootSec=10min 106 | OnUnitActiveSec=1m 107 | Unit=job.service 108 | 109 | [Install] 110 | WantedBy=multi-user.target 111 | 112 | .. code-block:: bash 113 | 114 | # job.service 115 | 116 | [Unit] 117 | Description=Run a job 118 | 119 | [Service] 120 | Type=oneshot 121 | WorkingDirectory=/path/to/job/folder 122 | ExecStart=/bin/bash run.sh 123 | 124 | [Install] 125 | WantedBy=multi-user.target 126 | 127 | 128 | 129 | .. code-block:: 130 | 131 | Minimal form Normalized form 132 | Sat,Thu,Mon..Wed,Sat..Sun → Mon..Thu,Sat,Sun *-*-* 00:00:00 133 | Mon,Sun 12-*-* 2,1:23 → Mon,Sun 2012-*-* 01,02:23:00 134 | Wed *-1 → Wed *-*-01 00:00:00 135 | Wed..Wed,Wed *-1 → Wed *-*-01 00:00:00 136 | Wed, 17:48 → Wed *-*-* 17:48:00 137 | Wed..Sat,Tue 12-10-15 1:2:3 → Tue..Sat 2012-10-15 01:02:03 138 | *-*-7 0:0:0 → *-*-07 00:00:00 139 | 10-15 → *-10-15 00:00:00 140 | monday *-12-* 17:00 → Mon *-12-* 17:00:00 141 | Mon,Fri *-*-3,1,2 *:30:45 → Mon,Fri *-*-01,02,03 *:30:45 142 | 12,14,13,12:20,10,30 → *-*-* 12,13,14:10,20,30:00 143 | 12..14:10,20,30 → *-*-* 12..14:10,20,30:00 144 | mon,fri *-1/2-1,3 *:30:45 → Mon,Fri *-01/2-01,03 *:30:45 145 | 03-05 08:05:40 → *-03-05 08:05:40 146 | 08:05:40 → *-*-* 08:05:40 147 | 05:40 → *-*-* 05:40:00 148 | Sat,Sun 12-05 08:05:40 → Sat,Sun *-12-05 08:05:40 149 | Sat,Sun 08:05:40 → Sat,Sun *-*-* 08:05:40 150 | 2003-03-05 05:40 → 2003-03-05 05:40:00 151 | 05:40:23.4200004/3.1700005 → *-*-* 05:40:23.420000/3.170001 152 | 2003-02..04-05 → 2003-02..04-05 00:00:00 153 | 2003-03-05 05:40 UTC → 2003-03-05 05:40:00 UTC 154 | 2003-03-05 → 2003-03-05 00:00:00 155 | 03-05 → *-03-05 00:00:00 156 | hourly → *-*-* *:00:00 157 | daily → *-*-* 00:00:00 158 | daily UTC → *-*-* 00:00:00 UTC 159 | monthly → *-*-01 00:00:00 160 | weekly → Mon *-*-* 00:00:00 161 | weekly Pacific/Auckland → Mon *-*-* 00:00:00 Pacific/Auckland 162 | yearly → *-01-01 00:00:00 163 | annually → *-01-01 00:00:00 164 | *:2/3 → *-*-* *:02/3:00 165 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | bandit==1.7.2 2 | coverage==6.5.0 3 | coveralls==3.3.1 4 | Flask==2.1.3 5 | Flask-SSLify==0.1.5 6 | Flask-Testing==0.8.1 7 | Flask-SeaSurf==1.1.1 8 | flask-talisman==1.0.0 9 | gunicorn==21.2.0 10 | pycodestyle==2.11.0 11 | pydocstyle==6.3.0 12 | requests==2.31.0 13 | Sphinx==7.1.2 14 | Werkzeug==2.3.4 15 | -------------------------------------------------------------------------------- /runtime.txt: -------------------------------------------------------------------------------- 1 | python-3.10.5 2 | --------------------------------------------------------------------------------