|
| 1 | +/// <reference types="vite/client" /> |
| 2 | +import { createRef } from '@motion-canvas/core/lib/utils'; |
| 3 | +import { makeScene2D, Code, LezerHighlighter, lines } from '@motion-canvas/2d'; |
| 4 | +import { all, waitFor, waitUntil } from '@motion-canvas/core/lib/flow'; |
| 5 | +import { ThreadGenerator } from '@motion-canvas/core/lib/threading'; |
| 6 | +import { DEFAULT } from '@motion-canvas/core/lib/signals'; |
| 7 | +import { BBox, Vector2 } from '@motion-canvas/core/lib/types'; |
| 8 | +import { tags } from '@lezer/highlight'; |
| 9 | +import { HighlightStyle } from '@codemirror/language'; |
| 10 | + |
| 11 | +import { parser as parser_css } from '@lezer/css'; |
| 12 | +import { parser as parser_cpp } from '@lezer/cpp'; |
| 13 | + |
| 14 | +import blockingCode from '@lectures/parallelism.md?snippet=parallelism_blocking/main.cpp'; |
| 15 | +import asyncCode from '@lectures/parallelism.md?snippet=parallelism_async/main.cpp'; |
| 16 | +import algorithmsSequentialCode from '@lectures/parallelism.md?snippet=parallelism_algorithms/main_sequential.cpp'; |
| 17 | +import algorithmsParallelCode from '@lectures/parallelism.md?snippet=parallelism_algorithms/main_parallel.cpp'; |
| 18 | +import tbbCode from '@lectures/parallelism.md?snippet=parallelism_algorithms/main_tbb.cpp'; |
| 19 | +import jthreadCode from '@lectures/parallelism.md?snippet=parallelism_jthread/main.cpp'; |
| 20 | +import threadpool17Code from '@lectures/parallelism.md?snippet=parallelism_threadpool_17/main.cpp'; |
| 21 | + |
| 22 | +import { MyStyle } from '../../styles'; |
| 23 | + |
| 24 | +const CppHighlighter = new LezerHighlighter(parser_cpp, MyStyle); |
| 25 | + |
| 26 | +function* centerOn( |
| 27 | + codeRef: Code, |
| 28 | + selectionInput: any, |
| 29 | + duration: number, |
| 30 | + targetFontSize?: number, |
| 31 | +): ThreadGenerator { |
| 32 | + // We only care about the bounding box of the new selection |
| 33 | + let bboxes: BBox[] = []; |
| 34 | + if (selectionInput !== DEFAULT) { |
| 35 | + // getSelectionBBox computes the bounds for the given selection using the CURRENT layout state. |
| 36 | + // We do NOT need to set the selection signal to measure it! |
| 37 | + bboxes = codeRef.getSelectionBBox(selectionInput); |
| 38 | + } |
| 39 | + |
| 40 | + if (bboxes.length === 0) { |
| 41 | + const fallbackAnimations: ThreadGenerator[] = [ |
| 42 | + codeRef.selection(selectionInput, duration), |
| 43 | + codeRef.y(0, duration) |
| 44 | + ]; |
| 45 | + if (targetFontSize !== undefined) { |
| 46 | + fallbackAnimations.push(codeRef.fontSize(targetFontSize, duration)); |
| 47 | + } |
| 48 | + yield* all(...fallbackAnimations); |
| 49 | + return; |
| 50 | + } |
| 51 | + |
| 52 | + let minY = Infinity; |
| 53 | + let maxY = -Infinity; |
| 54 | + |
| 55 | + for (const bbox of bboxes) { |
| 56 | + if (bbox.top !== undefined && !isNaN(bbox.top)) minY = Math.min(minY, bbox.top); |
| 57 | + if (bbox.bottom !== undefined && !isNaN(bbox.bottom)) maxY = Math.max(maxY, bbox.bottom); |
| 58 | + } |
| 59 | + |
| 60 | + let centerY = (minY + maxY) / 2; |
| 61 | + if (!isFinite(centerY) || isNaN(centerY)) { |
| 62 | + centerY = 0; |
| 63 | + } |
| 64 | + |
| 65 | + // Scale the calculated target offset based on how the font size will change. |
| 66 | + // This perfectly centers it without needing to pollute the animation timeline |
| 67 | + // with synchronous layout mutations. |
| 68 | + if (targetFontSize !== undefined) { |
| 69 | + const currentFontSize = codeRef.fontSize(); |
| 70 | + if (currentFontSize > 0) { |
| 71 | + centerY = centerY * (targetFontSize / currentFontSize); |
| 72 | + } |
| 73 | + } |
| 74 | + |
| 75 | + const animations: ThreadGenerator[] = [ |
| 76 | + codeRef.selection(selectionInput, duration), |
| 77 | + codeRef.y(-centerY, duration) |
| 78 | + ]; |
| 79 | + |
| 80 | + if (targetFontSize !== undefined) { |
| 81 | + animations.push(codeRef.fontSize(targetFontSize, duration)); |
| 82 | + } |
| 83 | + |
| 84 | + yield* all(...animations); |
| 85 | +} |
| 86 | + |
| 87 | +export default makeScene2D(function* (view) { |
| 88 | + const codeRef = createRef<Code>(); |
| 89 | + |
| 90 | + yield view.add(<Code |
| 91 | + ref={codeRef} |
| 92 | + fontSize={20} |
| 93 | + fontFamily={'Fira Mono'} |
| 94 | + fontWeight={500} |
| 95 | + offsetX={-1} |
| 96 | + x={-800} |
| 97 | + y={0} |
| 98 | + highlighter={CppHighlighter} |
| 99 | + />); |
| 100 | + |
| 101 | + const duration = 1.0; |
| 102 | + |
| 103 | + // 0. Blocking |
| 104 | + yield* codeRef().code(blockingCode, 0); |
| 105 | + yield* centerOn(codeRef(), DEFAULT, 0, 20); |
| 106 | + yield* waitFor(duration); |
| 107 | + |
| 108 | + // Focus on loading an image |
| 109 | + yield* centerOn(codeRef(), [lines(8, 10)], duration, 30); |
| 110 | + yield* waitFor(duration); |
| 111 | + yield* centerOn(codeRef(), [lines(12, 16), lines(6, 11)], duration, 30); |
| 112 | + yield* waitFor(duration); |
| 113 | + yield* centerOn(codeRef(), lines(18, 28), duration, 30); |
| 114 | + yield* waitFor(duration); |
| 115 | + yield* centerOn(codeRef(), DEFAULT, duration, 20); |
| 116 | + yield* waitFor(duration); |
| 117 | + |
| 118 | + // 1. std::async Background Task |
| 119 | + yield* all( |
| 120 | + codeRef().code(asyncCode, duration), |
| 121 | + centerOn(codeRef(), DEFAULT, duration, 14) |
| 122 | + ); |
| 123 | + yield* waitFor(duration); |
| 124 | + |
| 125 | + // Focus on loading an image |
| 126 | + yield* centerOn(codeRef(), lines(21, 38), duration, 30); |
| 127 | + yield* waitFor(duration); |
| 128 | + |
| 129 | + // Focus on std::async |
| 130 | + yield* centerOn(codeRef(), lines(42, 45), duration, 30); |
| 131 | + yield* waitFor(duration); |
| 132 | + |
| 133 | + // Focus on future polling |
| 134 | + yield* centerOn(codeRef(), lines(46, 54), duration, 30); |
| 135 | + yield* waitFor(duration); |
| 136 | + |
| 137 | + // Focus on getting |
| 138 | + yield* centerOn(codeRef(), lines(55, 58), duration, 30); |
| 139 | + yield* waitFor(duration); |
| 140 | + |
| 141 | + yield* centerOn(codeRef(), lines(44, 45), duration, 40); |
| 142 | + yield* waitFor(duration); |
| 143 | + |
| 144 | + // 2. Parallel Algorithms |
| 145 | + yield* centerOn(codeRef(), DEFAULT, duration, 18); |
| 146 | + yield* codeRef().code(algorithmsSequentialCode, duration); |
| 147 | + yield* waitFor(duration); |
| 148 | + |
| 149 | + yield* centerOn(codeRef(), lines(16, 22), duration, 30); |
| 150 | + yield* waitFor(duration); |
| 151 | + |
| 152 | + yield* centerOn(codeRef(), lines(8, 10), duration, 30); |
| 153 | + yield* waitFor(duration); |
| 154 | + |
| 155 | + yield* centerOn(codeRef(), lines(12, 14), duration, 30); |
| 156 | + yield* waitFor(duration); |
| 157 | + |
| 158 | + yield* centerOn(codeRef(), lines(26, 28), duration, 30); |
| 159 | + yield* waitFor(duration); |
| 160 | + |
| 161 | + yield* centerOn(codeRef(), lines(32, 35), duration, 30); |
| 162 | + yield* waitFor(duration); |
| 163 | + |
| 164 | + yield* centerOn(codeRef(), lines(29, 39), duration, 30); |
| 165 | + yield* waitFor(duration); |
| 166 | + |
| 167 | + // 2. Parallel Algorithms |
| 168 | + yield* centerOn(codeRef(), DEFAULT, duration, 18); |
| 169 | + yield* codeRef().code(algorithmsParallelCode, duration); |
| 170 | + yield* waitFor(duration); |
| 171 | + |
| 172 | + yield* centerOn(codeRef(), lines(32, 37), duration, 30); |
| 173 | + yield* waitFor(duration); |
| 174 | + |
| 175 | + yield* centerOn(codeRef(), lines(2, 2), duration, 30); |
| 176 | + yield* waitFor(duration); |
| 177 | + |
| 178 | + yield* centerOn(codeRef(), lines(29, 41), duration, 30); |
| 179 | + yield* waitFor(duration); |
| 180 | + |
| 181 | + yield* centerOn(codeRef(), DEFAULT, duration, 17); |
| 182 | + yield* waitFor(duration); |
| 183 | + |
| 184 | + // 3. Raw TBB |
| 185 | + yield* codeRef().code(tbbCode, duration); |
| 186 | + yield* waitFor(duration); |
| 187 | + |
| 188 | + yield* centerOn(codeRef(), lines(34, 41), duration, 30); |
| 189 | + yield* waitFor(duration); |
| 190 | + |
| 191 | + yield* centerOn(codeRef(), DEFAULT, duration, 20); |
| 192 | + yield* waitFor(duration); |
| 193 | + |
| 194 | + // 4. Thread Pool jthread |
| 195 | + yield* codeRef().code(jthreadCode, duration); |
| 196 | + yield* waitFor(duration); |
| 197 | + |
| 198 | + // Focus constructor and submit |
| 199 | + yield* centerOn(codeRef(), lines(22, 42), duration, 22); |
| 200 | + yield* waitFor(duration); |
| 201 | + |
| 202 | + yield* centerOn(codeRef(), DEFAULT, duration, 15); |
| 203 | + yield* waitFor(duration); |
| 204 | + |
| 205 | + // Focus on the locking and cv in ProcessImages |
| 206 | + yield* centerOn(codeRef(), lines(55, 61), duration, 22); |
| 207 | + yield* waitFor(duration); |
| 208 | + |
| 209 | + yield* centerOn(codeRef(), DEFAULT, duration, 15); |
| 210 | + yield* waitFor(duration); |
| 211 | + |
| 212 | + // 5. Thread Pool C++17 Equivalent (Morphing from C++20) |
| 213 | + // Morph the C++20 thread pool cleanly into the C++17 one! |
| 214 | + yield* codeRef().code(threadpool17Code, duration); |
| 215 | + yield* waitFor(duration); |
| 216 | + |
| 217 | + // Focus on shutdown logic |
| 218 | + yield* centerOn(codeRef(), lines(41, 61), duration, 22); |
| 219 | + yield* waitFor(duration); |
| 220 | + |
| 221 | + yield* centerOn(codeRef(), DEFAULT, duration, 15); |
| 222 | + yield* waitFor(duration); |
| 223 | + |
| 224 | + // Focus CV condition |
| 225 | + yield* centerOn(codeRef(), lines(71, 77), duration, 25); |
| 226 | + yield* waitFor(duration); |
| 227 | + |
| 228 | + // Focus on the data members changing |
| 229 | + yield* centerOn(codeRef(), lines(100, 105), duration, 22); |
| 230 | + yield* waitFor(duration); |
| 231 | + |
| 232 | + // Finally wrap it out |
| 233 | + yield* centerOn(codeRef(), DEFAULT, duration, 20); |
| 234 | + yield* waitFor(duration); |
| 235 | + |
| 236 | +}); |
0 commit comments