diff --git a/animation/forwarding_references/.gitignore b/animation/forwarding_references/.gitignore new file mode 100644 index 0000000..829b1c7 --- /dev/null +++ b/animation/forwarding_references/.gitignore @@ -0,0 +1,15 @@ +# Generated files +node_modules +output +dist + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/animation/forwarding_references/package-lock.json b/animation/forwarding_references/package-lock.json new file mode 100644 index 0000000..4959bff --- /dev/null +++ b/animation/forwarding_references/package-lock.json @@ -0,0 +1,1366 @@ +{ + "name": "class_templates_why", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "class_templates_why", + "version": "0.0.0", + "dependencies": { + "@lezer/cpp": "^1.1.2", + "@motion-canvas/2d": "^3.16.0", + "@motion-canvas/core": "^3.16.0", + "@motion-canvas/ffmpeg": "^1.1.0" + }, + "devDependencies": { + "@motion-canvas/ui": "^3.16.0", + "@motion-canvas/vite-plugin": "^3.15.1", + "typescript": "^5.2.2", + "vite": "^4.0.0" + } + }, + "node_modules/@codemirror/language": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.1.tgz", + "integrity": "sha512-5GrXzrhq6k+gL5fjkAwt90nYDmjlzTIJV8THnxNFtNKWotMIlzzN+CpqxqwXOECnUdOndmSeWntVrVcv5axWRQ==", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.23.0", + "@lezer/common": "^1.1.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0", + "style-mod": "^4.0.0" + } + }, + "node_modules/@codemirror/state": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.4.1.tgz", + "integrity": "sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==" + }, + "node_modules/@codemirror/view": { + "version": "6.26.3", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.26.3.tgz", + "integrity": "sha512-gmqxkPALZjkgSxIeeweY/wGQXBfwTUaLs8h7OKtSwfbj9Ct3L11lD+u1sS7XHppxFQoMDiMDp07P9f3I2jWOHw==", + "dependencies": { + "@codemirror/state": "^6.4.0", + "style-mod": "^4.1.0", + "w3c-keyname": "^2.2.4" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@ffmpeg-installer/darwin-arm64": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@ffmpeg-installer/darwin-arm64/-/darwin-arm64-4.1.5.tgz", + "integrity": "sha512-hYqTiP63mXz7wSQfuqfFwfLOfwwFChUedeCVKkBtl/cliaTM7/ePI9bVzfZ2c+dWu3TqCwLDRWNSJ5pqZl8otA==", + "cpu": [ + "arm64" + ], + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@ffmpeg-installer/darwin-x64": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@ffmpeg-installer/darwin-x64/-/darwin-x64-4.1.0.tgz", + "integrity": "sha512-Z4EyG3cIFjdhlY8wI9aLUXuH8nVt7E9SlMVZtWvSPnm2sm37/yC2CwjUzyCQbJbySnef1tQwGG2Sx+uWhd9IAw==", + "cpu": [ + "x64" + ], + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@ffmpeg-installer/ffmpeg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@ffmpeg-installer/ffmpeg/-/ffmpeg-1.1.0.tgz", + "integrity": "sha512-Uq4rmwkdGxIa9A6Bd/VqqYbT7zqh1GrT5/rFwCwKM70b42W5gIjWeVETq6SdcL0zXqDtY081Ws/iJWhr1+xvQg==", + "optionalDependencies": { + "@ffmpeg-installer/darwin-arm64": "4.1.5", + "@ffmpeg-installer/darwin-x64": "4.1.0", + "@ffmpeg-installer/linux-arm": "4.1.3", + "@ffmpeg-installer/linux-arm64": "4.1.4", + "@ffmpeg-installer/linux-ia32": "4.1.0", + "@ffmpeg-installer/linux-x64": "4.1.0", + "@ffmpeg-installer/win32-ia32": "4.1.0", + "@ffmpeg-installer/win32-x64": "4.1.0" + } + }, + "node_modules/@ffmpeg-installer/linux-arm": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@ffmpeg-installer/linux-arm/-/linux-arm-4.1.3.tgz", + "integrity": "sha512-NDf5V6l8AfzZ8WzUGZ5mV8O/xMzRag2ETR6+TlGIsMHp81agx51cqpPItXPib/nAZYmo55Bl2L6/WOMI3A5YRg==", + "cpu": [ + "arm" + ], + "hasInstallScript": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@ffmpeg-installer/linux-arm64": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@ffmpeg-installer/linux-arm64/-/linux-arm64-4.1.4.tgz", + "integrity": "sha512-dljEqAOD0oIM6O6DxBW9US/FkvqvQwgJ2lGHOwHDDwu/pX8+V0YsDL1xqHbj1DMX/+nP9rxw7G7gcUvGspSoKg==", + "cpu": [ + "arm64" + ], + "hasInstallScript": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@ffmpeg-installer/linux-ia32": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@ffmpeg-installer/linux-ia32/-/linux-ia32-4.1.0.tgz", + "integrity": "sha512-0LWyFQnPf+Ij9GQGD034hS6A90URNu9HCtQ5cTqo5MxOEc7Rd8gLXrJvn++UmxhU0J5RyRE9KRYstdCVUjkNOQ==", + "cpu": [ + "ia32" + ], + "hasInstallScript": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@ffmpeg-installer/linux-x64": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@ffmpeg-installer/linux-x64/-/linux-x64-4.1.0.tgz", + "integrity": "sha512-Y5BWhGLU/WpQjOArNIgXD3z5mxxdV8c41C+U15nsE5yF8tVcdCGet5zPs5Zy3Ta6bU7haGpIzryutqCGQA/W8A==", + "cpu": [ + "x64" + ], + "hasInstallScript": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@ffmpeg-installer/win32-ia32": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@ffmpeg-installer/win32-ia32/-/win32-ia32-4.1.0.tgz", + "integrity": "sha512-FV2D7RlaZv/lrtdhaQ4oETwoFUsUjlUiasiZLDxhEUPdNDWcH1OU9K1xTvqz+OXLdsmYelUDuBS/zkMOTtlUAw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@ffmpeg-installer/win32-x64": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@ffmpeg-installer/win32-x64/-/win32-x64-4.1.0.tgz", + "integrity": "sha512-Drt5u2vzDnIONf4ZEkKtFlbvwj6rI3kxw1Ck9fpudmtgaZIHD4ucsWB2lCZBXRxJgXR+2IMSti+4rtM4C4rXgg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@ffprobe-installer/darwin-arm64": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@ffprobe-installer/darwin-arm64/-/darwin-arm64-5.0.1.tgz", + "integrity": "sha512-vwNCNjokH8hfkbl6m95zICHwkSzhEvDC3GVBcUp5HX8+4wsX10SP3B+bGur7XUzTIZ4cQpgJmEIAx6TUwRepMg==", + "cpu": [ + "arm64" + ], + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@ffprobe-installer/darwin-x64": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@ffprobe-installer/darwin-x64/-/darwin-x64-5.1.0.tgz", + "integrity": "sha512-J+YGscZMpQclFg31O4cfVRGmDpkVsQ2fZujoUdMAAYcP0NtqpC49Hs3SWJpBdsGB4VeqOt5TTm1vSZQzs1NkhA==", + "cpu": [ + "x64" + ], + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@ffprobe-installer/ffprobe": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@ffprobe-installer/ffprobe/-/ffprobe-2.1.2.tgz", + "integrity": "sha512-ZNvwk4f2magF42Zji2Ese16SMj9BS7Fui4kRjg6gTYTxY3gWZNpg85n4MIfQyI9nimHg4x/gT6FVkp/bBDuBwg==", + "engines": { + "node": ">=14.21.2" + }, + "optionalDependencies": { + "@ffprobe-installer/darwin-arm64": "5.0.1", + "@ffprobe-installer/darwin-x64": "5.1.0", + "@ffprobe-installer/linux-arm": "5.2.0", + "@ffprobe-installer/linux-arm64": "5.2.0", + "@ffprobe-installer/linux-ia32": "5.2.0", + "@ffprobe-installer/linux-x64": "5.2.0", + "@ffprobe-installer/win32-ia32": "5.1.0", + "@ffprobe-installer/win32-x64": "5.1.0" + } + }, + "node_modules/@ffprobe-installer/linux-arm": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@ffprobe-installer/linux-arm/-/linux-arm-5.2.0.tgz", + "integrity": "sha512-PF5HqEhCY7WTWHtLDYbA/+rLS+rhslWvyBlAG1Fk8VzVlnRdl93o6hy7DE2kJgxWQbFaR3ZktPQGEzfkrmQHvQ==", + "cpu": [ + "arm" + ], + "hasInstallScript": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@ffprobe-installer/linux-arm64": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@ffprobe-installer/linux-arm64/-/linux-arm64-5.2.0.tgz", + "integrity": "sha512-X1VvWtlLs6ScP73biVLuHD5ohKJKsMTa0vafCESOen4mOoNeLAYbxOVxDWAdFz9cpZgRiloFj5QD6nDj8E28yQ==", + "cpu": [ + "arm64" + ], + "hasInstallScript": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@ffprobe-installer/linux-ia32": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@ffprobe-installer/linux-ia32/-/linux-ia32-5.2.0.tgz", + "integrity": "sha512-TFVK5sasXyXhbIG7LtPRDmtkrkOsInwKcL43iEvEw+D9vCS2rc//mn9/0Q+BR0UoJEiMK4+ApYr/3LLVUBPOCQ==", + "cpu": [ + "ia32" + ], + "hasInstallScript": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@ffprobe-installer/linux-x64": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@ffprobe-installer/linux-x64/-/linux-x64-5.2.0.tgz", + "integrity": "sha512-D3UeqTLYPNs7pBWPLUYGehPdRVqU8eACox4OZy3pZUZatxye2YKlvBwEfaLdL1v2Z4FOAlLUhms0kY8m8kqSRA==", + "cpu": [ + "x64" + ], + "hasInstallScript": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@ffprobe-installer/win32-ia32": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@ffprobe-installer/win32-ia32/-/win32-ia32-5.1.0.tgz", + "integrity": "sha512-5O3vOoNRxmut0/Nu9vSazTdSHasrr+zPT2B3Hm7kjmO3QVFcIfVImS6ReQnZeSy8JPJOqXts5kX5x/3KOX54XQ==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@ffprobe-installer/win32-x64": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@ffprobe-installer/win32-x64/-/win32-x64-5.1.0.tgz", + "integrity": "sha512-jMGYeAgkrdn4e2vvYt/qakgHRE3CPju4bn5TmdPfoAm1BlX1mY9cyMd8gf5vSzI8gH8Zq5WQAyAkmekX/8TSTg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@lezer/common": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.1.tgz", + "integrity": "sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ==" + }, + "node_modules/@lezer/cpp": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@lezer/cpp/-/cpp-1.1.2.tgz", + "integrity": "sha512-macwKtyeUO0EW86r3xWQCzOV9/CF8imJLpJlPv3sDY57cPGeUZ8gXWOWNlJr52TVByMV3PayFQCA5SHEERDmVQ==", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/highlight": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.0.tgz", + "integrity": "sha512-WrS5Mw51sGrpqjlh3d4/fOwpEV2Hd3YOkp9DBt4k8XZQcoTHZFB7sx030A6OcahF4J1nDQAa3jXlTVVYH50IFA==", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@lezer/lr": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.0.tgz", + "integrity": "sha512-Wst46p51km8gH0ZUmeNrtpRYmdlRHUpN1DQd3GFAyKANi8WVz8c2jHYTf1CVScFaCjQw1iO3ZZdqGDxQPRErTg==", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@motion-canvas/2d": { + "version": "3.16.0", + "resolved": "https://registry.npmjs.org/@motion-canvas/2d/-/2d-3.16.0.tgz", + "integrity": "sha512-8vyCSNE9ZCkGB4Wz8yS48h0xQ79mbmbCkhpxu4ARBrFtSVLqgo/6kz2yifJi4wPK4pCDFw5knABjukOKtMaPMQ==", + "dependencies": { + "@codemirror/language": "^6.10.1", + "@lezer/common": "^1.2.1", + "@lezer/highlight": "^1.2.0", + "@motion-canvas/core": "^3.16.0", + "code-fns": "^0.8.2", + "mathjax-full": "^3.2.2", + "parse-svg-path": "^0.1.2" + } + }, + "node_modules/@motion-canvas/core": { + "version": "3.16.0", + "resolved": "https://registry.npmjs.org/@motion-canvas/core/-/core-3.16.0.tgz", + "integrity": "sha512-egOrQjVOHWf+HMFH+AOLLSV/djf+YGGPxbz0Jbnva3C3VTH2l6MMKTdoYyGRI3w02gJO1pIo7bcePq3erlxulw==", + "dependencies": { + "@types/chroma-js": "^2.1.4", + "chroma-js": "^2.4.2" + } + }, + "node_modules/@motion-canvas/ffmpeg": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@motion-canvas/ffmpeg/-/ffmpeg-1.1.1.tgz", + "integrity": "sha512-w2d7oFfR3hYHXeYtFGoHp6goY+vVL0LoZ2h1b/veTH5KvE7jrLp2Kl/XPHsYJ5ZDRHUT0Nhl05DBLdXYqdSqgg==", + "dependencies": { + "@ffmpeg-installer/ffmpeg": "^1.1.0", + "@ffprobe-installer/ffprobe": "^2.0.0", + "fluent-ffmpeg": "^2.1.2" + }, + "peerDependencies": { + "@motion-canvas/core": "^3.7.0", + "@motion-canvas/vite-plugin": "^3.7.0", + "vite": "4.x" + } + }, + "node_modules/@motion-canvas/ui": { + "version": "3.16.0", + "resolved": "https://registry.npmjs.org/@motion-canvas/ui/-/ui-3.16.0.tgz", + "integrity": "sha512-PJZnbkiJKED4nNDnN649zojfPMVRTvFOqxUExi6TdrckiLFsTJFy+dYbyMML223ekDrkmHuQU35tcs3svwfYrw==", + "dev": true, + "dependencies": { + "@motion-canvas/core": "^3.16.0", + "@preact/signals": "^1.2.1", + "preact": "^10.19.2" + } + }, + "node_modules/@motion-canvas/vite-plugin": { + "version": "3.15.1", + "resolved": "https://registry.npmjs.org/@motion-canvas/vite-plugin/-/vite-plugin-3.15.1.tgz", + "integrity": "sha512-yeRMJQxTcYVZGVMnNXQPm0SySQzJXnaRrggGJ2bnDHMsqxCRJt/RfIioK0LMvBaUB+UWlPsJUTMltHuq+J64JA==", + "dependencies": { + "fast-glob": "^3.3.1", + "follow-redirects": "^1.15.2", + "mime-types": "^2.1.35", + "source-map": "^0.6.1" + }, + "peerDependencies": { + "vite": "4.x || 5.x" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@preact/signals": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@preact/signals/-/signals-1.2.3.tgz", + "integrity": "sha512-M2DXse3Wi8HwjI1d2vQWOLJ3lHogvqTsJYvl4ofXRXgMFQzJ7kmlZvlt5i8x5S5VwgZu0ghru4HkLqOoFfU2JQ==", + "dev": true, + "dependencies": { + "@preact/signals-core": "^1.6.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + }, + "peerDependencies": { + "preact": "10.x" + } + }, + "node_modules/@preact/signals-core": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@preact/signals-core/-/signals-core-1.6.0.tgz", + "integrity": "sha512-O/XGxwP85h1F7+ouqTMOIZ3+V1whfaV9ToIVcuyGriD4JkSD00cQo54BKdqjvBJxbenvp7ynfqRHEwI6e+NIhw==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/@types/chroma-js": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/chroma-js/-/chroma-js-2.4.4.tgz", + "integrity": "sha512-/DTccpHTaKomqussrn+ciEvfW4k6NAHzNzs/sts1TCqg333qNxOhy8TNIoQCmbGG3Tl8KdEhkGAssb1n3mTXiQ==" + }, + "node_modules/@types/hast": { + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz", + "integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==", + "dependencies": { + "@types/unist": "^2" + } + }, + "node_modules/@types/unist": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", + "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==" + }, + "node_modules/@wooorm/starry-night": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@wooorm/starry-night/-/starry-night-1.7.0.tgz", + "integrity": "sha512-ktO0nkddrovIoNW2jAUT+Cdd9n1bWjy1Ir4CdcmgTaT6E94HLlQfu7Yv62falclBEwvsuVp3bSBw23wtta1fNw==", + "dependencies": { + "@types/hast": "^2.0.0", + "import-meta-resolve": "^2.0.0", + "vscode-oniguruma": "^1.0.0", + "vscode-textmate": "^9.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chroma-js": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.4.2.tgz", + "integrity": "sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A==" + }, + "node_modules/code-fns": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/code-fns/-/code-fns-0.8.2.tgz", + "integrity": "sha512-3VVeq3cnWxWiWKFLsVo+XWsOXBSW2gAx2uv0ViETLNmNuygEPHlCeDAv/Zy7xXqPgXtgLZyvIJZmx+ojTgOIGA==", + "dependencies": { + "@wooorm/starry-night": "^1.2.0" + } + }, + "node_modules/commander": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.2.0.tgz", + "integrity": "sha512-e2i4wANQiSXgnrBlIatyHtP1odfUp0BbV5Y5nEGbxtIrStkEOAAzCUirvLBNXHLr7kwLvJl6V+4V3XV9x7Wd9w==", + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/esbuild": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" + } + }, + "node_modules/esm": { + "version": "3.2.25", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fluent-ffmpeg": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fluent-ffmpeg/-/fluent-ffmpeg-2.1.2.tgz", + "integrity": "sha512-IZTB4kq5GK0DPp7sGQ0q/BWurGHffRtQQwVkiqDgeO6wYJLLV5ZhgNOQ65loZxxuPMKZKZcICCUnaGtlxBiR0Q==", + "dependencies": { + "async": ">=0.2.9", + "which": "^1.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/import-meta-resolve": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-2.2.2.tgz", + "integrity": "sha512-f8KcQ1D80V7RnqVm+/lirO9zkOxjGxhaTC1IPrBGd3MEfNgmNG67tSUO9gTi2F3Blr2Az6g1vocaxzkVnWl9MA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/mathjax-full": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/mathjax-full/-/mathjax-full-3.2.2.tgz", + "integrity": "sha512-+LfG9Fik+OuI8SLwsiR02IVdjcnRCy5MufYLi0C3TdMT56L/pjB0alMVGgoWJF8pN9Rc7FESycZB9BMNWIid5w==", + "dependencies": { + "esm": "^3.2.25", + "mhchemparser": "^4.1.0", + "mj-context-menu": "^0.6.1", + "speech-rule-engine": "^4.0.6" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/mhchemparser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/mhchemparser/-/mhchemparser-4.2.1.tgz", + "integrity": "sha512-kYmyrCirqJf3zZ9t/0wGgRZ4/ZJw//VwaRVGA75C4nhE60vtnIzhl9J9ndkX/h6hxSN7pjg/cE0VxbnNM+bnDQ==" + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mj-context-menu": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/mj-context-menu/-/mj-context-menu-0.6.1.tgz", + "integrity": "sha512-7NO5s6n10TIV96d4g2uDpG7ZDpIhMh0QNfGdJw/W47JswFcosz457wqz/b5sAKvl12sxINGFCn80NZHKwxQEXA==" + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/parse-svg-path": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/parse-svg-path/-/parse-svg-path-0.1.2.tgz", + "integrity": "sha512-JyPSBnkTJ0AI8GGJLfMXvKq42cj5c006fnLz6fXy6zfoVjJizi8BNTpu8on8ziI1cKy9d9DGNuY17Ce7wuejpQ==" + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/preact": { + "version": "10.21.0", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.21.0.tgz", + "integrity": "sha512-aQAIxtzWEwH8ou+OovWVSVNlFImL7xUCwJX3YMqA3U8iKCNC34999fFOnWjYNsylgfPgMexpbk7WYOLtKr/mxg==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/speech-rule-engine": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/speech-rule-engine/-/speech-rule-engine-4.0.7.tgz", + "integrity": "sha512-sJrL3/wHzNwJRLBdf6CjJWIlxC04iYKkyXvYSVsWVOiC2DSkHmxsqOhEeMsBA9XK+CHuNcsdkbFDnoUfAsmp9g==", + "dependencies": { + "commander": "9.2.0", + "wicked-good-xpath": "1.3.0", + "xmldom-sre": "0.1.31" + }, + "bin": { + "sre": "bin/sre" + } + }, + "node_modules/style-mod": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz", + "integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/vite": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.3.tgz", + "integrity": "sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==", + "dependencies": { + "esbuild": "^0.18.10", + "postcss": "^8.4.27", + "rollup": "^3.27.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vscode-oniguruma": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", + "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==" + }, + "node_modules/vscode-textmate": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-9.0.0.tgz", + "integrity": "sha512-Cl65diFGxz7gpwbav10HqiY/eVYTO1sjQpmRmV991Bj7wAoOAjGQ97PpQcXorDE2Uc4hnGWLY17xme+5t6MlSg==" + }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==" + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/wicked-good-xpath": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/wicked-good-xpath/-/wicked-good-xpath-1.3.0.tgz", + "integrity": "sha512-Gd9+TUn5nXdwj/hFsPVx5cuHHiF5Bwuc30jZ4+ronF1qHK5O7HD0sgmXWSEgwKquT3ClLoKPVbO6qGwVwLzvAw==" + }, + "node_modules/xmldom-sre": { + "version": "0.1.31", + "resolved": "https://registry.npmjs.org/xmldom-sre/-/xmldom-sre-0.1.31.tgz", + "integrity": "sha512-f9s+fUkX04BxQf+7mMWAp5zk61pciie+fFLC9hX9UVvCeJQfNHRHXpeo5MPcR0EUf57PYLdt+ZO4f3Ipk2oZUw==", + "engines": { + "node": ">=0.1" + } + } + } +} diff --git a/animation/forwarding_references/package.json b/animation/forwarding_references/package.json new file mode 100644 index 0000000..88b8e4d --- /dev/null +++ b/animation/forwarding_references/package.json @@ -0,0 +1,22 @@ +{ + "name": "class_templates_why", + "private": true, + "version": "0.0.0", + "scripts": { + "start": "vite", + "serve": "vite", + "build": "tsc && vite build" + }, + "dependencies": { + "@lezer/cpp": "^1.1.2", + "@motion-canvas/2d": "^3.16.0", + "@motion-canvas/core": "^3.16.0", + "@motion-canvas/ffmpeg": "^1.1.0" + }, + "devDependencies": { + "@motion-canvas/ui": "^3.16.0", + "@motion-canvas/vite-plugin": "^3.15.1", + "typescript": "^5.2.2", + "vite": "^4.0.0" + } +} diff --git a/animation/forwarding_references/src/functions/functions.tsx b/animation/forwarding_references/src/functions/functions.tsx new file mode 100644 index 0000000..458fb31 --- /dev/null +++ b/animation/forwarding_references/src/functions/functions.tsx @@ -0,0 +1,64 @@ +import { + CodeModification, +} from '@motion-canvas/2d/lib/components/CodeBlock'; + +const store = (...args: [TemplateStringsArray, ...any]) => args; + +function to_string([strings, ...values]: [TemplateStringsArray, ...any]): string { + return strings.reduce((acc, str, i) => { + const value = values[i] ?? ''; + return acc + str + value; + }, ''); +} + +function append( + template_1: TemplateStringsArray, args_1: string[], + template_2: TemplateStringsArray, args_2: string[]): [TemplateStringsArray, ...string[]] { + let new_template = Array.from<string>(template_1); + let new_args: Array<string> = args_1; + new_template[template_1.length - 1] += template_2[0] + new_template = new_template.concat(template_2.slice(1)) + new_args = new_args.concat(args_2) + return [new_template as unknown as TemplateStringsArray, ...new_args]; +} + +const isCodeModification = (code: any): code is CodeModification => (code as CodeModification).from !== undefined; + +function simplify( + args_in: [TemplateStringsArray, ...any]): [TemplateStringsArray, ...string[]] { + const template = args_in[0] + const args = args_in.slice(1) + if (args.every((arg) => (typeof (arg) == "string") || isCodeModification(arg))) { + return args_in + } + let new_template: Array<any> = []; + let new_args: Array<any> = []; + let concatenate = false; + for (let i = 0; i <= args.length; i++) { + if (concatenate) { + concatenate = false; + new_template[new_template.length - 1] += template[i]; + } else { + new_template.push(template[i]); + } + if (i == args.length) { break; } + if (typeof (args[i]) == "string" || isCodeModification(args[i])) { + new_args.push(args[i]) + continue; + } + let simplified_arg = simplify(args[i]); + let simplified_template = simplified_arg[0] + let simplified_args = simplified_arg.slice(1) + const appended = append( + new_template as unknown as TemplateStringsArray, + new_args, + simplified_template, + simplified_args as string[]); + new_template = Array.from<string>(appended[0]) + new_args = appended.slice(1) + concatenate = true; + } + return [new_template as unknown as TemplateStringsArray, ...new_args] +} + +export {store, simplify, to_string}; diff --git a/animation/forwarding_references/src/global.css b/animation/forwarding_references/src/global.css new file mode 100644 index 0000000..201f5ff --- /dev/null +++ b/animation/forwarding_references/src/global.css @@ -0,0 +1 @@ +@import url('https://fonts.googleapis.com/css2?family=Fira+Mono:wght@400;500;700&display=swap'); diff --git a/animation/forwarding_references/src/motion-canvas.d.ts b/animation/forwarding_references/src/motion-canvas.d.ts new file mode 100644 index 0000000..067c6a4 --- /dev/null +++ b/animation/forwarding_references/src/motion-canvas.d.ts @@ -0,0 +1 @@ +/// <reference types="@motion-canvas/core/project" /> diff --git a/animation/forwarding_references/src/project.meta b/animation/forwarding_references/src/project.meta new file mode 100644 index 0000000..5f34ffe --- /dev/null +++ b/animation/forwarding_references/src/project.meta @@ -0,0 +1,31 @@ +{ + "version": 0, + "shared": { + "background": "rgb(10,15,20)", + "range": [ + 0, + null + ], + "size": { + "x": 1920, + "y": 1080 + }, + "audioOffset": 0 + }, + "preview": { + "fps": 30, + "resolutionScale": 2 + }, + "rendering": { + "fps": 30, + "resolutionScale": 1, + "colorSpace": "srgb", + "exporter": { + "name": "@motion-canvas/ffmpeg", + "options": { + "fastStart": true, + "includeAudio": true + } + } + } +} \ No newline at end of file diff --git a/animation/forwarding_references/src/project.ts b/animation/forwarding_references/src/project.ts new file mode 100644 index 0000000..82ee0bd --- /dev/null +++ b/animation/forwarding_references/src/project.ts @@ -0,0 +1,36 @@ +import { makeProject } from '@motion-canvas/core'; +import { Code, LezerHighlighter } from '@motion-canvas/2d'; +import { parser } from '@lezer/cpp'; +import { tags } from '@lezer/highlight'; +import { HighlightStyle } from '@codemirror/language'; + +const MyStyle = HighlightStyle.define([ + { tag: tags.keyword, color: '#569CD6' }, // VSCode Keyword color + { tag: tags.controlKeyword, color: '#C586C0' }, // VSCode Control Keyword color + { tag: tags.operatorKeyword, color: '#C586C0' }, // VSCode Control Keyword color + { tag: tags.comment, color: 'gray' }, // VSCode Comment color + { tag: tags.className, color: '#4EC9B0' }, // VSCode Class Name color + { tag: tags.constant(tags.variableName), color: '#B5CEA8' }, // VSCode Constant color + { tag: tags.function(tags.variableName), color: '#DCDCAA' }, // VSCode Function color + { tag: tags.function(tags.propertyName), color: '#DCDCAA' }, // VSCode Function color + // { tag: tags.propertyName, color: '#DCDCAA' }, // VSCode Function color + { tag: tags.number, color: '#B5CEA8' }, // VSCode Number color + { tag: tags.string, color: '#CE9178' }, // VSCode String color + { tag: tags.typeName, color: '#4EC9B0' }, // VSCode Type Name color + { tag: tags.squareBracket, color: '#C586C0' }, // VSCode Square Bracket color + { tag: tags.bracket, color: '#C586C0' }, // VSCode Bracket color + { tag: tags.brace, color: '#DDDD22' }, // VSCode Brace color + { tag: tags.processingInstruction, color: '#C586C0' }, // VSCode Brace color + { tag: tags.arithmeticOperator, color: '#D16969' }, // VSCode Arithmetic Operator color +]); + +Code.defaultHighlighter = new LezerHighlighter(parser, MyStyle); + +import './global.css'; + +import example from './scenes/example?scene'; + + +export default makeProject({ + scenes: [example], +}); diff --git a/animation/forwarding_references/src/scenes/example.meta b/animation/forwarding_references/src/scenes/example.meta new file mode 100644 index 0000000..c31dca6 --- /dev/null +++ b/animation/forwarding_references/src/scenes/example.meta @@ -0,0 +1,5 @@ +{ + "version": 0, + "timeEvents": [], + "seed": 1820440022 +} \ No newline at end of file diff --git a/animation/forwarding_references/src/scenes/example.tsx b/animation/forwarding_references/src/scenes/example.tsx new file mode 100644 index 0000000..2a3bf2c --- /dev/null +++ b/animation/forwarding_references/src/scenes/example.tsx @@ -0,0 +1,1061 @@ +import { createRef } from '@motion-canvas/core/lib/utils'; +import { makeScene2D, Code, lines } from '@motion-canvas/2d'; +import { all, waitFor, waitUntil } from '@motion-canvas/core/lib/flow'; +import { DEFAULT } from '@motion-canvas/core/lib/signals'; +import { BBox, Vector2 } from '@motion-canvas/core/lib/types'; + +import { store, simplify } from '../functions/functions' + +export default makeScene2D(function* (view) { + const codeRef = createRef<Code>(); + + yield view.add(<Code + ref={codeRef} + fontSize={50} + fontFamily={'Fira Mono'} + fontWeight={500} + offsetX={-1} + x={-600} + />); + + + const code_move = `\ + void DoSmth(SomeType&& value);` + + + + const duration = 1.0 + + yield* codeRef().code(code_move, 0).wait(duration); + + const code_forward = `\ + template <class SomeType> + void DoSmth(SomeType&& value);` + + yield* codeRef().code(code_forward, duration).wait(duration); + + const code_forward_with_body = `\ + #include <utility> + + template <class SomeType> + void DoSmth(SomeType&& value) { + DoSmthElse(std::forward<SomeType>(value)); + }` + + yield* all( + codeRef().x(-600, duration), + codeRef().code(code_forward_with_body, duration).wait(duration) + ); + + const forwarding_code = `\ + class Container { + public: + void Put(const Data& data) { data_ = data; } + + private: + Data data_{}; + };` + + yield* all( + codeRef().code(forwarding_code, 0).wait(duration), + codeRef().fontSize(30, 0) + ); + + const forwarding_code_with_data = `\ + #include <iostream> + + // 😱 Missing other special class methods! + struct Data { + Data& operator=(const Data& other) { + std::cout << "Copy assignment" << std::endl; + return *this; + } + + Data& operator=(Data&& other) { + std::cout << "Move assignment" << std::endl; + return *this; + } + }; + + class Container { + public: + void Put(const Data& data) { data_ = data; } + + private: + Data data_{}; + };` + + yield* all( + codeRef().code(forwarding_code_with_data, duration).wait(duration) + ); + + const forwarding_code_with_data_and_main = `\ + #include <iostream> + + // 😱 Missing other special class methods! + struct Data { + Data& operator=(const Data& other) { + std::cout << "Copy assignment" << std::endl; + return *this; + } + + Data& operator=(Data&& other) { + std::cout << "Move assignment" << std::endl; + return *this; + } + }; + + class Container { + public: + void Put(const Data& data) { data_ = data; } + + private: + Data data_{}; + }; + + int main() { + Container container{}; + Data data{}; + container.Put(data); + }` + + yield* all( + codeRef().fontSize(28, duration), + codeRef().code(forwarding_code_with_data_and_main, duration).wait(duration) + ); + + yield* all( + codeRef().selection([lines(4, 7)], duration).wait(duration), + ); + + const forwarding_code_with_data_and_main_temp = `\ + #include <iostream> + + // 😱 Missing other special class methods! + struct Data { + Data& operator=(const Data& other) { + std::cout << "Copy assignment" << std::endl; + return *this; + } + + Data& operator=(Data&& other) { + std::cout << "Move assignment" << std::endl; + return *this; + } + }; + + class Container { + public: + void Put(const Data& data) { data_ = data; } + + private: + Data data_{}; + }; + + int main() { + Container container{}; + container.Put(Data{}); + }` + yield* all( + codeRef().selection(DEFAULT, 0).wait(duration), + ); + yield* all( + codeRef().selection(lines(23, 27), duration), + ); + yield* all( + codeRef().fontSize(28, duration), + codeRef().selection(lines(23, 26), duration), + codeRef().code(forwarding_code_with_data_and_main_temp, duration).wait(duration) + ); + + yield* all( + codeRef().selection([lines(23, 26), lines(4, 7)], duration).wait(duration), + ); + yield* all( + codeRef().selection([lines(23, 26), lines(4, 7), lines(17, 18)], duration).wait(duration), + ); + + const forwarding_code_with_moving_data_and_main_temp = `\ + #include <iostream> + #include <utility> + + // 😱 Missing other special class methods! + struct Data { + Data& operator=(const Data& other) { + std::cout << "Copy assignment" << std::endl; + return *this; + } + + Data& operator=(Data&& other) { + std::cout << "Move assignment" << std::endl; + return *this; + } + }; + + class Container { + public: + void Put(const Data& data) { data_ = data; } + + void Put(Data&& data) { data_ = std::move(data); } + + private: + Data data_{}; + }; + + int main() { + Container container{}; + container.Put(Data{}); + }` + + yield* all( + codeRef().selection(DEFAULT, 0).wait(duration), + ); + + yield* all( + codeRef().fontSize(28, duration), + codeRef().selection(lines(20, 21), duration), + codeRef().code(forwarding_code_with_moving_data_and_main_temp, duration).wait(duration) + ); + + yield* all( + codeRef().selection(codeRef().findAllRanges(/std::move\(data\)/g), duration).wait(duration) + ); + + const forwarding_code_with_moving_data_and_main_move = `\ + #include <iostream> + #include <utility> + + // 😱 Missing other special class methods! + struct Data { + Data& operator=(const Data& other) { + std::cout << "Copy assignment" << std::endl; + return *this; + } + + Data& operator=(Data&& other) { + std::cout << "Move assignment" << std::endl; + return *this; + } + }; + + class Container { + public: + void Put(const Data& data) { data_ = data; } + + void Put(Data&& data) { data_ = std::move(data); } + + private: + Data data_{}; + }; + + int main() { + Container container{}; + Data data{}; + container.Put(data); + container.Put(Data{}); + }` + + yield* all( + codeRef().fontSize(26, duration), + codeRef().selection(lines(25, 31), duration), + codeRef().code(forwarding_code_with_moving_data_and_main_move, duration).wait(duration) + ); + + const container_overloads_code = `\ + // Assume Data is defined in this header + #include "data.hpp" + // Needed for std::move + #include <utility> + + class Container { + public: + void Put(const Data& data) { data_ = data; } + + void Put(Data&& data) { data_ = std::move(data); } + + private: + Data data_{}; + };` + + yield* all( + codeRef().fontSize(35, 0), + codeRef().selection(DEFAULT, 0), + codeRef().code(container_overloads_code, 0).wait(duration) + ); + + const container_overloads_code_no_const = `\ + // Assume Data is defined in this header + #include "data.hpp" + // Needed for std::move + #include <utility> + + class Container { + public: + void Put(Data&& data) { data_ = std::move(data); } + + private: + Data data_{}; + };` + + yield* all( + codeRef().code(container_overloads_code_no_const, duration).wait(duration) + ); + + const container_overloads_code_template = `\ + // Assume Data is defined in this header + #include "data.hpp" + // Needed for std::move + #include <utility> + + class Container { + public: + template <typename T> + void Put(T&& data) { data_ = std::move(data); } + + private: + Data data_{}; + };` + + yield* all( + codeRef().code(container_overloads_code_template, duration).wait(duration) + ); + + const container_forward_code = `\ + // Assume Data is defined in this header + #include "data.hpp" + // Needed for std::forward + #include <utility> + + class Container { + public: + template <typename T> + void Put(T&& data) { data_ = std::forward<T>(data); } + + private: + Data data_{}; + };` + + yield* all( + codeRef().code(container_forward_code, duration).wait(duration) + ); + + const container_forward_code_with_main = `\ + // Needed for std::forward + #include <utility> + + // 😱 Missing other special class methods! + struct Data { + Data& operator=(const Data& other) { + std::cout << "Copy assignment" << std::endl; + return *this; + } + + Data& operator=(Data&& other) { + std::cout << "Move assignment" << std::endl; + return *this; + } + }; + + class Container { + public: + template <typename T> + void Put(T&& data) { data_ = std::forward<T>(data); } + + private: + Data data_{}; + }; + + int main() { + Container container{}; + Data data{}; + container.Put(data); + container.Put(Data{}); + }` + + yield* all( + codeRef().fontSize(26, duration), + codeRef().code(container_forward_code_with_main, duration).wait(duration) + ); + yield* waitFor(duration); + + + yield* all( + codeRef().fontSize(55, duration), + codeRef().y(-250, duration), + codeRef().selection(codeRef().findAllRanges(/template/g), duration).wait(duration) + ); + + yield* all( + codeRef().y(-750, duration), + codeRef().selection(lines(25, 30), duration).wait(duration) + ); + + const container_forward_code_with_main_42 = `\ + // Needed for std::forward + #include <utility> + + // 😱 Missing other special class methods! + struct Data { + Data& operator=(const Data& other) { + std::cout << "Copy assignment" << std::endl; + return *this; + } + + Data& operator=(Data&& other) { + std::cout << "Move assignment" << std::endl; + return *this; + } + }; + + class Container { + public: + template <typename T> + void Put(T&& data) { data_ = std::forward<T>(data); } + + private: + Data data_{}; + }; + + int main() { + Container container{}; + container.Put(42); // ❌ Won't compile. + }` + + yield* all( + codeRef().fontSize(55, duration), + codeRef().selection(lines(25, 28), duration), + codeRef().x(-700, duration), + codeRef().code(container_forward_code_with_main_42, duration).wait(duration) + ); + yield* waitFor(duration); + + + const container_forward_multi_param = `\ + // Assume Data is defined in this header + #include "data.hpp" + // Needed for std::forward + #include <utility> + + class Container { + public: + template <typename T, typename S> + void Put(T&& data_1, S&& data_2) { + data_1_ = std::forward<T>(data_1); + data_2_ = std::forward<S>(data_2); + } + + private: + Data data_1_{}; + Data data_2_{}; + };` + + yield* all( + codeRef().selection(DEFAULT, 0), + codeRef().y(0, 0), + codeRef().x(-800, 0), + codeRef().fontSize(40, 0), + codeRef().code(container_forward_code, 0).wait(duration) + ); + yield* all( + codeRef().code(container_forward_multi_param, duration).wait(duration) + ); + yield* all( + codeRef().selection(codeRef().findAllRanges(/Data data_\d_{};/g), duration).wait(duration) + ); + yield* all( + codeRef().selection(lines(7, 11), duration).wait(duration) + ); + + const container_forward_multi_param_with_main = `\ + // Needed for std::forward + #include <utility> + + // 😱 Missing other special class methods! + struct Data { + Data& operator=(const Data& other) { + std::cout << "Copy assignment" << std::endl; + return *this; + } + + Data& operator=(Data&& other) { + std::cout << "Move assignment" << std::endl; + return *this; + } + }; + + class Container { + public: + template <typename T, typename S> + void Put(T&& data_1, S&& data_2) { + data_1_ = std::forward<T>(data_1); + data_2_ = std::forward<S>(data_2); + } + + private: + Data data_1_{}; + Data data_2_{}; + }; + + int main() { + Container container{}; + Data data{}; + container.Put(data, Data{}); + std::cout << "-----" << std::endl; + container.Put(Data{}, data); + std::cout << "-----" << std::endl; + container.Put(Data{}, std::move(data)); + }` + + yield* all( + codeRef().selection(lines(15, Infinity), duration), + codeRef().y(-300, duration), + codeRef().x(-800, duration), + codeRef().fontSize(35, duration), + codeRef().code(container_forward_multi_param_with_main, duration).wait(duration) + ); + + yield* all( + codeRef().selection(lines(15, 27), duration), + codeRef().y(-100, duration), + codeRef().fontSize(35, duration).wait(duration), + ); + + const container_forward_multi_param_explicit_with_main = `\ + // Needed for std::forward + #include <utility> + + // 😱 Missing other special class methods! + struct Data { + Data& operator=(const Data& other) { + std::cout << "Copy assignment" << std::endl; + return *this; + } + + Data& operator=(Data&& other) { + std::cout << "Move assignment" << std::endl; + return *this; + } + }; + + class Container { + public: + void Put(Data&& data_1, Data&& data_2) { + data_1_ = std::move(data_1); + data_2_ = std::move(data_2); + } + void Put(const Data& data_1, Data&& data_2) { + data_1_ = data_1; + data_2_ = std::move(data_2); + } + void Put(Data&& data_1, const Data& data_2) { + data_1_ = std::move(data_1); + data_2_ = data_2; + } + void Put(const Data& data_1, const Data& data_2) { + data_1_ = data_1; + data_2_ = data_2; + } + + private: + Data data_1_{}; + Data data_2_{}; + }; + + int main() { + Container container{}; + Data data{}; + container.Put(data, Data{}); + std::cout << "-----" << std::endl; + container.Put(Data{}, data); + std::cout << "-----" << std::endl; + container.Put(Data{}, std::move(data)); + }` + + yield* all( + codeRef().y(-150, duration), + codeRef().selection(lines(15, 38), duration), + codeRef().fontSize(35, duration), + codeRef().code(container_forward_multi_param_explicit_with_main, duration).wait(duration) + ); + + yield* waitFor(duration); + + const forward_explained_code = `\ + #include <type_traits> + + template <class T> + T&& forward(std::remove_reference_t<T>& t) { + return static_cast<T&&>(t); + } + + template <class T> + T&& forward(std::remove_reference_t<T>&& t) { + return static_cast<T&&>(t); + }` + + yield* all( + codeRef().y(0, 0), + codeRef().selection(DEFAULT, 0), + codeRef().fontSize(50, 0), + codeRef().code(forward_explained_code, 0).wait(duration) + ); + + yield* all( + codeRef().selection(codeRef().findAllRanges(/std::remove_reference_t[\w<>&\s]*/g), duration).wait(duration) + ); + + yield* all( + codeRef().selection(codeRef().findAllRanges(/std::remove_reference_t/g), duration).wait(duration) + ); + + + const forward_explained_code_with_print = `\ + #include <iostream> + #include <type_traits> + #include <utility> + + template <class T> + T&& forward(std::remove_reference_t<T>& t) { + return static_cast<T&&>(t); + } + + template <class T> + T&& forward(std::remove_reference_t<T>&& t) { + return static_cast<T&&>(t); + } + + void Print(int&) { std::cout << "lvalue" << std::endl; } + + void Print(int&&) { std::cout << "rvalue" << std::endl; } + + template <class SomeType> + void DoSmth(SomeType&& value) { + Print(forward<SomeType>(value)); + } + + int main() { + int number{}; + DoSmth(number); // DoSmth(int&) + DoSmth(42); // DoSmth(int&&) + DoSmth(std::move(number)); // DoSmth(int&&) + }` + + yield* all( + codeRef().selection(DEFAULT, 0).wait(duration), + ); + + yield* all( + codeRef().selection(DEFAULT, duration), + codeRef().fontSize(25, duration), + codeRef().code(forward_explained_code_with_print, duration).wait(duration) + ); + + yield* all( + codeRef().fontSize(55, duration), + codeRef().y(-500, duration), + codeRef().selection([ + ...codeRef().findAllRanges(/int number.*/g), + ...codeRef().findAllRanges(/DoSmth\(number\);.*/g), + ], duration).wait(duration), + ); + + yield* all( + codeRef().selection([ + ...codeRef().findAllRanges(/int number.*/g), + ...codeRef().findAllRanges(/DoSmth\(number\);.*/g), + lines(17, 21) + ], duration).wait(duration), + ); + + + + const forward_explained_code_with_print_do_smth_explicit = `\ + #include <iostream> + #include <type_traits> + #include <utility> + + template <class T> + T&& forward(std::remove_reference_t<T>& t) { + return static_cast<T&&>(t); + } + + template <class T> + T&& forward(std::remove_reference_t<T>&& t) { + return static_cast<T&&>(t); + } + + void Print(int&) { std::cout << "lvalue" << std::endl; } + + void Print(int&&) { std::cout << "rvalue" << std::endl; } + + template <> + void DoSmth<int&>(int& && value) { + Print(forward<int&>(value)); + } + + int main() { + int number{}; + DoSmth(number); // DoSmth(int&) + DoSmth(42); // DoSmth(int&&) + DoSmth(std::move(number)); // DoSmth(int&&) + }` + + yield* all( + codeRef().fontSize(55, duration), + codeRef().y(-500, duration), + codeRef().code(forward_explained_code_with_print_do_smth_explicit, duration).wait(duration) + ); + + const forward_explained_code_with_print_do_smth_explicit_collapsed = `\ + #include <iostream> + #include <type_traits> + #include <utility> + + template <class T> + T&& forward(std::remove_reference_t<T>& t) { + return static_cast<T&&>(t); + } + + template <class T> + T&& forward(std::remove_reference_t<T>&& t) { + return static_cast<T&&>(t); + } + + void Print(int&) { std::cout << "lvalue" << std::endl; } + + void Print(int&&) { std::cout << "rvalue" << std::endl; } + + template <> + void DoSmth<int&>(int& value) { + Print(forward<int&>(value)); + } + + int main() { + int number{}; + DoSmth(number); // DoSmth(int&) + DoSmth(42); // DoSmth(int&&) + DoSmth(std::move(number)); // DoSmth(int&&) + }` + + yield* all( + codeRef().fontSize(55, duration), + codeRef().y(-500, duration), + codeRef().code(forward_explained_code_with_print_do_smth_explicit_collapsed, duration).wait(duration) + ); + + yield* all( + codeRef().fontSize(45, duration), + codeRef().y(100, duration), + codeRef().selection([lines(4, 12), ...codeRef().findAllRanges(/forward<int&>\(value\)/g)], duration).wait(duration), + ); + + const forward_explained_code_forward_explicit = `\ + #include <iostream> + #include <type_traits> + #include <utility> + + template <> + int& && forward<int&>(std::remove_reference_t<int&>& t) { + return static_cast<int& &&>(t); + } + + template <> + int& && forward<int&>(std::remove_reference_t<int&>&& t) { + return static_cast<int& &&>(t); + } + + void Print(int&) { std::cout << "lvalue" << std::endl; } + + void Print(int&&) { std::cout << "rvalue" << std::endl; } + + template <> + void DoSmth<int&>(int& value) { + Print(forward<int&>(value)); + } + + int main() { + int number{}; + DoSmth(number); // DoSmth(int&) + DoSmth(42); // DoSmth(int&&) + DoSmth(std::move(number)); // DoSmth(int&&) + }` + + + yield* all( + codeRef().code(forward_explained_code_forward_explicit, duration).wait(duration), + ); + + const forward_explained_code_forward_explicit_no_refs = `\ + #include <iostream> + #include <type_traits> + #include <utility> + + template <> + int& && forward<int&>(int& t) { + return static_cast<int& &&>(t); + } + + template <> + int& && forward<int&>(int&& t) { + return static_cast<int& &&>(t); + } + + void Print(int&) { std::cout << "lvalue" << std::endl; } + + void Print(int&&) { std::cout << "rvalue" << std::endl; } + + template <> + void DoSmth<int&>(int& value) { + Print(forward<int&>(value)); + } + + int main() { + int number{}; + DoSmth(number); // DoSmth(int&) + DoSmth(42); // DoSmth(int&&) + DoSmth(std::move(number)); // DoSmth(int&&) + }` + + + yield* all( + codeRef().selection([lines(4, 8), ...codeRef().findAllRanges(/forward<int&>\(value\)/g)], duration).wait(duration), + codeRef().code(forward_explained_code_forward_explicit_no_refs, duration).wait(duration), + ); + + const forward_explained_code_forward_explicit_no_refs_collapsed = `\ + #include <iostream> + #include <type_traits> + #include <utility> + + template <> + int& forward<int&>(int& t) { + return static_cast<int&>(t); + } + + template <> + int& forward<int&>(int&& t) { + return static_cast<int&>(t); + } + + void Print(int&) { std::cout << "lvalue" << std::endl; } + + void Print(int&&) { std::cout << "rvalue" << std::endl; } + + template <> + void DoSmth<int&>(int& value) { + Print(forward<int&>(value)); + } + + int main() { + int number{}; + DoSmth(number); // DoSmth(int&) + DoSmth(42); // DoSmth(int&&) + DoSmth(std::move(number)); // DoSmth(int&&) + }` + + + yield* all( + codeRef().selection([lines(4, 8), ...codeRef().findAllRanges(/forward<int&>\(value\)/g)], duration).wait(duration), + codeRef().code(forward_explained_code_forward_explicit_no_refs_collapsed, duration).wait(duration), + ); + + yield* all( + codeRef().selection([ + lines(4, 8), + lines(14, 15), + ...codeRef().findAllRanges(/Print\(forward<int&>\(value\)\);/g) + ], duration).wait(duration), + ); + + + // ---------------------- + yield* all( + codeRef().y(0, 0), + codeRef().selection(DEFAULT, 0), + codeRef().fontSize(25, 0), + codeRef().code(forward_explained_code_with_print, 0).wait(duration) + ); + + yield* all( + codeRef().fontSize(55, duration), + codeRef().y(-500, duration), + codeRef().selection([ + ...codeRef().findAllRanges(/int number.*/g), + ...codeRef().findAllRanges(/DoSmth\(42\);.*/g), + ...codeRef().findAllRanges(/DoSmth\(std::move\(number\)\);.*/g), + ], duration).wait(duration), + ); + + yield* all( + codeRef().selection([ + ...codeRef().findAllRanges(/int number.*/g), + ...codeRef().findAllRanges(/DoSmth\(42\);.*/g), + ...codeRef().findAllRanges(/DoSmth\(std::move\(number\)\);.*/g), + lines(17, 21) + ], duration).wait(duration), + ); + + + + const forward_explained_code_with_print_do_smth_explicit_rvalue = `\ + #include <iostream> + #include <type_traits> + #include <utility> + + template <class T> + T&& forward(std::remove_reference_t<T>& t) { + return static_cast<T&&>(t); + } + + template <class T> + T&& forward(std::remove_reference_t<T>&& t) { + return static_cast<T&&>(t); + } + + void Print(int&) { std::cout << "lvalue" << std::endl; } + + void Print(int&&) { std::cout << "rvalue" << std::endl; } + + template <> + void DoSmth<int>(int&& value) { + Print(forward<int>(value)); + } + + int main() { + int number{}; + DoSmth(number); // DoSmth(int&) + DoSmth(42); // DoSmth(int&&) + DoSmth(std::move(number)); // DoSmth(int&&) + }` + + yield* all( + codeRef().fontSize(55, duration), + codeRef().y(-500, duration), + codeRef().code(forward_explained_code_with_print_do_smth_explicit_rvalue, duration).wait(duration) + ); + + yield* all( + codeRef().fontSize(45, duration), + codeRef().y(100, duration), + codeRef().selection([ + lines(4, 12), + ...codeRef().findAllRanges(/forward<int>\(value\)/g)], duration).wait(duration), + ); + + const forward_explained_code_forward_explicit_rvalue = `\ + #include <iostream> + #include <type_traits> + #include <utility> + + template <> + int&& forward<int>(std::remove_reference_t<int>& t) { + return static_cast<int&&>(t); + } + + template <> + int&& forward<int>(std::remove_reference_t<int>&& t) { + return static_cast<int&&>(t); + } + + void Print(int&) { std::cout << "lvalue" << std::endl; } + + void Print(int&&) { std::cout << "rvalue" << std::endl; } + + template <> + void DoSmth<int>(int&& value) { + Print(forward<int>(value)); + } + + int main() { + int number{}; + DoSmth(number); // DoSmth(int&) + DoSmth(42); // DoSmth(int&&) + DoSmth(std::move(number)); // DoSmth(int&&) + }` + + + yield* all( + codeRef().code(forward_explained_code_forward_explicit_rvalue, duration).wait(duration), + ); + + const forward_explained_code_forward_explicit_no_refs_rvalue = `\ + #include <iostream> + #include <type_traits> + #include <utility> + + template <> + int&& forward<int>(int& t) { + return static_cast<int&&>(t); + } + + template <> + int&& forward<int>(int&& t) { + return static_cast<int&&>(t); + } + + void Print(int&) { std::cout << "lvalue" << std::endl; } + + void Print(int&&) { std::cout << "rvalue" << std::endl; } + + template <> + void DoSmth<int>(int&& value) { + Print(forward<int>(value)); + } + + int main() { + int number{}; + DoSmth(number); // DoSmth(int&) + DoSmth(42); // DoSmth(int&&) + DoSmth(std::move(number)); // DoSmth(int&&) + }` + + + yield* all( + codeRef().code(forward_explained_code_forward_explicit_no_refs_rvalue, duration).wait(duration), + ); + + yield* all( + codeRef().selection([ + lines(4, 8), + ...codeRef().findAllRanges(/forward<int>\(value\)/g)], duration).wait(duration), + ); + + yield* all( + codeRef().selection([ + lines(4, 8), + lines(16, 17), + ...codeRef().findAllRanges(/Print\(forward<int>\(value\)\);/g) + ], duration).wait(duration), + ); + + const forward_second_overload = `\ + #include <type_traits> + #include <utility> + + template <class T> + T&& forward(std::remove_reference_t<T>& t) { + return static_cast<T&&>(t); + } + + template <class T> + T&& forward(std::remove_reference_t<T>&& t) { + return static_cast<T&&>(t); + } + + int main() { + // We can also use std::forward here of course. + forward<int>(42); + int number{}; + forward<int>(std::move(number)); + }` + + yield* all( + codeRef().fontSize(42, duration), + codeRef().y(0, duration), + codeRef().selection(DEFAULT, duration).wait(duration), + codeRef().code(forward_second_overload, duration).wait(duration), + ); + + + yield* waitFor(duration * 3); +}); diff --git a/animation/forwarding_references/tsconfig.json b/animation/forwarding_references/tsconfig.json new file mode 100644 index 0000000..e7d5347 --- /dev/null +++ b/animation/forwarding_references/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "@motion-canvas/2d/tsconfig.project.json", + "include": ["src"] +} diff --git a/animation/forwarding_references/vite.config.ts b/animation/forwarding_references/vite.config.ts new file mode 100644 index 0000000..42d9d68 --- /dev/null +++ b/animation/forwarding_references/vite.config.ts @@ -0,0 +1,10 @@ +import {defineConfig} from 'vite'; +import motionCanvas from '@motion-canvas/vite-plugin'; +import ffmpeg from '@motion-canvas/ffmpeg'; + +export default defineConfig({ + plugins: [ + motionCanvas(), + ffmpeg(), + ], +}); diff --git a/lectures/forwarding_references.md b/lectures/forwarding_references.md new file mode 100644 index 0000000..0f26795 --- /dev/null +++ b/lectures/forwarding_references.md @@ -0,0 +1,591 @@ +**Forwarding references in modern C++** + +---- + +<p align="center"> + <a href="https://youtu.be/RW9KnqszYj4"><img src="https://img.youtube.com/vi/RW9KnqszYj4/maxresdefault.jpg" alt="Video" align="right" width=50% style="margin: 0.5rem"></a> +</p> + +- [The forwarding reference](#the-forwarding-reference) +- [Why use forwarding references](#why-use-forwarding-references) + - [Example setup](#example-setup) + - [How forwarding references simplify things](#how-forwarding-references-simplify-things) + - [When to prefer forwarding references](#when-to-prefer-forwarding-references) +- [How forwarding references work](#how-forwarding-references-work) + - [Reference collapsing](#reference-collapsing) + - [Remove reference using `std::remove_reference_t`](#remove-reference-using-stdremove_reference_t) + - [How `std::forward` works](#how-stdforward-works) + - [Passing an lvalue](#passing-an-lvalue) + - [Passing by rvalue](#passing-by-rvalue) +- [Summary](#summary) + + +By now we already know what move semantics is. We have even essentially [reinvented](move_semantics.md) it from scratch in one of the previous lectures. So we should be quite comfortable seeing functions (be it part of a class or not) that look like this: +<!-- +`CPP_SETUP_START` +struct SomeType{}; +$PLACEHOLDER +`CPP_SETUP_END` +`CPP_COPY_SNIPPET` forwarding_refs_do_smth/do_smth.cpp +`CPP_RUN_CMD` CWD:forwarding_refs_do_smth c++ -std=c++17 -c do_smth.cpp +--> +```cpp +void DoSmth(SomeType&& value); +``` +These function usually have something to do with the ownership of the parameters they receive by an rvalue reference. + +Well, now that we also talked about templates, there is one more thing we need to talk about. And it is a bit confusing at the first glance. + +🚨 You see if we add a template into the mix, `value` is **not really an rvalue reference** anymore: +<!-- +`CPP_SETUP_START` +$PLACEHOLDER +`CPP_SETUP_END` +`CPP_COPY_SNIPPET` forwarding_refs_do_smth/forward_do_smth_def.cpp +`CPP_RUN_CMD` CWD:forwarding_refs_do_smth c++ -std=c++17 -c forward_do_smth_def.cpp +--> +```cpp +template <class SomeType> +void DoSmth(SomeType&& value); +``` + +<!-- Intro --> + +## The forwarding reference +Ok, to spend you the suspense, the `value` in this example of ours is called a **"forwarding reference"** and it is usually used in combination with `std::forward` (don't worry, we'll unpack what we see here a bit later): +<!-- +`CPP_SETUP_START` +struct SomeType{}; +void DoSmthElse(SomeType&&); +$PLACEHOLDER +`CPP_SETUP_END` +`CPP_COPY_SNIPPET` forwarding_refs_do_smth/forward_do_smth.cpp +`CPP_RUN_CMD` CWD:forwarding_refs_do_smth c++ -std=c++17 -c forward_do_smth.cpp +--> +```cpp +#include <utility> + +template <class SomeType> +void DoSmth(SomeType&& value) { + DoSmthElse(std::forward<SomeType>(value)); +} +``` + +More formally, to quote [cppreference.com](https://en.cppreference.com/w/cpp/language/reference#Forwarding_references): +> Forwarding reference is a function parameter of a function template declared as rvalue reference to cv-unqualified type template parameter of that same function template. + +Sometimes you will also hear people calling it a "universal reference", a term [coined by Scott Meyers](https://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers), but I prefer the **"forwarding reference"** name as it is the one used in the standard today. If you want to learn more about it, please feel free to read [Arthur O'Dwyer's post](https://quuxplusone.github.io/blog/2022/02/02/look-what-they-need/) about this, he described it all much better than I ever could! + +## Why use forwarding references +Anyway, in the spirit of this course, before we go into talking about **how** a forwarding reference works, I really want to talk a bit about **why** it exists and what we might want to use it for. + +Long story short, just like normal rvalue references, I see forwarding references exclusively in the sense of ownership transfer. However, where a standard rvalue reference is designed to **always** transfer the ownership, a forwarding reference is designed for very generic contexts where it can **decide** if the ownership can be transferred based on the types of the input parameters. + +I realize that this statement might feel too general, so let's illustrate what I mean using small concrete examples. As always, our examples are going to be very simple, but illustrative of the concept at hand. + +### Example setup +For simplicity, let us say that we have a class `Container` that owns some `Data` and has a simple method `Put` that accepts a `const` reference to new `Data` to be put into it: + +`container.hpp` +<!-- +`CPP_SETUP_START` +$PLACEHOLDER +`CPP_SETUP_END` +`CPP_COPY_SNIPPET` forwarding_refs/container.hpp +--> +```cpp +#include "data.hpp" + +class Container { + public: + void Put(const Data& data) { data_ = data; } + + private: + Data data_{}; +}; +``` + +Our `Data` class is going to be a very simple `struct` that is able to print from its copy and move assignment operators: + +`data.hpp` +<!-- +`CPP_SETUP_START` +$PLACEHOLDER +`CPP_SETUP_END` +`CPP_COPY_SNIPPET` forwarding_refs/data.hpp +--> +```cpp +#include <iostream> + +// 😱 Missing other special class methods! +struct Data { + Data& operator=(const Data& other) { + std::cout << "Copy assignment" << std::endl; + return *this; + } + + Data& operator=(Data&& other) { + std::cout << "Move assignment" << std::endl; + return *this; + } +}; +``` +Note that to keep the code to the minimum, I omit the rest of the special functions in this struct, specifically a copy and move constructors as well as the destructor, please see the [rule of "all or nothing"](all_or_nothing.md) lecture to make sure we're on the same page why it is important to have all of those special functions. This is not too important is this particular example as we don't work with any memory or resources, but it is good to keep this knowledge up to date for the cases when we do. + +Finally, in the `main` function, we create an instance of `Data` and pass it into our container: + +`main.cpp` +<!-- +`CPP_SETUP_START` +$PLACEHOLDER +`CPP_SETUP_END` +`CPP_COPY_SNIPPET` forwarding_refs/main.cpp +`CPP_RUN_CMD` CWD:forwarding_refs c++ -std=c++17 main.cpp +--> +```cpp +#include "container.hpp" + +int main() { + Container container{}; + Data data{}; + container.Put(data); +} +``` +If we compile and run this code we will get the output `Copy assignment` which indicates that the data is copied into our container, just as we expect. + +Now let's say we don't want to create a `Data` instance in our `main` function and want to pass a temporary object to be owned by our `Container`. We can modify our `main` function every so slightly to achieve this: + +`main.cpp` +<!-- +`CPP_SETUP_START` +$PLACEHOLDER +`CPP_SETUP_END` +`CPP_COPY_SNIPPET` forwarding_refs/main_temp.cpp +`CPP_RUN_CMD` CWD:forwarding_refs c++ -std=c++17 main_temp.cpp +--> +```cpp +#include "container.hpp" + +int main() { + Container container{}; + container.Put(Data{}); +} +``` +However, if we compile and run _this_ code we get the same output that indicates that copy assignment operator was called again. Not exactly what we want! + +The reason for this is, of course, the fact that the `Put` method of our `Container` class only accepts a `const` reference to `Data`. By design a `const` reference binds to anything, so a temporary `Data` object is created, it gets bound to a `const` reference when passed into the `Put` function and its lifetime is extended for the duration of the execution of this function. Then because `data` is a `const` reference, its copy assignment operator is called to copy itself into the private `data_` field of our `Container` object. + +Now, as copying might be expensive for large objects, we might want to avoid it, so we can force the temporary `Data` object to be moved into our container instead by overloading the `Put` method for an rvalue reference: + +`container.hpp` +<!-- +`CPP_SETUP_START` +$PLACEHOLDER +`CPP_SETUP_END` +`CPP_COPY_SNIPPET` forwarding_refs/container.hpp +--> +```cpp +#include "data.hpp" + +#include <utility> + +class Container { + public: + void Put(const Data& data) { data_ = data; } + + void Put(Data&& data) { data_ = std::move(data); } + + private: + Data data_{}; +}; +``` +If this, or the fact that we have to use `std::move` on `data` here is confusing, do give the lecture about [reinventing move semantics](move_semantics.md) another go, I go in pretty detailed explanations about everything relevant to this there. + +Anyway, this does the trick and now we can have both behaviors if we need them in our `main` function: + +`main.cpp` +<!-- +`CPP_SETUP_START` +$PLACEHOLDER +`CPP_SETUP_END` +`CPP_COPY_SNIPPET` forwarding_refs/main_both.cpp +`CPP_RUN_CMD` CWD:forwarding_refs c++ -std=c++17 main_both.cpp +--> +```cpp +#include "container.hpp" + +int main() { + Container container{}; + Data data{}; + container.Put(data); + container.Put(Data{}); +} +``` +Passing the `data` variable will actually copy the data into our container, while passing a temporary will move this temporary into the container without performing a copy. + +### How forwarding references simplify things +So far we haven't really learnt anything new, have we? This is all just using the knowledge about move semantics and [function overloading](functions.md#function-overloading---writing-functions-with-the-same-names) from before. But it _is_ a necessary setup to understand **why** we might want to use forwarding references in the first place. + +In this simple case, we needed two function overloads to achieve the behavior that we wanted. Using forwarding references we only need one function instead. Let us modify our `Container` class to use forwarding references instead! + +For this, we remove the `Put` function that takes a `const` reference and make the remaining `Put` function, one that takes an rvalue reference, a function template. We then also use the template parameter `T` instead of the `Data` type in this function. Finally, we replace `std::move` with `std::forward<T>` and we have a fully functioning forwarding reference setup: + +`container.hpp` +<!-- +`CPP_SETUP_START` +$PLACEHOLDER +`CPP_SETUP_END` +`CPP_COPY_SNIPPET` forwarding_refs/container.hpp +`CPP_RUN_CMD` CWD:forwarding_refs c++ -std=c++17 main_both.cpp +--> +```cpp +#include "data.hpp" + +#include <utility> + +class Container { + public: + template <typename T> + void Put(T&& data) { data_ = std::forward<T>(data); } + + private: + Data data_{}; +}; +``` +If we compile and run this code we will still get exactly the behavior that we want: the `data` object gets copied into our container, while the temporary `Data` gets moved. So the forwarding references, and `std::forward` by extension allow us to auto-magically select if we want to copy or move an object based on the provided argument type. How neat is this? + + +### When to prefer forwarding references +So I hope it makes sense what forwarding references allow us to achieve. But it comes at a cost! We now have a `template` in the game, which means that we can now try to provide a wrong type, say `int` into our `Put` function: +<!-- +`CPP_SKIP_SNIPPET` +--> +```cpp +#include "container.hpp" + +int main() { + Container container{}; + container.Put(42); +} +``` +Which would lead to a nice compilation error of course that would tell us something about not being able to convert between `int` and an rvalue reference to `Data`: +```css +<source>: In instantiation of 'void Container::Put(DataT&&) [with DataT = int]': +<source>:31:18: required from here + 31 | container.Put(42); + | ~~~~~~~~~~~~~^~~~ +<source>:19:15: error: no match for 'operator=' (operand types are 'Data' and 'int') + 19 | data_ = std::forward<DataT>(data); + | ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~ +<source>:4:11: note: candidate: 'Data& Data::operator=(const Data&)' + 4 | Data& operator=(const Data& other) { + | ^~~~~~~~ +<source>:4:33: note: no known conversion for argument 1 from 'int' to 'const Data&' + 4 | Data& operator=(const Data& other) { + | ~~~~~~~~~~~~^~~~~ +<source>:9:11: note: candidate: 'Data& Data::operator=(Data&&)' + 9 | Data& operator=(Data&& other) { + | ^~~~~~~~ +<source>:9:28: note: no known conversion for argument 1 from 'int' to 'Data&&' + 9 | Data& operator=(Data&& other) { + | ~~~~~~~^~~~~ +``` +And while we _can_ mitigate this and improve the error message by using traits or concepts, which we already talked about before when we talked about [how to use templates with classes](templates_how_classes.md), it still complicates the code quite a bit. So is it really worth it? + +I would argue that in the situations like the one in our example, I would _not_ use forwarding references and would just add the two overloads for the `const` reference and the rvalue reference instead. The reason being arguably better readability and the fact that in some cases the compiler will actually generate more code if we use a forwarding reference as opposed to explicit overloads in this case. This is, though, very close to being just a personal preference. + +The situation changes, however, should we have more function parameters to think about. To illustrate what I'm talking about, let us modify our `Container` class a bit by adding another `Data` entry to it: + +`container.hpp` +<!-- +`CPP_SETUP_START` +$PLACEHOLDER +`CPP_SETUP_END` +`CPP_COPY_SNIPPET` forwarding_refs/container.hpp +--> +```cpp +#include "data.hpp" + +#include <utility> + +class Container { + public: + template <typename T, typename S> + void Put(T&& data_1, S&& data_2) { + data_1_ = std::forward<T>(data_1); + data_2_ = std::forward<S>(data_2); + } + + private: + Data data_1_{}; + Data data_2_{}; +}; +``` +Note what changed here. We now have two objects to store. Here, both `data_1_` and `data_2_` have the same type, but they could of course be of different types. The `Put` function now accepts two template arguments `T` and `S` as well as two forwarding references as its function arguments: `data_1` and `data_2`. + +Now, what happens if we pass various combination of lvalue and rvalue references to `Data` into our `Put` function? + +`main.cpp` +<!-- +`CPP_SETUP_START` +$PLACEHOLDER +`CPP_SETUP_END` +`CPP_COPY_SNIPPET` forwarding_refs/main_two_params.cpp +`CPP_RUN_CMD` CWD:forwarding_refs c++ -std=c++17 main_two_params.cpp +--> +```cpp +#include "container.hpp" + +int main() { + Container container{}; + Data data{}; + container.Put(data, Data{}); + std::cout << "-----" << std::endl; + container.Put(Data{}, data); + std::cout << "-----" << std::endl; + container.Put(Data{}, std::move(data)); +} +``` +I'll let you figure out the actual output from this code on your own. +<!-- And please post in the comments what you think this code will print and why! --> + +But the main thing is that in all of these cases the `Put` function will do what we want. It will move the data it can move and copy the data it cannot. And by now, if we look at our new `Put` function long enough and think about how to write the same functionality without the forwarding references, we might start understanding where exactly the forwarding references are useful. Let's see how we would write our `Put` functions without using forwarding references, shall we? + +`container.hpp` +<!-- +`CPP_SETUP_START` +$PLACEHOLDER +`CPP_SETUP_END` +`CPP_COPY_SNIPPET` forwarding_refs/container.hpp +`CPP_RUN_CMD` CWD:forwarding_refs c++ -std=c++17 main_two_params.cpp +--> +```cpp +#include "data.hpp" + +#include <utility> + +class Container { + public: + void Put(Data&& data_1, Data&& data_2) { + data_1_ = std::move(data_1); + data_2_ = std::move(data_2); + } + void Put(const Data& data_1, Data&& data_2) { + data_1_ = data_1; + data_2_ = std::move(data_2); + } + void Put(Data&& data_1, const Data& data_2) { + data_1_ = std::move(data_1); + data_2_ = data_2; + } + void Put(const Data& data_1, const Data& data_2) { + data_1_ = data_1; + data_2_ = data_2; + } + + private: + Data data_1_{}; + Data data_2_{}; +}; +``` +To achieve the same performance, we need to have an explicit overload for every combination of lvalue and rvalue references that is possible for our function parameters. Which means that we now need 4 different functions! And you can imagine now what would happen if we would have even more parameters. We didn't really talk about it just yet, but we can pass _any_ number of template parameters into a function, using variadic templates, where using forwarding references is really our only way to write the code that will behave efficiently for any input parameters. + +So, if you ask me, this is the reason why forwarding references really exist in the language. And this also warrants a rule of thumb of when they should be used. + +🚨 Slightly controversially, I would recommend to only use forwarding references when we **really know what we're doing** in very generic contexts. When we have many function parameters of different types to think of and when these said parameters might be copied or moved if their type allows for it. + +## How forwarding references work +Now that we know why we might want to use forwarding references and what they allow us to achieve, I think it is important to also talk about **how** this is done. What is the magic behind a forwarding reference being able to figure out what to do given the argument type? + +And of course, this is not magic, but just clever engineering! +Here, I'm planning to go quite deep into details, but we should be able to follow each step of the way with the knowledge we gained until this point in this course. 🤞 + +### Reference collapsing +In order to understand what happens there, we need to take a short detour through [reference collapsing](https://en.cppreference.com/w/cpp/language/reference#Reference_collapsing). This happens when we use type aliases to reference types and then use references with these type aliases. This basically leads us to effectively have many `&`s stacked together! So we need to map an arbitrary amount of `&`s onto the references that we know how to work with, the lvalue reference denoted by `&` and an rvalue reference denoted by `&&`. And the rule for reference collapsing is quite simple: + +🚨 **Rvalue reference to rvalue reference collapses to rvalue reference, all other combinations form lvalue references:** +<!-- +`CPP_SETUP_START` +$PLACEHOLDER +`CPP_SETUP_END` +`CPP_COPY_SNIPPET` ref_collapsing/main.cpp +`CPP_RUN_CMD` CWD:ref_collapsing c++ -std=c++17 -c main.cpp +--> +```cpp +#include <type_traits> + +using lref = int&; +using rref = int&&; + +static_assert(std::is_same_v<lref, int&>); +static_assert(std::is_same_v<rref, int&&>); + +static_assert(std::is_same_v<lref&, int&>); +static_assert(std::is_same_v<lref&&, int&>); + +static_assert(std::is_same_v<rref&, int&>); +static_assert(std::is_same_v<rref&&, int&&>); +``` +These `static_assert`s here check if the conditions in them are `true` at compile time. In our case, we use the trait alias [`std::is_same_v`](https://en.cppreference.com/w/cpp/types/is_same) to check if the provided types are the same. It doesn't really matter how `std::is_same_v` is implemented here as long as you trust me that it returns `true` if the types are the same :wink: + +That being said, after following the lecture on [how to write class templates](templates_how_classes.md) as well as the one on [how to use `static` with classes](static_in_classes.md) you should be able to implement such a trait on your own! +<!-- Please comment below on how you would do it! And please like this video and subscribe to my channel if you got any value out of it for yourself --> + +### Remove reference using `std::remove_reference_t` +Continuing with the topic of playing with references and type traits, we can design a type trait to remove reference from a provided type completely. Such a trait is implemented as [`std::remove_reference_t`](https://en.cppreference.com/w/cpp/types/remove_reference) in the C++ standard library. + +We can now see how it works using the `static_assert`s again: +<!-- +`CPP_SETUP_START` +$PLACEHOLDER +`CPP_SETUP_END` +`CPP_COPY_SNIPPET` remove_reference/main.cpp +`CPP_RUN_CMD` CWD:remove_reference c++ -std=c++17 -c main.cpp +--> +```cpp +#include <type_traits> + +static_assert(std::is_same_v<std::remove_reference_t<int>, int>); +static_assert(std::is_same_v<std::remove_reference_t<int&>, int>); +static_assert(std::is_same_v<std::remove_reference_t<int&&>, int>); +``` +Basically, passing any reference type through the `std::remove_reference_t` trait alias will produce the actual type behind the reference. + + +### How `std::forward` works +Armed with this knowledge let us have a precise look at `std::forward` and implement our own version of it to understand what happens under the hood better. For this, we need two overloads of our function template `forward`, one that takes an lvalue reference and one that takes an rvalue reference: +<!-- +`CPP_SETUP_START` +$PLACEHOLDER +`CPP_SETUP_END` +`CPP_COPY_SNIPPET` forward/forward.hpp +--> +```cpp +#include <type_traits> + +template <class T> +T&& forward(std::remove_reference_t<T>& t) { return static_cast<T&&>(t); } + +template <class T> +T&& forward(std::remove_reference_t<T>&& t) { return static_cast<T&&>(t); } +``` +Both overloads don't use their template type parameter directly to specify the type of their input parameter, but pass it through the `std::remove_reference_t` trait that removes any kind of reference from its input template parameter. The function then always returns the input parameter cast to an rvalue of the template type parameter `T`, or `T&&` type. This difference of the input parameter type and the return type in combination with reference collapsing that we have just discussed is what makes the magic work! + +To see it in detail, let us illustrate what happens when we pass arguments of various types into our `forward` function using the forwarding reference: +<!-- +`CPP_SETUP_START` +#include "forward.hpp" +$PLACEHOLDER +`CPP_SETUP_END` +`CPP_COPY_SNIPPET` forward/do_smth.hpp +--> +```cpp +#include <iostream> +#include <utility> + +void Print(int&) { std::cout << "lvalue" << std::endl; } +void Print(int&&) { std::cout << "rvalue" << std::endl; } + +template <class SomeType> +void DoSmth(SomeType&& value) { + // 💡 Using our custom forward here, but std::forward works the same. + Print(forward<SomeType>(value)); +} +``` +Here, we will use a simple `Print` function overloaded for lvalue and rvalue references to `int` to show what happens. We then pass a number arguments into our `DoSmth` function from `main`. + +#### Passing an lvalue +We can observe, that passing a variable `number` as an argument prints `lvalue`, which is what we expect. So let's dig in and understand exactly why it works. +<!-- +`CPP_SETUP_START` +#include "do_smth.hpp" +$PLACEHOLDER +`CPP_SETUP_END` +`CPP_COPY_SNIPPET` forward/main_lvalue.cpp +`CPP_RUN_CMD` CWD:forward c++ -std=c++17 main_lvalue.cpp +--> +```cpp +int main() { + int number{}; + DoSmth(number); +} +``` + +1. When we pass `number` to `DoSmth`, the compiler needs to make sure that our forwarding reference type `SomeType&&` matches our de-facto input type, an lvalue reference to int: `int&` +2. A way to make this happen is to deduce `SomeType` to be `int&` using the reference collapsing rules as then `SomeType&&` is `int& &&` which collapses to `int&`, which matches the de-factor input parameter. +3. This leads `value` to have the type `int& &&`, or, as we've just discussed `int&` +4. Given all of this, our call to `forward<SomeType>(value)` ends up being a call to `forward<int&>(int&)`, making the `T` type in the `forward` function be `int&` and choosing the first overload because `std::remove_reference_t<int&>` is just `int`, so the first overload takes `int&`. +5. We then return `T&&` from the `forward` function, which means that we return `int& &&`, which again collapses to `int&`. +6. Which means that we get an lvalue reference out of our `forward` function, and the compiler picks the first overload of our `Print` function and prints `lvalue`. + + +#### Passing by rvalue +Now let's do the same exercise for the situation when we pass an rvalue into the `DoSmth` function. We can see that the code prints `rvalue` for both situations when we pass a temporary and when we `std::move` from an lvalue. So let's dive into what happens here too. +<!-- +`CPP_SETUP_START` +#include "do_smth.hpp" +$PLACEHOLDER +`CPP_SETUP_END` +`CPP_COPY_SNIPPET` forward/main_rvalue.cpp +`CPP_RUN_CMD` CWD:forward c++ -std=c++17 main_rvalue.cpp +--> +```cpp +int main() { + int number{}; + DoSmth(42); + DoSmth(std::move(number)); +} +``` +1. The compiler needs to make sure that `SomeType&&` matches the input type `int&&` +2. So it trivially deduces `SomeType` to be `int` +3. Which leaves `value` to have type `int&&`. +4. Now, when we call `forward<int>(value)`, the `T` type in our `forward` function will be `int`, the `remove_reference_t<int>` in the `forward` function will collapse to a simple `int` type and, considering that `value` has type `int&&`, we might expect that a *second* overload would be called. But in reality, the **first overload will be picked!** We have to remember that `value` here **has a name and an address in memory** which makes it an **lvalue** that stores an rvalue reference! So it binds to the first `forward` overload. If this is confusing, which I admit it _is_ a little bit, please have another look at the [lecture where we reinvent move semantics](move_semantics.md) to learn why it was designed the way it was designed. +5. Despite getting an lvalue reference as a parameter to our `forward` function we return this value as the `T&&` type, or `int&&` in our case. So in the end, we still convert our value to an rvalue reference and return it as such! +6. This, in turn, leads us to picking the `Print(int&&)` overload and printing `rvalue` to the terminal. + +It might be a bit too quick to follow, so as usual, you can play with these examples yourself at your own pace by following the link to [cppinsights.io](https://cppinsights.io/s/e48f0dba) +<!-- that you can find in the description to this video. --> + +But I'm afraid there is still one more thing to discuss, though. You might be still wondering: when is that second overload called? And really, the only case I can think of is when we directly call the `forward` function with a real rvalue - either providing a temporary object or an lvalue that we explicitly mark as an xvalue with `std::move`: +<!-- +`CPP_SETUP_START` +$PLACEHOLDER +`CPP_SETUP_END` +`CPP_COPY_SNIPPET` forward_overload/main.cpp +`CPP_RUN_CMD` CWD:forward_overload c++ -std=c++17 main.cpp +--> +```cpp +#include <type_traits> +#include <utility> + +template <class T> +T&& forward(std::remove_reference_t<T>& t) { + return static_cast<T&&>(t); +} + +template <class T> +T&& forward(std::remove_reference_t<T>&& t) { + return static_cast<T&&>(t); +} + +int main() { + // We can also use std::forward here of course. + forward<int>(42); + int number{}; + forward<int>(std::move(number)); +} +``` +I'll leave it up to you to figure out exactly why the second overload is called in both cases here but if something is not clear, please ask questions! + +And now I guess we've covered pretty much all there is to how forwarding references work in conjunction with `std::forward`! I know it was quite a lot, but if we are comfortable with this, it is a good indicator that we are comfortable with a lot of key mechanisms used in C++. + +## Summary +With this we should be well equipped to detect when we see a forwarding reference used in the code. + +Not only that but we should also leave with an intuition that it makes sense to use forwarding references if we have many function parameters of many template type parameters that can be either copied or moved depending on the reference type used. + +Finally, we even dove deep into how it all works, how the compiler picks which types to deduce and which overloads to pick. + +Hope this makes your journey towards understanding how to work with templates in C++ easier and that you enjoyed this explanation of mine. + +<!-- Finally, if you feel that one or another concept don't fully make sense just yet, please give the appropriate videos on my channel a re-watch. So why not catch up on what move semantics is and maybe even reinvent it with me? For that please click on the video here. Otherwise, if you'd like to watch the series on why and how to use templates, then do give this video a click instead. Thanks a lot for watching and see you next time! Bye! --> diff --git a/readme.md b/readme.md index 57ed729..58f5848 100644 --- a/readme.md +++ b/readme.md @@ -545,6 +545,30 @@ Headers with classes ---------------------------------------------------------- </details> +</details> + +<details> +<summary>Forwarding references</summary> + +---------------------------------------------------------- +[![Video thumbnail](https://img.youtube.com/vi/RW9KnqszYj4/maxresdefault.jpg)](https://youtu.be/RW9KnqszYj4) + +- [The forwarding reference](lectures/forwarding_references.md#the-forwarding-reference) +- [Why use forwarding references](lectures/forwarding_references.md#why-use-forwarding-references) + - [Example setup](lectures/forwarding_references.md#example-setup) + - [How forwarding references simplify things](lectures/forwarding_references.md#how-forwarding-references-simplify-things) + - [When to prefer forwarding references](lectures/forwarding_references.md#when-to-prefer-forwarding-references) +- [How forwarding references work](lectures/forwarding_references.md#how-forwarding-references-work) + - [Reference collapsing](lectures/forwarding_references.md#reference-collapsing) + - [Remove reference using `std::remove_reference_t`](lectures/forwarding_references.md#remove-reference-using-stdremove_reference_t) + - [How `std::forward` works](lectures/forwarding_references.md#how-stdforward-works) + - [Passing an lvalue](lectures/forwarding_references.md#passing-an-lvalue) + - [Passing by rvalue](lectures/forwarding_references.md#passing-by-rvalue) +- [Summary](lectures/forwarding_references.md#summary) + +---------------------------------------------------------- +</details> + ## PS ### Most of the code snippets are validated automatically