diff --git a/.gitignore b/.gitignore index 0fdf57a38..a29397393 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,8 @@ site/.vitepress/cache/ site/.vitepress/.build-cache/ site/.vitepress/.build-tmp/ site/.vitepress/.search-cache/ +# animy_maker 每次编译会重新生成 posters/,但 SSG 首帧已接管其兜底职责(docs/09 §7) +site/.vitepress/theme/components/animations/posters/ # Book/PDF pipeline (generated locally or uploaded as CI/Release artifacts) .pdf-build/ diff --git a/README.md b/README.md index 13e8a5a97..1b4b607b4 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ --- -![English Coverage](https://img.shields.io/badge/en_coverage-97%25-green.svg) 578/598 docs translated +![English Coverage](https://img.shields.io/badge/en_coverage-96%25-green.svg) 578/601 docs translated ## 嘿!这是什么? diff --git a/code/examples/vol3/primer_01_dangling_pointer.cpp b/code/examples/vol3/primer_01_dangling_pointer.cpp new file mode 100644 index 000000000..f4a66eb3d --- /dev/null +++ b/code/examples/vol3/primer_01_dangling_pointer.cpp @@ -0,0 +1,24 @@ +// primer_01_dangling_pointer.cpp +// 扩容后旧指针悬空:先看两个地址分道扬镳,再看 UB 是死是活 + +#include +#include + +int main() { + std::vector v; + v.reserve(2); + v.push_back(41); + v.push_back(1); + + int* p = &v[0]; // 缓存一个指针 + std::printf("before: p = %p, v.data() = %p\n", static_cast(p), + static_cast(v.data())); + + v.push_back(99); // 容量已满,触发扩容(缓冲整体搬迁) + std::printf("after : p = %p, v.data() = %p\n", static_cast(p), + static_cast(v.data())); + + *p = 100; // 往旧地址写:未定义行为 + std::printf("*p = %d (this write went to the OLD buffer)\n", *p); + return 0; +} diff --git a/code/examples/vol3/primer_01_vector_growth.cpp b/code/examples/vol3/primer_01_vector_growth.cpp new file mode 100644 index 000000000..bc2780a87 --- /dev/null +++ b/code/examples/vol3/primer_01_vector_growth.cpp @@ -0,0 +1,22 @@ +// primer_01_vector_growth.cpp +// 观察 std::vector 的扩容:容量序列 + 缓冲地址变化(搬家现场) + +#include +#include + +int main() { + std::vector v; + std::size_t last_cap = v.capacity(); + std::printf("born : size=%zu capacity=%zu data=%p\n", v.size(), v.capacity(), + static_cast(v.data())); + + for (int i = 0; i < 40; ++i) { + v.push_back(i); + if (v.capacity() != last_cap) { + std::printf("push #%-2d: size=%zu capacity=%zu data=%p\n", i + 1, v.size(), + v.capacity(), static_cast(v.data())); + last_cap = v.capacity(); + } + } + return 0; +} diff --git a/code/examples/vol3/primer_02_address_stability.cpp b/code/examples/vol3/primer_02_address_stability.cpp new file mode 100644 index 000000000..e34aabd71 --- /dev/null +++ b/code/examples/vol3/primer_02_address_stability.cpp @@ -0,0 +1,29 @@ +// primer_02_address_stability.cpp +// 链表从不搬家:删掉中间一个节点,其余节点的地址一位都不动 + +#include +#include + +int main() { + std::list L{0, 1, 2, 3, 4, 5, 6, 7}; + + auto dump = [&L](const char* tag) { + std::printf("%s:\n", tag); + int i = 0; + for (int& x : L) { + std::printf(" [%d] addr=%p val=%d\n", i++, static_cast(&x), x); + } + }; + + dump("before erase"); + + for (auto it = L.begin(); it != L.end(); ++it) { + if (*it == 4) { + L.erase(it); // 只解除这一个节点,其余节点不动 + break; + } + } + + dump("after erase (node holding 4 removed)"); + return 0; +} diff --git a/code/examples/vol3/primer_02_node_chain.cpp b/code/examples/vol3/primer_02_node_chain.cpp new file mode 100644 index 000000000..68f7fdb47 --- /dev/null +++ b/code/examples/vol3/primer_02_node_chain.cpp @@ -0,0 +1,36 @@ +// primer_02_node_chain.cpp +// 手工串一条链:三个节点 + 头插一个 99 + 遍历打印 + 逐个释放 + +#include + +struct Node { + int val; + Node* next; +}; + +void push_front(Node*& head, int x) { + Node* n = new Node{x, head}; // 新节点的 next 指向原来的头节点 + head = n; // head 改指新节点 +} + +int main() { + Node* c = new Node{30, nullptr}; // 链尾:next 存 nullptr + Node* b = new Node{20, c}; // 中间节点:next 指向 c + Node* a = new Node{10, b}; // 头节点:next 指向 b + Node* head = a; // 入口指向头节点 + + push_front(head, 99); + + for (Node* cur = head; cur != nullptr; cur = cur->next) { + std::printf("%d -> ", cur->val); + } + std::printf("nullptr\n"); + + Node* cur = head; // 逐个释放节点,防止泄漏 + while (cur != nullptr) { + Node* nxt = cur->next; + delete cur; + cur = nxt; + } + return 0; +} diff --git a/documents/vol3-standard-library/containers/03-vector-deep-dive.md b/documents/vol3-standard-library/containers/03-vector-deep-dive.md index cc027be2d..8304d959f 100644 --- a/documents/vol3-standard-library/containers/03-vector-deep-dive.md +++ b/documents/vol3-standard-library/containers/03-vector-deep-dive.md @@ -50,7 +50,7 @@ flowchart LR ## 扩容这件事:说是摊还常数,单次可能是 O(n) -那往一个 `capacity` 已经塞满的 `vector` 里再 `push_back` 会怎样?会触发一次 *reallocation*——申请新缓冲、把旧元素搬过去、释放旧缓冲。标准对这一步的承诺是 `push_back` 的**摊还常数复杂度**,请各位务必咬住"摊还"这两个字,它不是"常数"。 +那往一个 `capacity` 已经塞满的 `vector` 里再 `push_back` 会怎样?会触发一次 *reallocation*——申请新缓冲、把旧元素搬过去、释放旧缓冲。标准对这一步的承诺是 `push_back` 的**摊还常数复杂度**,请各位务必记住"摊还"这两个字,它不是"常数"。 这话太容易被读成"每次 `push_back` 都是 O(1)",于是一些朋友就放心地往热循环里塞 `push_back`,结果某一次扩容直接是一次 O(n) 的搬家,性能曲线上"咔"地掉一个尖峰。摊还分析为什么能成立?关键就在于每次扩容时,容量是按一个大于 1 的几何倍数往上翻的,于是那一次昂贵的搬家费用,就被摊到了之前若干次便宜的 `push_back` 头上。 diff --git a/documents/vol3-standard-library/containers/index.md b/documents/vol3-standard-library/containers/index.md index a676250b5..a23ea50a3 100644 --- a/documents/vol3-standard-library/containers/index.md +++ b/documents/vol3-standard-library/containers/index.md @@ -6,9 +6,10 @@ sidebar_order: 10 # 容器与数据结构 -存放和管理数据的家伙们。这一组把每个容器的内部表示、扩容与迭代器失效规则、复杂度代价讲透,并在「容器选择指南」里给出按操作挑选容器的决策路径。 +存放和管理数据的家伙们。这一组把每个容器的内部表示、扩容与迭代器失效规则、复杂度代价讲透,并在「容器选择指南」里给出按操作挑选容器的决策路径。还没摸过动态数组、哈希表这些结构本身的读者,先走一遍「数据结构 primer」子系列,地基打好再上来。 + 数据结构 primer:容器底下的结构 容器选择指南 array:定长数组 vector 深入 diff --git a/documents/vol3-standard-library/containers/primer/01-amortized-cost.drawio b/documents/vol3-standard-library/containers/primer/01-amortized-cost.drawio new file mode 100644 index 000000000..8ad48af22 --- /dev/null +++ b/documents/vol3-standard-library/containers/primer/01-amortized-cost.drawio @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documents/vol3-standard-library/containers/primer/01-dynamic-array.md b/documents/vol3-standard-library/containers/primer/01-dynamic-array.md new file mode 100644 index 000000000..853feb83f --- /dev/null +++ b/documents/vol3-standard-library/containers/primer/01-dynamic-array.md @@ -0,0 +1,256 @@ +--- +title: "动态数组:一块会搬家的内存" +description: "数据结构 primer 第一篇。静态数组的长度与栈空间限制(2 MiB 栈数组真跑即崩,退出码 0xC00000FD)把咱们引向堆上的连续存储;用 data/size/cap 三个成员搭出动态数组雏形,MSVC x64 真跑给出容量序列 1,2,3,4,6,9,13,19,28,42 与每次扩容的缓冲地址变化,20 万元素计时实测加一增长约 1.9 秒、翻倍约 0.6 毫秒,ASan 复现扩容后旧指针 use-after-free(WRITE of size 4)。全部输出为本机真跑,非转述。" +chapter: 7 +order: 1 +tags: + - host + - cpp-modern + - beginner + - vector + - 容器 + - 基础 + - 入门 +difficulty: beginner +platform: host +reading_time_minutes: 15 +prerequisites: + - "卷一·第 12 章:进程内存布局(栈与堆)" + - "卷一:指针基础(取地址、解引用)" +related: + - "vector 深入:三指针、扩容与迭代器失效" + - "mini STL 实战(二):Vector,扩容与搬迁" +cpp_standard: [11] +--- + +# 动态数组:一块会搬家的内存 + +兄弟们,咱们马上就要开始标准库的学习了,在您点开了咱们的数据结构库支持之前,我相信,您应该不会对 `int a[100]` 这个说辞感到陌生了。(哈?陌生,看看C语言的教程吧!),咱们也稍微使用了一下 `std::vector`。好像都是数组,对吧。**差别在哪?前者的格子在咱们写下这行代码的那一刻就定死了,编译进可执行文件后一个字节都多不出来,这我相信大家都不会有意见;但是很奇怪,后者却可以连塞一百万个数不炸。多出来的内存从哪来?** + +从堆上借的。 + +是的,从堆上借的。而且借的从来不是同一块——装满了就换一块更大的,把所有元素整体搬过去。`std::vector` 的全部秘密就这一句话。这一篇咱们把它摊开:内存住在哪、谁在计数、搬家怎么搬、搬一次多贵、搬完之后哪些东西会悄悄失效。把这些立住,再去读实现层的深讲、去碰链表和哈希表,脚下都是地基。 + +## 静态数组为什么在业务场景非常多用? + +笔者想了想,其实有三点:长度定死、栈太小、加不了 + +您要是做后端开发,来了数据登记,总不可能说:就只有 10 个用户在这一秒提交了表单,肯定是不定长的,对吧!有时候一个都没有,有时候几百个。 + +如果是嵌入式来的朋友,我这样说:写代码的时候,咱们经常不知道运行时会来多少数据——传感器一秒发多少帧、日志攒多少行、用户输多少个数,全是运行时的事,编译期定长度等于闭眼押注。 + +归根结底,问题还是出在 `int a[100]` 这种写法上:咱们写下方这行代码时,长度就成了类型的一部分,编译期就得给定。想改,没门兄弟们! + +第二是空间。这样声明的数组默认住在栈上,而栈是很小的:Windows 默认 1 MiB,Linux 常见 8 MiB。咱们真跑一个(MSVC x64): + +```cpp +#include + +int main() { + int big[2 * 1024 * 1024]; // 2 MiB,超出默认 1 MiB 的栈 + big[0] = 41; + std::printf("big[0] = %d\n", big[0]); + return 0; +} +``` + +一行输出都没有,进程直接死在起跑线上。 + +```text +EXIT_CODE:-1073741571 +``` + +嗯,这个退出码我是在 Windows 上跑的(笔者上班的时候摸鱼只有 Windows 能用):这个数就是 Windows 的 `0xC00000FD`,栈溢出状态码。Linux 下换汤不换药,栈超限同样崩,只是死法换成段错误。栈是给局部变量和函数调用准备的快车道,容量小,由操作系统在建线程时一次性划拨,想改要去链接器选项或线程属性里专门开口子;拿它装运行时才知道大小的数据,是用错了房间。 + +> 笔者真的见过有人跟我刚,说我打OI这样写的,直到看到他的样板代码,我直接说——大哥,放在 bss / data 段跟放在栈上不是一回事情!如果您是OJ选手,开大数组记得要么static修饰,要不就丢全局去,我建议丢全局,因为不用打static关键字。 + + +第三,就算长度蒙对了,咱们中途想再多装一个,也没有余地。数组在内存里是连成一排的格子,后面紧挨着别人的地盘,想加长得连别人的地一起占,不现实。 + +## 数据住堆上,手里攥一个指针 + +三个滔天门槛指向了同一个解法:数据搬到堆上。堆是一大片按需申请的内存,`new` 多大都能谈(物理内存允许的话),什么时候还、还多少也归咱们管。栈上只留一个小小的句柄: + +```cpp +int* data = new int[8]; // 堆上分配 8 个 int +data[0] = 41; // 用法跟数组一模一样 +delete[] data; // 用完必须释放 +``` + +![栈上的指针指向堆上的连续格子](./01-stack-heap-pointers.drawio) + +用法上咱们看不出 `data[0]` 和 `a[0]` 有区别,下标访问走的是同一套地址算术。区别全在背后:`a` 的格子编译时就分好、函数返回自动回收;`data` 的格子运行时借、必须手动还,忘了还就是内存泄漏。 + +不过这个裸写法马上暴露两个新问题。头一个:借了 8 格,第 9 个数据来了怎么办?再借一块更大的、把旧元素搬过去、把旧内存还掉,这个动作咱们下一节专门拆。第二个更隐蔽:函数中途 `return` 或者抛了异常,`delete[]` 就被跳过了,泄漏照旧。裸指针管资源,出错的路径太多。咱们先解决"怎么装得下",封装和自动回收的事,结尾交给 RAII。 + +## 两个数字分清楚:装了几个,最多装几个 + +咱们把裸指针和它的计数包在一起,动态数组的雏形就出来了: + +```cpp +struct IntVec { + int* data; // 堆上那块连续内存的起点 + size_t size; // 装了几个(前 size 格是有效元素) + size_t cap; // 最多装几个(整块内存的格数) +}; +``` + +![size 与 capacity 分离:8 格容量,前 5 格有元素](./01-size-capacity.drawio) + +`size` 和 `cap` 是两码事,这是咱们理解动态数组要建立的第一个直觉:`size` 说现在有几个活元素,`cap` 说这块内存一共借了几格。中间空着的那截不还回去,留给下一次 `push_back` 直接用;立刻还掉、下次再借,分配器一来一回的开销比留着高。 + +有了这两个数,咱们往尾部加元素就分成两种情况: + +```cpp +void push_back(IntVec& v, int x) { + if (v.size < v.cap) { + v.data[v.size] = x; // 还有空位:写一格,计数加一 + v.size += 1; + return; + } + grow(v); // 容量满:扩容,下一节的事 + v.data[v.size] = x; + v.size += 1; +} +``` + +余量充足时,`push_back` 干的活就是写一格、`size` 加一,这就是它便宜的全部原因。`std::vector` 的本体也胖不到哪去,咱们真跑一下: + +```text +sizeof(std::vector) = 24 bytes +``` + +24 字节,64 位机上正好三个指针的宽度。肉全在堆上,对象自己瘦得只剩计数。这三个指针具体怎么摆(起点、尾后、仓底),怎么由它们推出 `size()` 和 `capacity()`,本卷 [`vector 深入`](../03-vector-deep-dive.md) 一篇有完整推导,咱们这里记住结论就够。 + +## 满了就搬家:换一块更大的内存 + +`size` 追上 `cap` 的那一刻,就是搬家的时刻。咱们要做的就三步:借一块更大的新内存,把旧元素搬过去,把旧内存还掉。 + +```cpp +void grow(IntVec& v) { + size_t ncap = v.cap == 0 ? 1 : v.cap * 2; // 新容量翻倍 + int* nd = new int[ncap]; // 申请更大的新缓冲 + for (size_t i = 0; i < v.size; ++i) { + nd[i] = v.data[i]; // 旧元素逐个拷贝过去 + } + delete[] v.data; // 释放旧缓冲 + v.data = nd; + v.cap = ncap; +} +``` + +![扩容三步:申请新缓冲、搬迁元素、释放旧缓冲](./01-reallocation-steps.drawio) + +代码朴素,但有两个细节值得咱们盯住。新家的大小是 `cap * 2` 而不是 `cap + 1`,这个倍数是整个设计的灵魂,下一节拿计时数据说话。搬迁循环写的是逐元素赋值;对 `int` 这种平凡类型,标准库实际走的是整块拷贝(`memmove` 一族);元素换成复杂对象,搬迁还牵扯构造与析构怎么配对,那是另一档讲究,vol8 的 [`Vector,扩容与搬迁`](../../../vol8-domains/data-structure/02-vector-growth-and-relocation.md) 专门拆它。 + +咱们让 `std::vector` 自己演示一遍搬家。连塞 40 个数,容量一变就打一行(MSVC x64 真跑): + +```text +born : size=0 capacity=0 data=0000000000000000 +push #1 : size=1 capacity=1 data=0000016D1A7AF410 +push #2 : size=2 capacity=2 data=0000016D1A7AF430 +push #3 : size=3 capacity=3 data=0000016D1A7B6C90 +push #4 : size=4 capacity=4 data=0000016D1A7B6B10 +push #5 : size=5 capacity=6 data=0000016D1A7B6DB0 +push #7 : size=7 capacity=9 data=0000016D1A7B7380 +push #10 : size=10 capacity=13 data=0000016D1A7A5B60 +push #14 : size=14 capacity=19 data=0000016D1A7AC890 +push #20 : size=20 capacity=28 data=0000016D1A7AF410 +push #29 : size=29 capacity=42 data=0000016D1A7AF490 +``` + +咱们把两列一起读。容量列:1, 2, 3, 4, 6, 9, 13, 19, 28, 42,每次约乘 1.5,这是 MSVC STL 的策略;libstdc++ 和 libc++ 乘 2,序列是 0, 1, 2, 4, 8, 16, 32(对照见 [`vector 深入`](../03-vector-deep-dive.md))。倍数标准没规定,各家自己定,但都严格大于 1——为什么,下一节见分晓。 + +咱们再看地址列:容量一变,`data` 就换。每次扩容都是整体搬家,旧缓冲整块作废。还有个耐人寻味的细节:`push #20` 拿到的地址 `...AF410`,跟 `push #1` 一模一样。 + +欸!这还真不是巧合——1.5 倍策略下,前面退掉的旧块大小正好够后面的扩容复用,分配器把刚还回来的房子又租给了咱们。为什么 1.5 有这个性质而 2 没有,`vector 深入` 里有一段漂亮的推导,这里咱们记住现象就够。 + +这一幕您也可以亲手复现,咱们把演示放到了在线编译器: + + + +## 翻倍,还是加一:搬家的价钱差三个数量级 + +回到 `grow` 里那个倍数。直觉上似乎 `cap + 1` 更省内存:要几个借几个,一格不多占。咱们把两种策略各自塞 20 万个数,计时真跑(MSVC `/O2`,各三轮): + +```text +appending 200000 ints, 3 runs each (times in microseconds): +run 1: +1 growth = 2016464 us x2 growth = 676 us +run 2: +1 growth = 1868235 us x2 growth = 662 us +run 3: +1 growth = 1869491 us x2 growth = 590 us +``` + +![摊还的直觉:绝大多数 push 便宜,容量边界上偶尔贵一次](./01-amortized-cost.drawio) + +加一策略约 1.9 秒,翻倍策略不到 1 毫秒,差三个数量级。推导不复杂,咱们先算加一策略:第 N 个元素进来前要搬走全部 N-1 个旧元素,总共搬 0+1+2+…+(N-1) ≈ N²/2 次,N 取 20 万就是两千亿次拷贝;翻倍策略只在容量 1, 2, 4, 8, … 这些点上搬家,每次的搬运量加起来 1+2+4+…+N/2 < N,20 万元素总共搬不到 40 万次。平方级对线性级,数据量一大就是秒级对微秒级。 + +所以标准给 `push_back` 的复杂度承诺写的是**摊还常数**(amortized constant)。摊还两个字是关键:单个 `push_back` 触发搬家时,实打实是 O(n)。直觉的讲法是咱们把偶尔一次贵搬家摊到之前一串便宜的写入头上,平均每次仍是常数。上面那张图画的正是这个形态:绝大多数 `push_back` 是高度 1 的矮柱,容量边界上偶尔一根高柱,而高柱的间隔一次比一次远,平均高度被稀释回常数。 + +咱们提前知道要装多少的话,`reserve(n)` 能一次借够、整段免掉搬家,热路径上的毛刺也就不存在了。`shrink_to_fit`、`resize` 这些跟容量打交道的接口,细节都在 `vector 深入` 那篇,本篇不铺开。 + +## 中间插一个:后半段集体挪座 + +到这里咱们手里这个动态数组看着处处便宜:下标访问一步到位(基地址加偏移乘格子宽度,纯算术),尾部追加摊还常数。代价藏在中间。往头部插一个数试试(真跑): + +```text +before insert at front: 0 1 2 3 4 5 6 7 +after insert at front: 99 0 1 2 3 4 5 6 7 +``` + +8 个老元素,每个都往后挪了一格。这是连续存储定下的约束:格子必须连成排,第 0 格要腾给新元素,后面 8 个只能依次右移;删除同理,中间挖走一个,后面全部左移补洞。插的位置越靠前,挪得越多,平均一次中间插入或删除是 O(n) 次元素移动。尾插便宜、头插贵,这是"连续"的一体两面:它给了咱们 O(1) 随机访问和漂亮的缓存局部性,也定死了中间操作的搬运义务。 + +那有没有插中间谁都不用挪的结构?有。代价是咱们找第 i 个元素不能一步命中,得从头顺着问过去。那就是链表,本系列的下一篇。 + +## 搬完家,旧地址全作废 + +最后一件事故,也是新手踩得最狠的坑。咱们看代码: + +```cpp +std::vector v; +v.reserve(2); +v.push_back(41); +v.push_back(1); + +int* p = &v[0]; // 缓存一个指针 +v.push_back(99); // 容量已满,触发扩容 +*p = 100; // 往旧地址写 +``` + +咱们看 `p`:它指向旧缓冲的第一格。搬家发生时旧缓冲已经被 `delete`,`p` 从此指向一块已归还的内存。`*p = 100` 这行是未定义行为:可能崩,可能看起来没事,也可能悄悄把 100 写进分配器已经转租给别人的格子,污染一个毫无关系的对象。三种结局标准一个都不保证,这正是 UB 讨厌的地方:它最喜欢在测试时装没事,上线后搞破坏。 + +咱们用 AddressSanitizer 把这一幕逮个正着(MSVC,`/fsanitize=address`): + +```text +==18800==ERROR: AddressSanitizer: heap-use-after-free on address 0x123562da0010 +WRITE of size 4 at 0x123562da0010 thread T0 +``` + +`WRITE of size 4`,正是一个 `int` 的写入宽度,地址就是旧缓冲那格。没有 ASan 的话,这个程序在真机上大概率"正常跑完",错误沉在水底。引用和迭代器也一样。不管咱们手里拿的是 `&v[0]` 这样的指针、`v.front()` 返回的引用,还是循环里正走着的迭代器,触发搬家的那次操作一过,手里这些全部作废。 + +哪种操作让什么失效、哪种不失效(`reserve` 没超容量就不失效,`swap` 甚至一个都不失效),完整的失效规则表在 [`vector 深入`](../03-vector-deep-dive.md)。这里咱们先把"搬家等于旧地址全废"这个因果立住,那张表读起来就不再是死记的条目。 + +这个事故也备了一份在线版,您跑一遍就记得牢: + + + +## 雏形加上 RAII、模板和异常安全,就是 std::vector + +回头看咱们这一路搭的东西:堆上一块连续内存、`size` 和 `cap` 两个数、满了翻倍搬家。`std::vector` 的骨架就是它,再往上添三样工装:RAII 让析构自动还内存,泄漏这条路被堵死;模板把格子从 `int` 泛化成任意类型;异常安全处理"搬一半坏了怎么办",以及元素的移动构造够不够 `noexcept` 会不会拖慢搬迁。这三样在项目里各有归宿:想看实现层全貌,读本卷 [`vector 深入:三指针、扩容与迭代器失效`](../03-vector-deep-dive.md);想亲手把雏形搓成真容器,去 vol8 的 [mini STL 实战](../../../vol8-domains/data-structure/index.md),从裸缓冲开始一步一步来。 + +primer 的下一站是链表:一种永远不搬家的结构,代价是找元素得顺着问路。连续与离散、随机访问与顺序访问,这对取舍把数据结构的选择题撑开了大半,咱们下篇见。 + +## 参考资源 + +- [cppreference:std::vector](https://en.cppreference.com/w/cpp/container/vector)——复杂度承诺与迭代器失效规则的权威出处 +- 本卷 [`vector 深入`](../03-vector-deep-dive.md)——三指针推导、三家扩容策略的数学、完整失效表 +- vol8 [`mini STL 实战(二):Vector,扩容与搬迁`](../../../vol8-domains/data-structure/02-vector-growth-and-relocation.md)——亲手实现版,对象搬迁的完整讲究 diff --git a/documents/vol3-standard-library/containers/primer/01-reallocation-steps.drawio b/documents/vol3-standard-library/containers/primer/01-reallocation-steps.drawio new file mode 100644 index 000000000..aff0a3523 --- /dev/null +++ b/documents/vol3-standard-library/containers/primer/01-reallocation-steps.drawio @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documents/vol3-standard-library/containers/primer/01-size-capacity.drawio b/documents/vol3-standard-library/containers/primer/01-size-capacity.drawio new file mode 100644 index 000000000..09183dfc5 --- /dev/null +++ b/documents/vol3-standard-library/containers/primer/01-size-capacity.drawio @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documents/vol3-standard-library/containers/primer/01-stack-heap-pointers.drawio b/documents/vol3-standard-library/containers/primer/01-stack-heap-pointers.drawio new file mode 100644 index 000000000..b5e9ba66b --- /dev/null +++ b/documents/vol3-standard-library/containers/primer/01-stack-heap-pointers.drawio @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documents/vol3-standard-library/containers/primer/02-cache-locality.drawio b/documents/vol3-standard-library/containers/primer/02-cache-locality.drawio new file mode 100644 index 000000000..22185487a --- /dev/null +++ b/documents/vol3-standard-library/containers/primer/02-cache-locality.drawio @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documents/vol3-standard-library/containers/primer/02-front-insert.drawio b/documents/vol3-standard-library/containers/primer/02-front-insert.drawio new file mode 100644 index 000000000..d703a0666 --- /dev/null +++ b/documents/vol3-standard-library/containers/primer/02-front-insert.drawio @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documents/vol3-standard-library/containers/primer/02-linked-list.md b/documents/vol3-standard-library/containers/primer/02-linked-list.md new file mode 100644 index 000000000..82267839d --- /dev/null +++ b/documents/vol3-standard-library/containers/primer/02-linked-list.md @@ -0,0 +1,212 @@ +--- +title: "链表:从不搬家,代价是问路" +description: "数据结构 primer 第二篇。上一篇动态数组头插要全体挪座,这一篇拆掉'连续'这个前提:数据装进节点、指针串珠,插删只改指针不动别人——头插 10 万元素实测 vector 约 317 毫秒、list 约 2.7 毫秒。代价随即到来:没有下标,跳到第 90 万元素 list 慢四个数量级开外;顺序遍历也因节点散落堆上吃缓存的亏,实测慢约 15 倍;每个节点还多背两个指针。地址实验直接给出证据:删除节点后其余地址纹丝不动,splice 剪接前后节点位置一字不变——从不搬家,是真的。全部输出为本机真跑,非转述。" +chapter: 7 +order: 2 +tags: + - host + - cpp-modern + - beginner + - 容器 + - 基础 + - 入门 +difficulty: beginner +platform: host +reading_time_minutes: 15 +prerequisites: + - "数据结构 primer(一):动态数组:一块会搬家的内存" + - "卷一·第 12 章:进程内存布局(栈与堆)" + - "卷一:指针基础(取地址、解引用)" +related: + - "deque、list 与 forward_list" + - "vector 深入:三指针、扩容与迭代器失效" +cpp_standard: [11] +--- + +# 链表:从不搬家,代价是问路 + +上一篇咱们给动态数组留了一道坎:往头部插一个 99,后面 8 个老元素全体右移一格,插得越靠前挪得越多。根子在一个字上——**连续**。格子必须连成一排,`a[i]` 才有地址公式可算,缓存才有局部性可用;可也正是这个"连成一排",定了中间插删的搬运义务:第 0 格要腾给新人,后面所有人都是挡路的。 + +那把"连续"拆掉呢?数据不需要再挤在一条街上,每个人住自己的房子,房子里留一张纸条写着"下一家在哪"。这一拆,插删的搬运义务没了——代价是找元素再无捷径,只能顺着纸条一家家问过去。这一篇咱们就把链表从节点搭起,把它的便宜和它的代价都拿真跑数据摊开。 + +## 把格子拆成节点,用指针串起来 + +链表的零件是**节点**:一块数据,加一个指向前方的指针,住在堆上。您可以把 `next` 想成一张写着"下一家在哪"的纸条,这个比喻咱们整篇都要用。 + +```cpp +struct Node { + int val; // 存的数据 + Node* next; // 指向下一个节点;链尾这里存 nullptr +}; +``` + +咱们手工串一串三个节点,感受一下这个结构的手感: + +```cpp +Node* head = nullptr; // 入口指针:空链 + +Node* c = new Node{30, nullptr}; // 链尾:next 存 nullptr +Node* b = new Node{20, c}; // 中间节点:next 指向 c +Node* a = new Node{10, b}; // 头节点:next 指向 b +head = a; // 入口指向头节点 +``` + +![head 指针指向第一个节点,每个节点带 val 与 next,末节点指向 nullptr](./02-node-chain.drawio) + +跟上一篇对照着看:`head` 的角色相当于 `IntVec::data`,是咱们攥在手里的句柄;区别在于 `data` 指向的 8 格是**一整块连续内存**,而 `head` 指向的第一个节点跟它的下一家毫无地缘关系:三个节点是三次独立的 `new`,分配器把它们放在哪,它们就住在哪。想访问第三个节点的 30,没有公式,只有一条路:从 `head` 走到第一家,读它的纸条,走到第二家,再读纸条,第三家才到。 + +链条的尽头是 `nullptr`:最后一家纸条上写着"没有了",这就是咱们遍历的终止条件。整条链的完整性全靠纸条维系:弄丢一张,后面整段就成了找不回的孤儿(泄漏);写错一张,就会走到不该去的人家(未定义行为)。 + +## 插入和删除:改的是纸条,不是房子 + +现在咱们回来看那道坎。往链表头部插一个 99,要动谁? + +```cpp +void push_front(Node*& head, int x) { + Node* n = new Node{x, head}; // 新节点的 next 指向原来的头节点 + head = n; // head 改指新节点 +} +``` + +两行,完事。新节点搬进来之前就把纸条写好(指向旧的第一家),然后入口改口。老节点们呢?咱们挨个去问,答案都是:不知道、不关心、不动窝,它们手里纸条上的地址一个都没变。删除同理:拿掉一家,只需要它的**前一家**把纸条从"指向它"改成"指向它的下一家",然后 `delete` 掉这个节点。从"后半段全体挪座"到"改两张纸条",这就是拆掉连续换来的头一样好处。 + +咱们把这套动作放到了在线编译器,您可以自己跑、自己改: + + + +咱们拿 `std::list`(标准库的双向链表,下一篇收尾再细说它)跟 `std::vector` 对着跑:各自往头部插 10 万元素,三轮计时(MSVC x64 `/O2`): + +```text +run 1: front-insert 100000 elems | vector = 317366 us | list = 2783 us +run 2: front-insert 100000 elems | vector = 316133 us | list = 2785 us +run 3: front-insert 100000 elems | vector = 317236 us | list = 2546 us +``` + +咱们看数字:vector 约 317 毫秒,list 约 2.7 毫秒,百倍上下。这百倍不是什么玄学,原因上一篇就拆过:vector 每次头插都要挪走全部已有元素,10 万元素总共约 50 亿次元素移动;list 每次头插都是常数个动作,分配节点、写两张纸条。**O(n) 对 O(1),规模一大就是数量级。** + +不过咱们先把话说到前头:上面比的是"头插",比的是两家结构各自的**贵项对便宜项**。要论综合胜负,还得把 list 这边的代价也摊开,下面三节挨个算。 + +## 没有下标:找元素只剩问路 + +vector 的 `v[900000]` 为什么是一步到位?因为格子连续,地址有公式:基地址加 900000 乘以格子宽度,一步算出,纯算术。链表的节点散落堆上,第 900000 个节点住在哪,没有任何公式能算——咱们唯一的办法是从头走 900000 步。所以 `std::list` 干脆**没有 `operator[]`**,写 `L[5]` 编译都过不了:这不是标准库偷懒,O(1) 的下标链表真的做不到,接口给出来,也只能每次从头走。 + +咱们真跑对比:同样访问第 90 万元素各 100 次(`std::next` 是"沿着链走 n 步"的标准写法): + +```text +jump to elem #900000 x 100 tries | vector = 2 us | list = 164761 us +``` + +vector 单次约 20 纳秒,list 单次约 1.6 毫秒,差四个数量级开外。更要命的是这份代价**没法摊还**:vector 的搬家贵在偶尔,摊还之后是常数;链表的问路是每次都贵,走 i 步就是 i 步,咱们问第 10 次和问第 100 万次一样实打实。 + +于是链表的世界里,"位置"这个概念变了味道。vector 里下标就是位置,拿到就能跳;链表里能一步跳到的位置只有两头(`begin()` 和 `end()`,`end()` 的上一格 `rbegin()` 也算,双链表尾部有入口),中间的任何位置咱们都得走着去。这也是为什么上一节说删除只需要前驱改纸条、成本 O(1),却处处带着前提——**前提是您已经走到了那儿、手里攥着迭代器**。位置本身,是要花 O(n) 买的。 + +⚠️ "链表插删 O(1)"这句话省略了主语:是"在**已知位置**插删"O(1),找位置另算 O(n)。咱们拿它去跟"vector 下标访问 O(1)"打擂台,比的根本不是同一件事。 + +## 缓存这一关:散落堆上的代价 + +第二份代价更隐蔽:它藏在硬件里,咱们光看代码看不出来。 + +按理说顺序遍历是链表最体面的活:从头走到尾,一步不绕路,复杂度 O(n) 跟 vector 一样。但咱们真跑一下:两容器各装 100 万元素,从头到尾求和,跑 20 轮计时: + +```text +walk 1000000 elems x 20 rounds | vector = 2462 us | list = 37271 us | sink = 19999980000000 +``` + +咱们同样 100 万元素、同样走一遍,list 慢约 15 倍。复杂度一样,常数差出一个数量级,差在**缓存**上。 + +CPU 取内存不是按字节取的,是按**缓存行**(cache line,通常 64 字节)整块搬的。vector 的 100 万个 `int` 挤在约 4 MB 的连续内存里:一次缓存未命中,64 字节进缓存,16 个 `int` 全在里面,后面 15 次访问全是缓存命中;而且访问模式是严格的"地址递增",硬件预取器(prefetcher)认得这个节奏,会提前把后面的行搬进来,等 CPU 真要用时数据已就位。咱们遍历 vector,几乎全程不等待。 + +链表的节点呢?咱们在地址实验里能直接看到它们住得多散。看真跑输出(`std::list` 装 8 个元素,打印每个元素的地址): + +```text +list of 8, element addresses: + [ 0] 0000019B99206B80 + [ 1] 0000019B99206BC0 + [ 2] 0000019B99206C00 + [ 3] 0000019B99206C20 + [ 4] 0000019B99206C40 + [ 5] 0000019B99206C60 + [ 6] 0000019B991FEBB0 + [ 7] 0000019B991FE670 +``` + +咱们看这份输出:前六个节点恰好住进了同一片街区(这已经是运气好了,连续 `push_back` 时分配器习惯性地把同尺寸的块往一处放),第七、第八个就被分到了 30 多 KB 之外的另一条街。这还只是 8 个节点;百万节点的链,物理地址上天南海北。每走一步,`next` 指向的地址都是一次跳跃:一个节点 24 字节,塞不满一条缓存行,一次未命中只服务一个元素;跳跃的地址毫无规律,预取器彻底失业。**每个元素一次缓存未命中**,这 15 倍就是这么攒出来的。 + +![缓存视角:vector 连续格子一行缓存行顺路服务多个元素;链表节点散落,每步一次跳跃](./02-cache-locality.drawio) + +这条经验值得咱们单独记下:**复杂度相同,物理布局不同,性能可以差一个数量级**。往后您读到任何"链表还是数组"的讨论,局部性都是绕不开的隐藏变量;本教程后面讲容器选择、讲数据结构设计,还会反复回到这一课。 + +## 每个节点多背的指针 + +第三份代价最直白:内存。节点要带纸条,纸条本身占地方,咱们真跑一下(x64): + +```text +sizes: int=4 ptr=8 DNode=24 SNode=16 std::list=16 std::forward_list=8 +``` + +咱们拿 `DNode` 算算:它是双向链表的节点(数据加 `next`、`prev` 两个指针),4 字节的 `int`,配上 16 字节指针再加 4 字节对齐填充,一个节点 24 字节。**装 4 字节数据,住 24 字节的房子**,六倍开销。单链表的 `SNode` 少一个 `prev`,16 字节,也有四倍。这不是 `std::list` 笨,是链表这个结构天生就得这么造:标准库的 `std::list` 节点同样是"一个值加两个指针"的身材。 + +好消息是这个比例随元素变大而摊薄:存 `int` 时指针占三分之二,您要是存 1 KB 的结构体,指针就只占百分之一点五了。所以"链表内存开销大"要辩证着说:**小元素密集的场景才是重灾区**,恰好这类场景又最吃上一节的缓存亏,两个短板经常一起出现。 + +输出里最后两个数也值得咱们多看一眼:`std::list` 对象本身只有 16 字节,双链表两头各一个入口指针,苗条得很;`std::forward_list` 更是只有 8 字节,单指针。不过 `forward_list` 省得不只是节点:它连 `size()` 都没提供。为什么?因为单链表要数清自己有几个元素,只能全链走一遍 O(n),标准索性不给这个接口,逼着不需要计数的使用方省下每个节点里的计数开销。省到这个份上,连 API 都跟着改了。 + +## 从不搬家意味着什么:地址、迭代器与 splice + +三份代价都摊完了,咱们回头看链表最值钱的性质:**节点从生到死住在同一个地址**。不搬家,意味着指向节点的指针、引用、迭代器不会因为别的插入删除而失效;对照上一篇 vector"搬家等于旧地址全废",这是方向性的差别。空口无凭,上真跑。 + +第一个实验:咱们删掉链表中间一个节点,看其余节点的地址如何? + +```text +after erasing the node holding 4: + [ 0] 0000019B99206B80 + [ 1] 0000019B99206BC0 + [ 2] 0000019B99206C00 + [ 3] 0000019B99206C20 + [ 5] 0000019B99206C60 + [ 6] 0000019B991FEBB0 + [ 7] 0000019B991FE670 +``` + +咱们对照删除前的清单:剩下的 7 个节点,地址一位都没动。被删的那家房子退了(`delete`),前后两家纸条重写,其余人照旧过日子。同一实验里 vector 删掉 `v[4]` 之后呢?元素 5 住进了原来 4 的地址,6 住进原来 5 的,7 住进原来 6 的,后半段全体往前挪一格,物理上真搬了。 + +这个实验您也可以在线跑: + + + +第二个实验更有味道,是链表的招牌菜 `splice`(剪接):把一条链中间的一段,整段剪下来接到另一条链上。咱们把 `b` 链中间的 11、12、13 剪到 `a` 链尾部: + +```text +after splice: a = 0 1 2 11 12 13 | b = 10 14 +node addresses now: 11@0000019B991FE5F0 12@0000019B991FE5B0 13@0000019B991FE990 (unchanged) +``` + +咱们把三个节点的地址再对一遍:换了主人,一字不变——**搬的是归属,不是房子**。这个操作只重写了边界上的几根指针(`a` 尾接到 11、13 接 `b` 剩下的 14),一个元素都没碰,O(1) 完工。同样的事让 vector 做,得把三个元素拷过去再把 `b` 的尾巴前移补洞,两头都是 O(n)。凡是"把一段数据在容器间倒手"的场景(任务队列合流、缓冲区移交、定时器轮片搬迁),链表这个"只改归属"的能力都是独门优势。 + +![splice 剪接:节点不动,四根边界指针重连,归属从 b 换到 a](./02-splice.drawio) + +⚠️ 链表迭代器唯一的失效方式是**指向的节点被删**。咱们删除时用 `it = L.erase(it)` 接住返回的下一个位置继续走,这是链表遍历删除的标准姿势;拿着已删节点的迭代器继续解引用,跟上一篇悬空指针是同一种事故。 + +## 什么时候轮到链表 + +三份代价(问路 O(n)、缓存吃亏、指针开销)对一项长处(已知位置插删 O(1) 且地址稳定),选择的轮廓其实清楚了:**咱们手里已经攥着位置、且之后要在这些位置上频繁插删的,链表赢**:维护一堆长期活着的观察者/回调、LRU 缓存的淘汰链、定时器队列,都是这个形态;反过来,**按下标访问、整段扫描为主的,vector 赢**,而且赢得比复杂度表上更狠(那 15 倍的常数差)。 + +还有个常被忽略的中间派:对象大、移动贵的元素,链表的"从不搬家"和 vector 的"扩容整体搬迁"对比会进一步放大:搬一个 8 字节 `int` 是 memmove 里的一瞬,搬一百万个非平凡对象就是实打实的析构加构造风暴(上一篇提过的 `move_if_noexcept` 讲究就在那)。正式的 `std::list`、`std::forward_list` 用法与坑(`merge`、`sort` 为什么是链表特有的版本、跟 `deque` 的三角关系),在本卷 [`deque、list 与 forward_list`](../05-deque-list-forward-list.md) 一篇展开;想亲手搓一条,vol8 的 mini STL 实战在排队等咱们。 + +primer 的下一站是哈希表:一个把这两篇捏在一起的结构——**数组做索引、链表做货舱**,随机访问的快和插删的活,它各借了一半。咱们下篇见。 + +## 参考资源 + +- [cppreference:std::list](https://en.cppreference.com/w/cpp/container/list)——复杂度承诺、迭代器失效规则、`splice`/`merge` 的语义 +- [cppreference:std::forward_list](https://en.cppreference.com/w/cpp/container/forward_list)——单链表,以及"为什么没有 size()"的设计说明 +- 本卷 [`deque、list 与 forward_list`](../05-deque-list-forward-list.md)——`std::list` 的深讲与容器间取舍 +- 本系列 [上一篇:动态数组,一块会搬家的内存](./01-dynamic-array.md)——连续存储的代价清单,本篇的对照组 diff --git a/documents/vol3-standard-library/containers/primer/02-node-chain.drawio b/documents/vol3-standard-library/containers/primer/02-node-chain.drawio new file mode 100644 index 000000000..cf8fdd5bb --- /dev/null +++ b/documents/vol3-standard-library/containers/primer/02-node-chain.drawio @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documents/vol3-standard-library/containers/primer/02-splice.drawio b/documents/vol3-standard-library/containers/primer/02-splice.drawio new file mode 100644 index 000000000..a6387813c --- /dev/null +++ b/documents/vol3-standard-library/containers/primer/02-splice.drawio @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documents/vol3-standard-library/containers/primer/index.md b/documents/vol3-standard-library/containers/primer/index.md new file mode 100644 index 000000000..da60d6281 --- /dev/null +++ b/documents/vol3-standard-library/containers/primer/index.md @@ -0,0 +1,18 @@ +--- +title: "数据结构 primer:容器底下的结构" +sidebar_order: 0 +--- + +# 数据结构 primer:容器底下的结构 + +本卷直接讲 STL 容器的内存布局与失效规矩,可容器不是凭空来的:`vector` 背后是动态数组,`map` 背后是红黑树,`unordered_map` 背后是哈希表。没摸过这些结构本身,读实现层的文章就像没见过地基先看二楼。这个子系列把它们一个个讲清楚:每篇只讲一个结构,讲它解决什么问题、代价在哪里,配真跑证据与示意图;讲完把它交还给对应的容器深讲与手搓实战。 + + + 动态数组:一块会搬家的内存 + 链表:从不搬家,代价是问路 + + +## 相邻内容 + +- [vol3 容器卷](../index.md):std 容器的概念层,本系列的下游 +- [vol8 mini STL 实战](../../../vol8-domains/data-structure/index.md):亲手手搓容器,本系列的实战延伸 diff --git a/documents/vol8-domains/data-structure/02-vector-growth-and-relocation.md b/documents/vol8-domains/data-structure/02-vector-growth-and-relocation.md index fe6424f53..d12ca07d4 100644 --- a/documents/vol8-domains/data-structure/02-vector-growth-and-relocation.md +++ b/documents/vol8-domains/data-structure/02-vector-growth-and-relocation.md @@ -34,6 +34,10 @@ related: 最终 size=40 capacity=64 ``` +这份轨迹做成了动画,您可以播放、暂停,也可以按步进键单步看,把每一次扩容都看个清楚: + + + 40 次入库,只有 5 次扩容,容量一路翻倍。这一篇咱们就把这个轨迹解释清楚,顺便把动态数组整个搓出来。上一篇的 `Relocate` 在扩容那一步原样复用,一行不改。 ## 成员:一个指针带一个计数 diff --git a/scripts/build.ts b/scripts/build.ts index 1fe4feb19..0bfad2015 100644 --- a/scripts/build.ts +++ b/scripts/build.ts @@ -204,7 +204,8 @@ export default withDrawio(defineConfig({ height: '600px', darkMode: 'auto', resize: true, - zoom: true, + // 不传 zoom: 会变成每图 toolbar 配置 → GraphViewer 渲染 body 级悬浮工具条, + // 滚动后飘在图外压正文(2026-09-05 幽灵工具条真凶), 勿再加回 }) ` } @@ -245,7 +246,8 @@ export default withDrawio(defineConfig({ height: '600px', darkMode: 'auto', resize: true, - zoom: true, + // 不传 zoom: 会变成每图 toolbar 配置 → GraphViewer 渲染 body 级悬浮工具条, + // 滚动后飘在图外压正文(2026-09-05 幽灵工具条真凶), 勿再加回 }) ` } diff --git a/site/.vitepress/config/index.ts b/site/.vitepress/config/index.ts index a1f17d0cc..11e5b83bf 100644 --- a/site/.vitepress/config/index.ts +++ b/site/.vitepress/config/index.ts @@ -113,5 +113,7 @@ export default withDrawio(defineConfig({ height: '600px', darkMode: 'auto', resize: true, - zoom: true, }) +// 注: 不传 zoom —— 插件会把它翻译成每张图的 toolbar 配置, GraphViewer 据此 +// 渲染 body 级绝对定位的悬浮工具条(坐标初始化时定格, 滚动后飘到图外压正文), +// 2026-09-05 幽灵工具条事故的真凶, 勿再加回。 diff --git a/site/.vitepress/theme/components/Anim.vue b/site/.vitepress/theme/components/Anim.vue new file mode 100644 index 000000000..6aa069de7 --- /dev/null +++ b/site/.vitepress/theme/components/Anim.vue @@ -0,0 +1,23 @@ + + + diff --git a/site/.vitepress/theme/components/animations/AnimPlayer.vue b/site/.vitepress/theme/components/animations/AnimPlayer.vue new file mode 100644 index 000000000..f007bc55a --- /dev/null +++ b/site/.vitepress/theme/components/animations/AnimPlayer.vue @@ -0,0 +1,693 @@ + + + + + + + diff --git a/site/.vitepress/theme/components/animations/README.md b/site/.vitepress/theme/components/animations/README.md new file mode 100644 index 000000000..0db20a9e1 --- /dev/null +++ b/site/.vitepress/theme/components/animations/README.md @@ -0,0 +1,62 @@ +# animation_maker Web 产物目录(单来源分发) + +**播放器一份, 数据每动画一份。** 生成日期: 2026-09-04。 + +| 路径 | 说明 | +|---|---| +| `AnimPlayer.vue` | 通用播放器, 全部动画共用, 零运行时依赖, 勿手改; 已存在时编译默认跳过, 升级加 `--force-player` | +| `data/.json` | 动画数据(id = DSL 文件名), 播放器唯一输入 | +| `posters/.svg` | 首帧静态图(打印/PDF 等无 JS 场景的可选兜底) | + +## 接入 VitePress(实战验证过的姿势) + +1. 拷 `AnimPlayer.vue` 到 `site/.vitepress/theme/components/animations/` + (仅需一份), 数据放同级 `data/` 子目录。 +2. 注册(懒加载, `theme/index.ts`): + + ```ts + import { defineAsyncComponent } from 'vue' + // enhanceApp({ app }) 内: + app.component('AnimPlayer', defineAsyncComponent(() => + import('./components/animations/AnimPlayer.vue'))) + ``` + + **必须 PascalCase 使用(``)**。不要写 ``: + VitePress 站点常把含连字符的标签交给 `isCustomElement` 当 Web Component, + 结果是静默变原生标签 —— 不报错、不渲染。 + +3. 页面级 import 数据后传入(md 内 ` + + + ``` + + 注意: + - **变量名随意, 不必含 id**; id 带连字符(如 `opp1-vector-growth`)不是 + 合法 JS 标识符, 别把文件名拼进变量名。 + - md 模板表达式在页面作用域求值, `provide/inject` 在其中拿不到 —— + 页面级 import 是唯一通路。 + - 跨深目录建议 vite alias: `{ '@anim': }`, + 之后 `import vecGrowth from '@anim/data/.json'`。 + +## 播放控制 + +- **单步**: 以 DSL 语义 Step 为边界步进(开场是独立一步), 进度条刻度即边界。 +- **倍速**: 0.5x-2x; DSL 中 push 的 `pace` 已折算为该 Step 的速率系数。 +- **键盘**: 进度条可聚焦, 左右方向键微调; `aria-valuenow` 同步。 +- **懒播放**: 进视口才首次自动播放(仅首次); `prefers-reduced-motion` 生效。 + +## SSG/SSR 安全 + +setup 阶段零 `window`/`document`; 渲染是纯函数 `buildFrame(t)`, SSR 输出即 +首帧; rAF/Observer 全在 `onMounted` 且暂停即停转。`pnpm build` 直接过。 + +## 更新播放器 + +编译时播放器已存在则默认跳过(保护消费端); 升级用: + + python -m animation_maker compile .yaml --backend web --force-player diff --git a/site/.vitepress/theme/components/animations/data/opp1-relocate-three-tier.json b/site/.vitepress/theme/components/animations/data/opp1-relocate-three-tier.json new file mode 100644 index 000000000..e9222aeda --- /dev/null +++ b/site/.vitepress/theme/components/animations/data/opp1-relocate-three-tier.json @@ -0,0 +1,3221 @@ +{ + "version": 1, + "id": "opp1-relocate-three-tier", + "title": "Relocate 搬家三档:memcpy / 移动交替 / 拷贝兜底", + "subtitle": "类型特征决定档位 —— 同一批对象的三种搬法", + "source": "projects/vol8-raw-buffer/02-dsl/opp1-relocate-three-tier.yaml", + "backend": "web", + "frame": { + "w": 14.2222, + "h": 8.0 + }, + "palette": { + "bg": "#17171f", + "text": "#ECECE4", + "muted": "#9a9aad", + "fill": "#5EC8E0", + "fillEdge": "#2E86AB", + "emptyEdge": "#4a4a5e", + "grow": "#FFB454", + "numOnFill": "#0e2430", + "ok": "#7BC96A", + "bad": "#E06C75", + "cardBg": "#1e1e2a" + }, + "actors": { + "title": { + "kind": "text", + "text": "Relocate 搬家三档:memcpy / 移动交替 / 拷贝兜底", + "x": 0.0, + "y": 3.4324, + "fs": 0.32, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 9.6576, + "h": 0.4352 + }, + "sub": { + "kind": "text", + "text": "类型特征决定档位 —— 同一批对象的三种搬法", + "x": 0.0, + "y": 2.8988, + "fs": 0.2, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 5.528, + "h": 0.272 + }, + "counter": { + "kind": "text", + "text": "size = 0 capacity = 0", + "x": 0.0, + "y": 1.6, + "fs": 0.3, + "color": "#ECECE4", + "mono": true, + "anchor": "middle", + "w": 5.148, + "h": 0.3 + }, + "_empty": { + "kind": "text", + "text": "还没申请内存", + "x": 0.0, + "y": -1.0, + "fs": 0.2, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 1.584, + "h": 0.272 + }, + "_cap_row": { + "kind": "text", + "text": "申请内存: capacity 0 → 4", + "x": -0.75, + "y": 0.1632, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 3.816, + "h": 0.3264 + }, + "row:row": { + "kind": "cells", + "cap": 64, + "side": 0.22, + "cx": -0.75, + "cy": -1.0, + "w": 4.42, + "h": 1.06, + "cells": [ + { + "i": 0, + "x": -2.85, + "y": -0.58, + "s": 0.22 + }, + { + "i": 1, + "x": -2.57, + "y": -0.58, + "s": 0.22 + }, + { + "i": 2, + "x": -2.29, + "y": -0.58, + "s": 0.22 + }, + { + "i": 3, + "x": -2.01, + "y": -0.58, + "s": 0.22 + }, + { + "i": 4, + "x": -1.73, + "y": -0.58, + "s": 0.22 + }, + { + "i": 5, + "x": -1.45, + "y": -0.58, + "s": 0.22 + }, + { + "i": 6, + "x": -1.17, + "y": -0.58, + "s": 0.22 + }, + { + "i": 7, + "x": -0.89, + "y": -0.58, + "s": 0.22 + }, + { + "i": 8, + "x": -0.61, + "y": -0.58, + "s": 0.22 + }, + { + "i": 9, + "x": -0.33, + "y": -0.58, + "s": 0.22 + }, + { + "i": 10, + "x": -0.05, + "y": -0.58, + "s": 0.22 + }, + { + "i": 11, + "x": 0.23, + "y": -0.58, + "s": 0.22 + }, + { + "i": 12, + "x": 0.51, + "y": -0.58, + "s": 0.22 + }, + { + "i": 13, + "x": 0.79, + "y": -0.58, + "s": 0.22 + }, + { + "i": 14, + "x": 1.07, + "y": -0.58, + "s": 0.22 + }, + { + "i": 15, + "x": 1.35, + "y": -0.58, + "s": 0.22 + }, + { + "i": 16, + "x": -2.85, + "y": -0.86, + "s": 0.22 + }, + { + "i": 17, + "x": -2.57, + "y": -0.86, + "s": 0.22 + }, + { + "i": 18, + "x": -2.29, + "y": -0.86, + "s": 0.22 + }, + { + "i": 19, + "x": -2.01, + "y": -0.86, + "s": 0.22 + }, + { + "i": 20, + "x": -1.73, + "y": -0.86, + "s": 0.22 + }, + { + "i": 21, + "x": -1.45, + "y": -0.86, + "s": 0.22 + }, + { + "i": 22, + "x": -1.17, + "y": -0.86, + "s": 0.22 + }, + { + "i": 23, + "x": -0.89, + "y": -0.86, + "s": 0.22 + }, + { + "i": 24, + "x": -0.61, + "y": -0.86, + "s": 0.22 + }, + { + "i": 25, + "x": -0.33, + "y": -0.86, + "s": 0.22 + }, + { + "i": 26, + "x": -0.05, + "y": -0.86, + "s": 0.22 + }, + { + "i": 27, + "x": 0.23, + "y": -0.86, + "s": 0.22 + }, + { + "i": 28, + "x": 0.51, + "y": -0.86, + "s": 0.22 + }, + { + "i": 29, + "x": 0.79, + "y": -0.86, + "s": 0.22 + }, + { + "i": 30, + "x": 1.07, + "y": -0.86, + "s": 0.22 + }, + { + "i": 31, + "x": 1.35, + "y": -0.86, + "s": 0.22 + }, + { + "i": 32, + "x": -2.85, + "y": -1.14, + "s": 0.22 + }, + { + "i": 33, + "x": -2.57, + "y": -1.14, + "s": 0.22 + }, + { + "i": 34, + "x": -2.29, + "y": -1.14, + "s": 0.22 + }, + { + "i": 35, + "x": -2.01, + "y": -1.14, + "s": 0.22 + }, + { + "i": 36, + "x": -1.73, + "y": -1.14, + "s": 0.22 + }, + { + "i": 37, + "x": -1.45, + "y": -1.14, + "s": 0.22 + }, + { + "i": 38, + "x": -1.17, + "y": -1.14, + "s": 0.22 + }, + { + "i": 39, + "x": -0.89, + "y": -1.14, + "s": 0.22 + }, + { + "i": 40, + "x": -0.61, + "y": -1.14, + "s": 0.22 + }, + { + "i": 41, + "x": -0.33, + "y": -1.14, + "s": 0.22 + }, + { + "i": 42, + "x": -0.05, + "y": -1.14, + "s": 0.22 + }, + { + "i": 43, + "x": 0.23, + "y": -1.14, + "s": 0.22 + }, + { + "i": 44, + "x": 0.51, + "y": -1.14, + "s": 0.22 + }, + { + "i": 45, + "x": 0.79, + "y": -1.14, + "s": 0.22 + }, + { + "i": 46, + "x": 1.07, + "y": -1.14, + "s": 0.22 + }, + { + "i": 47, + "x": 1.35, + "y": -1.14, + "s": 0.22 + }, + { + "i": 48, + "x": -2.85, + "y": -1.42, + "s": 0.22 + }, + { + "i": 49, + "x": -2.57, + "y": -1.42, + "s": 0.22 + }, + { + "i": 50, + "x": -2.29, + "y": -1.42, + "s": 0.22 + }, + { + "i": 51, + "x": -2.01, + "y": -1.42, + "s": 0.22 + }, + { + "i": 52, + "x": -1.73, + "y": -1.42, + "s": 0.22 + }, + { + "i": 53, + "x": -1.45, + "y": -1.42, + "s": 0.22 + }, + { + "i": 54, + "x": -1.17, + "y": -1.42, + "s": 0.22 + }, + { + "i": 55, + "x": -0.89, + "y": -1.42, + "s": 0.22 + }, + { + "i": 56, + "x": -0.61, + "y": -1.42, + "s": 0.22 + }, + { + "i": 57, + "x": -0.33, + "y": -1.42, + "s": 0.22 + }, + { + "i": 58, + "x": -0.05, + "y": -1.42, + "s": 0.22 + }, + { + "i": 59, + "x": 0.23, + "y": -1.42, + "s": 0.22 + }, + { + "i": 60, + "x": 0.51, + "y": -1.42, + "s": 0.22 + }, + { + "i": 61, + "x": 0.79, + "y": -1.42, + "s": 0.22 + }, + { + "i": 62, + "x": 1.07, + "y": -1.42, + "s": 0.22 + }, + { + "i": 63, + "x": 1.35, + "y": -1.42, + "s": 0.22 + } + ], + "idx": [] + }, + "show:code_t1": { + "kind": "code", + "fs": 0.3, + "lh": 0.387, + "pitch": 0.607, + "gutW": 0.1584, + "bodyW": 5.346, + "w": 6.3244, + "h": 1.514, + "rows": [ + { + "text": "if (triv_copy)", + "w": 2.772 + }, + { + "text": " memcpy(t, f, bytes); // 1", + "w": 5.346 + } + ], + "cx": -0.75, + "cy": -2.75 + }, + "show:lb_t1": { + "kind": "text", + "text": "第①档 平凡可拷贝:整块 memcpy", + "x": -4.4, + "y": 2.4, + "fs": 0.2, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 3.896, + "h": 0.272, + "id": "lb_t1" + }, + "_cap_row_4": { + "kind": "text", + "text": "满了!capacity 4 → 8,grow_to!", + "x": -0.75, + "y": -2.1732, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 4.8768, + "h": 0.3264 + }, + "_grow4:row": { + "kind": "cells", + "cap": 8, + "side": 0.5, + "cx": -0.75, + "cy": -3.51, + "w": 4.42, + "h": 0.5, + "cells": [ + { + "i": 0, + "x": -2.71, + "y": -3.51, + "s": 0.5 + }, + { + "i": 1, + "x": -2.15, + "y": -3.51, + "s": 0.5 + }, + { + "i": 2, + "x": -1.59, + "y": -3.51, + "s": 0.5 + }, + { + "i": 3, + "x": -1.03, + "y": -3.51, + "s": 0.5 + }, + { + "i": 4, + "x": -0.47, + "y": -3.51, + "s": 0.5 + }, + { + "i": 5, + "x": 0.09, + "y": -3.51, + "s": 0.5 + }, + { + "i": 6, + "x": 0.65, + "y": -3.51, + "s": 0.5 + }, + { + "i": 7, + "x": 1.21, + "y": -3.51, + "s": 0.5 + } + ], + "idx": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ] + }, + "_raii_row_4": { + "kind": "text", + "text": "旧对象已逐个析构, 内存 RAII 归还", + "x": -0.75, + "y": -0.3176, + "fs": 0.18, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 3.744, + "h": 0.2448 + }, + "show:code_t2": { + "kind": "code", + "fs": 0.3, + "lh": 0.387, + "pitch": 0.607, + "gutW": 0.1584, + "bodyW": 5.94, + "w": 6.9184, + "h": 1.514, + "rows": [ + { + "text": "new (t) T(std::move(*f)); // 2", + "w": 5.94 + }, + { + "text": "f->~T(); // 4", + "w": 5.94 + } + ], + "cx": -0.75, + "cy": -2.75 + }, + "show:lb_t2": { + "kind": "text", + "text": "第②档 能移动:新生+老死 交替", + "x": -4.4, + "y": 2.4, + "fs": 0.2, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 3.804, + "h": 0.272, + "id": "lb_t2" + }, + "ptr:p_from": { + "kind": "ptr", + "id": "p_from", + "name": "from", + "above": true, + "x": -1.59, + "tipY": -0.51, + "baseY": -0.12, + "txt": { + "text": "from", + "x": -1.59, + "y": 0.04, + "fs": 0.22, + "color": "#ECECE4", + "mono": true, + "anchor": "middle", + "w": 0.5808, + "h": 0.22 + }, + "cx": -1.59, + "cy": -0.18, + "w": 0.5808, + "h": 0.66 + }, + "ptr:p_to": { + "kind": "ptr", + "id": "p_to", + "name": "to", + "above": true, + "x": 0.65, + "tipY": -0.51, + "baseY": -0.12, + "txt": { + "text": "to", + "x": 0.65, + "y": 0.04, + "fs": 0.22, + "color": "#ECECE4", + "mono": true, + "anchor": "middle", + "w": 0.2904, + "h": 0.22 + }, + "cx": 0.65, + "cy": -0.18, + "w": 0.2904, + "h": 0.66 + }, + "_cap_row_8": { + "kind": "text", + "text": "满了!capacity 8 → 32,grow_to!", + "x": -0.75, + "y": -2.1132, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 5.0256, + "h": 0.3264 + }, + "_grow8:row": { + "kind": "cells", + "cap": 32, + "side": 0.3, + "cx": -0.75, + "cy": -3.45, + "w": 5.7, + "h": 0.66, + "cells": [ + { + "i": 0, + "x": -3.45, + "y": -3.27, + "s": 0.3 + }, + { + "i": 1, + "x": -3.09, + "y": -3.27, + "s": 0.3 + }, + { + "i": 2, + "x": -2.73, + "y": -3.27, + "s": 0.3 + }, + { + "i": 3, + "x": -2.37, + "y": -3.27, + "s": 0.3 + }, + { + "i": 4, + "x": -2.01, + "y": -3.27, + "s": 0.3 + }, + { + "i": 5, + "x": -1.65, + "y": -3.27, + "s": 0.3 + }, + { + "i": 6, + "x": -1.29, + "y": -3.27, + "s": 0.3 + }, + { + "i": 7, + "x": -0.93, + "y": -3.27, + "s": 0.3 + }, + { + "i": 8, + "x": -0.57, + "y": -3.27, + "s": 0.3 + }, + { + "i": 9, + "x": -0.21, + "y": -3.27, + "s": 0.3 + }, + { + "i": 10, + "x": 0.15, + "y": -3.27, + "s": 0.3 + }, + { + "i": 11, + "x": 0.51, + "y": -3.27, + "s": 0.3 + }, + { + "i": 12, + "x": 0.87, + "y": -3.27, + "s": 0.3 + }, + { + "i": 13, + "x": 1.23, + "y": -3.27, + "s": 0.3 + }, + { + "i": 14, + "x": 1.59, + "y": -3.27, + "s": 0.3 + }, + { + "i": 15, + "x": 1.95, + "y": -3.27, + "s": 0.3 + }, + { + "i": 16, + "x": -3.45, + "y": -3.63, + "s": 0.3 + }, + { + "i": 17, + "x": -3.09, + "y": -3.63, + "s": 0.3 + }, + { + "i": 18, + "x": -2.73, + "y": -3.63, + "s": 0.3 + }, + { + "i": 19, + "x": -2.37, + "y": -3.63, + "s": 0.3 + }, + { + "i": 20, + "x": -2.01, + "y": -3.63, + "s": 0.3 + }, + { + "i": 21, + "x": -1.65, + "y": -3.63, + "s": 0.3 + }, + { + "i": 22, + "x": -1.29, + "y": -3.63, + "s": 0.3 + }, + { + "i": 23, + "x": -0.93, + "y": -3.63, + "s": 0.3 + }, + { + "i": 24, + "x": -0.57, + "y": -3.63, + "s": 0.3 + }, + { + "i": 25, + "x": -0.21, + "y": -3.63, + "s": 0.3 + }, + { + "i": 26, + "x": 0.15, + "y": -3.63, + "s": 0.3 + }, + { + "i": 27, + "x": 0.51, + "y": -3.63, + "s": 0.3 + }, + { + "i": 28, + "x": 0.87, + "y": -3.63, + "s": 0.3 + }, + { + "i": 29, + "x": 1.23, + "y": -3.63, + "s": 0.3 + }, + { + "i": 30, + "x": 1.59, + "y": -3.63, + "s": 0.3 + }, + { + "i": 31, + "x": 1.95, + "y": -3.63, + "s": 0.3 + } + ], + "idx": [] + }, + "_raii_row_8": { + "kind": "text", + "text": "旧对象已逐个析构, 内存 RAII 归还", + "x": -0.75, + "y": -0.3776, + "fs": 0.18, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 3.744, + "h": 0.2448 + }, + "show:code_t3": { + "kind": "code", + "fs": 0.3, + "lh": 0.387, + "pitch": 0.607, + "gutW": 0.1584, + "bodyW": 4.752, + "w": 5.7304, + "h": 1.514, + "rows": [ + { + "text": "else new (t) T(*f); // 3", + "w": 4.752 + }, + { + "text": "f->~T(); // 4", + "w": 4.752 + } + ], + "cx": -0.75, + "cy": -2.75 + }, + "show:lb_t3": { + "kind": "text", + "text": "第③档 CopyOnly:拷贝兜底", + "x": -4.4, + "y": 2.4, + "fs": 0.2, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 3.228, + "h": 0.272, + "id": "lb_t3" + }, + "_cap_row_32": { + "kind": "text", + "text": "满了!capacity 32 → 64,grow_to!", + "x": -0.75, + "y": -2.1932, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 5.1744, + "h": 0.3264 + }, + "_grow32:row": { + "kind": "cells", + "cap": 64, + "side": 0.22, + "cx": -0.75, + "cy": -3.53, + "w": 4.42, + "h": 1.06, + "cells": [ + { + "i": 0, + "x": -2.85, + "y": -3.11, + "s": 0.22 + }, + { + "i": 1, + "x": -2.57, + "y": -3.11, + "s": 0.22 + }, + { + "i": 2, + "x": -2.29, + "y": -3.11, + "s": 0.22 + }, + { + "i": 3, + "x": -2.01, + "y": -3.11, + "s": 0.22 + }, + { + "i": 4, + "x": -1.73, + "y": -3.11, + "s": 0.22 + }, + { + "i": 5, + "x": -1.45, + "y": -3.11, + "s": 0.22 + }, + { + "i": 6, + "x": -1.17, + "y": -3.11, + "s": 0.22 + }, + { + "i": 7, + "x": -0.89, + "y": -3.11, + "s": 0.22 + }, + { + "i": 8, + "x": -0.61, + "y": -3.11, + "s": 0.22 + }, + { + "i": 9, + "x": -0.33, + "y": -3.11, + "s": 0.22 + }, + { + "i": 10, + "x": -0.05, + "y": -3.11, + "s": 0.22 + }, + { + "i": 11, + "x": 0.23, + "y": -3.11, + "s": 0.22 + }, + { + "i": 12, + "x": 0.51, + "y": -3.11, + "s": 0.22 + }, + { + "i": 13, + "x": 0.79, + "y": -3.11, + "s": 0.22 + }, + { + "i": 14, + "x": 1.07, + "y": -3.11, + "s": 0.22 + }, + { + "i": 15, + "x": 1.35, + "y": -3.11, + "s": 0.22 + }, + { + "i": 16, + "x": -2.85, + "y": -3.39, + "s": 0.22 + }, + { + "i": 17, + "x": -2.57, + "y": -3.39, + "s": 0.22 + }, + { + "i": 18, + "x": -2.29, + "y": -3.39, + "s": 0.22 + }, + { + "i": 19, + "x": -2.01, + "y": -3.39, + "s": 0.22 + }, + { + "i": 20, + "x": -1.73, + "y": -3.39, + "s": 0.22 + }, + { + "i": 21, + "x": -1.45, + "y": -3.39, + "s": 0.22 + }, + { + "i": 22, + "x": -1.17, + "y": -3.39, + "s": 0.22 + }, + { + "i": 23, + "x": -0.89, + "y": -3.39, + "s": 0.22 + }, + { + "i": 24, + "x": -0.61, + "y": -3.39, + "s": 0.22 + }, + { + "i": 25, + "x": -0.33, + "y": -3.39, + "s": 0.22 + }, + { + "i": 26, + "x": -0.05, + "y": -3.39, + "s": 0.22 + }, + { + "i": 27, + "x": 0.23, + "y": -3.39, + "s": 0.22 + }, + { + "i": 28, + "x": 0.51, + "y": -3.39, + "s": 0.22 + }, + { + "i": 29, + "x": 0.79, + "y": -3.39, + "s": 0.22 + }, + { + "i": 30, + "x": 1.07, + "y": -3.39, + "s": 0.22 + }, + { + "i": 31, + "x": 1.35, + "y": -3.39, + "s": 0.22 + }, + { + "i": 32, + "x": -2.85, + "y": -3.67, + "s": 0.22 + }, + { + "i": 33, + "x": -2.57, + "y": -3.67, + "s": 0.22 + }, + { + "i": 34, + "x": -2.29, + "y": -3.67, + "s": 0.22 + }, + { + "i": 35, + "x": -2.01, + "y": -3.67, + "s": 0.22 + }, + { + "i": 36, + "x": -1.73, + "y": -3.67, + "s": 0.22 + }, + { + "i": 37, + "x": -1.45, + "y": -3.67, + "s": 0.22 + }, + { + "i": 38, + "x": -1.17, + "y": -3.67, + "s": 0.22 + }, + { + "i": 39, + "x": -0.89, + "y": -3.67, + "s": 0.22 + }, + { + "i": 40, + "x": -0.61, + "y": -3.67, + "s": 0.22 + }, + { + "i": 41, + "x": -0.33, + "y": -3.67, + "s": 0.22 + }, + { + "i": 42, + "x": -0.05, + "y": -3.67, + "s": 0.22 + }, + { + "i": 43, + "x": 0.23, + "y": -3.67, + "s": 0.22 + }, + { + "i": 44, + "x": 0.51, + "y": -3.67, + "s": 0.22 + }, + { + "i": 45, + "x": 0.79, + "y": -3.67, + "s": 0.22 + }, + { + "i": 46, + "x": 1.07, + "y": -3.67, + "s": 0.22 + }, + { + "i": 47, + "x": 1.35, + "y": -3.67, + "s": 0.22 + }, + { + "i": 48, + "x": -2.85, + "y": -3.95, + "s": 0.22 + }, + { + "i": 49, + "x": -2.57, + "y": -3.95, + "s": 0.22 + }, + { + "i": 50, + "x": -2.29, + "y": -3.95, + "s": 0.22 + }, + { + "i": 51, + "x": -2.01, + "y": -3.95, + "s": 0.22 + }, + { + "i": 52, + "x": -1.73, + "y": -3.95, + "s": 0.22 + }, + { + "i": 53, + "x": -1.45, + "y": -3.95, + "s": 0.22 + }, + { + "i": 54, + "x": -1.17, + "y": -3.95, + "s": 0.22 + }, + { + "i": 55, + "x": -0.89, + "y": -3.95, + "s": 0.22 + }, + { + "i": 56, + "x": -0.61, + "y": -3.95, + "s": 0.22 + }, + { + "i": 57, + "x": -0.33, + "y": -3.95, + "s": 0.22 + }, + { + "i": 58, + "x": -0.05, + "y": -3.95, + "s": 0.22 + }, + { + "i": 59, + "x": 0.23, + "y": -3.95, + "s": 0.22 + }, + { + "i": 60, + "x": 0.51, + "y": -3.95, + "s": 0.22 + }, + { + "i": 61, + "x": 0.79, + "y": -3.95, + "s": 0.22 + }, + { + "i": 62, + "x": 1.07, + "y": -3.95, + "s": 0.22 + }, + { + "i": 63, + "x": 1.35, + "y": -3.95, + "s": 0.22 + } + ], + "idx": [] + }, + "_raii_row_32": { + "kind": "text", + "text": "旧对象已逐个析构, 内存 RAII 归还", + "x": -0.75, + "y": -0.2976, + "fs": 0.18, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 3.744, + "h": 0.2448 + }, + "concl:0": { + "kind": "text", + "text": "搬家三档:memcpy 整块 / 移动交替 / 拷贝兜底", + "x": 0.0, + "y": -2.084, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 6.6864, + "h": 0.3264 + }, + "concl:1": { + "kind": "text", + "text": "能移动就别拷贝:新生一个,老死一个", + "x": 0.0, + "y": -2.6604, + "fs": 0.24, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 5.3856, + "h": 0.3264 + }, + "concl:2": { + "kind": "text", + "text": "搬 5 个计数还是 5 —— 验收绿", + "x": 0.0, + "y": -3.2368, + "fs": 0.24, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 4.5264, + "h": 0.3264 + } + }, + "steps": [ + { + "kind": "intro", + "label": "开场", + "note": "", + "duration": 5.8, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "title", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "fadein", + "target": "sub", + "t": 2.4, + "dur": 0.5 + }, + { + "type": "fadein", + "target": "counter", + "t": 2.4, + "dur": 0.5 + }, + { + "type": "write", + "target": "_empty", + "t": 3.4, + "dur": 1.07 + }, + { + "type": "fadeout", + "target": "_empty", + "t": 5.5, + "dur": 0.3 + } + ] + }, + { + "kind": "grow_to", + "label": "申请 4", + "note": "capacity 0->4, 搬 0 格", + "duration": 6.15, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "row:row", + "g": { + "kind": "cells", + "cap": 4, + "side": 0.62, + "cx": -0.75, + "cy": -1.0, + "w": 2.66, + "h": 0.62, + "cells": [ + { + "i": 0, + "x": -1.77, + "y": -1.0, + "s": 0.62 + }, + { + "i": 1, + "x": -1.09, + "y": -1.0, + "s": 0.62 + }, + { + "i": 2, + "x": -0.41, + "y": -1.0, + "s": 0.62 + }, + { + "i": 3, + "x": 0.27, + "y": -1.0, + "s": 0.62 + } + ], + "idx": [ + 1, + 2, + 3, + 4 + ] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "fadeout", + "target": "_cap_row", + "t": 5.6, + "dur": 0.3 + }, + { + "type": "counter", + "text": "size = 0 capacity = 4", + "t": 5.9, + "dur": 0.25 + } + ] + }, + { + "kind": "push", + "label": "push ×4 (slow)", + "note": "[0,4)", + "duration": 1.2, + "speed": 0.6, + "events": [ + { + "type": "fill", + "target": "row:row", + "i": 0, + "s": 1, + "cap": 4, + "counter": true, + "t": 0.0, + "dur": 0.3 + }, + { + "type": "fill", + "target": "row:row", + "i": 1, + "s": 2, + "cap": 4, + "counter": true, + "t": 0.3, + "dur": 0.3 + }, + { + "type": "fill", + "target": "row:row", + "i": 2, + "s": 3, + "cap": 4, + "counter": true, + "t": 0.6, + "dur": 0.3 + }, + { + "type": "fill", + "target": "row:row", + "i": 3, + "s": 4, + "cap": 4, + "counter": true, + "t": 0.9, + "dur": 0.3 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "0.4s", + "duration": 0.4, + "speed": 1.0, + "events": [] + }, + { + "kind": "show", + "label": "show code_t1", + "note": "", + "duration": 2.8, + "speed": 1.0, + "events": [ + { + "type": "code_show", + "target": "show:code_t1", + "t": 0.0, + "dur": 2.8 + } + ] + }, + { + "kind": "show", + "label": "show lb_t1", + "note": "", + "duration": 2.4, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "show:lb_t1", + "t": 0.0, + "dur": 2.4 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "2.2s", + "duration": 2.2, + "speed": 1.0, + "events": [] + }, + { + "kind": "hide", + "label": "hide lb_t1", + "note": "", + "duration": 1.15, + "speed": 1.0, + "events": [ + { + "type": "fadeout", + "target": "show:lb_t1", + "t": 0.75, + "dur": 0.4 + } + ] + }, + { + "kind": "hide", + "label": "hide code_t1", + "note": "", + "duration": 0.75, + "speed": 1.0, + "events": [ + { + "type": "fadeout", + "target": "show:code_t1", + "t": 0.35, + "dur": 0.4 + } + ] + }, + { + "kind": "grow_to", + "label": "扩容 4→8", + "note": "capacity 4->8, 搬 4 格", + "duration": 11.05, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row_4", + "indicate": "row:row", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "_grow4:row", + "g": { + "kind": "cells", + "cap": 8, + "side": 0.5, + "cx": -0.75, + "cy": -3.51, + "w": 4.42, + "h": 0.5, + "cells": [ + { + "i": 0, + "x": -2.71, + "y": -3.51, + "s": 0.5 + }, + { + "i": 1, + "x": -2.15, + "y": -3.51, + "s": 0.5 + }, + { + "i": 2, + "x": -1.59, + "y": -3.51, + "s": 0.5 + }, + { + "i": 3, + "x": -1.03, + "y": -3.51, + "s": 0.5 + }, + { + "i": 4, + "x": -0.47, + "y": -3.51, + "s": 0.5 + }, + { + "i": 5, + "x": 0.09, + "y": -3.51, + "s": 0.5 + }, + { + "i": 6, + "x": 0.65, + "y": -3.51, + "s": 0.5 + }, + { + "i": 7, + "x": 1.21, + "y": -3.51, + "s": 0.5 + } + ], + "idx": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "relocate", + "src": "row:row", + "dst": "_grow4:row", + "count": 4, + "t": 3.1, + "dur": 1.0 + }, + { + "type": "row_destroy", + "target": "row:row", + "write": "_raii_row_4", + "t": 4.1, + "dur": 2.4 + }, + { + "type": "fadeout", + "target": "_cap_row_4", + "t": 9.7, + "dur": 0.3 + }, + { + "type": "fadeout", + "target": "_raii_row_4", + "t": 10.0, + "dur": 0.3 + }, + { + "type": "row_swap", + "target": "row:row", + "tmp": "_grow4:row", + "to": [ + -0.75, + -1.0 + ], + "t": 10.3, + "dur": 0.5 + }, + { + "type": "counter", + "text": "size = 4 capacity = 8", + "t": 10.8, + "dur": 0.25 + } + ] + }, + { + "kind": "highlight", + "label": "高亮 [0,4) gold", + "note": "", + "duration": 1.6, + "speed": 1.0, + "events": [ + { + "type": "hl_show", + "frame": { + "kind": "frame", + "color": "#FFB454", + "cx": -1.87, + "cy": -1.0, + "w": 2.28, + "h": 0.6 + }, + "t": 0.0, + "dur": 0.4 + }, + { + "type": "hl_hide", + "frame": { + "kind": "frame", + "color": "#FFB454", + "cx": -1.87, + "cy": -1.0, + "w": 2.28, + "h": 0.6 + }, + "t": 1.3, + "dur": 0.3 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "0.3s", + "duration": 0.3, + "speed": 1.0, + "events": [] + }, + { + "kind": "push", + "label": "push ×4 (normal)", + "note": "[4,8)", + "duration": 0.72, + "speed": 1.0, + "events": [ + { + "type": "fill", + "target": "row:row", + "i": 4, + "s": 5, + "cap": 8, + "counter": true, + "t": 0.0, + "dur": 0.18 + }, + { + "type": "fill", + "target": "row:row", + "i": 5, + "s": 6, + "cap": 8, + "counter": true, + "t": 0.18, + "dur": 0.18 + }, + { + "type": "fill", + "target": "row:row", + "i": 6, + "s": 7, + "cap": 8, + "counter": true, + "t": 0.36, + "dur": 0.18 + }, + { + "type": "fill", + "target": "row:row", + "i": 7, + "s": 8, + "cap": 8, + "counter": true, + "t": 0.54, + "dur": 0.18 + } + ] + }, + { + "kind": "show", + "label": "show code_t2", + "note": "", + "duration": 2.8, + "speed": 1.0, + "events": [ + { + "type": "code_show", + "target": "show:code_t2", + "t": 0.0, + "dur": 2.8 + } + ] + }, + { + "kind": "show", + "label": "show lb_t2", + "note": "", + "duration": 2.27, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "show:lb_t2", + "t": 0.0, + "dur": 2.27 + } + ] + }, + { + "kind": "point_to", + "label": "指针 from 出场", + "note": "index 0", + "duration": 0.4, + "speed": 1.0, + "events": [ + { + "type": "ptr_show", + "target": "p_from", + "t": 0.0, + "dur": 0.4 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "0.4s", + "duration": 0.4, + "speed": 1.0, + "events": [] + }, + { + "kind": "point_to", + "label": "指针 from → 2", + "note": "index 2", + "duration": 0.3, + "speed": 1.0, + "events": [ + { + "type": "ptr_move", + "target": "p_from", + "to": [ + -1.59, + -0.51 + ], + "t": 0.0, + "dur": 0.3 + } + ] + }, + { + "kind": "point_to", + "label": "指针 to 出场", + "note": "index 6", + "duration": 0.4, + "speed": 1.0, + "events": [ + { + "type": "ptr_show", + "target": "p_to", + "t": 0.0, + "dur": 0.4 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "0.8s", + "duration": 0.8, + "speed": 1.0, + "events": [] + }, + { + "kind": "hide", + "label": "hide lb_t2", + "note": "", + "duration": 0.75, + "speed": 1.0, + "events": [ + { + "type": "fadeout", + "target": "show:lb_t2", + "t": 0.35, + "dur": 0.4 + } + ] + }, + { + "kind": "hide", + "label": "hide code_t2", + "note": "", + "duration": 0.75, + "speed": 1.0, + "events": [ + { + "type": "fadeout", + "target": "show:code_t2", + "t": 0.35, + "dur": 0.4 + } + ] + }, + { + "kind": "grow_to", + "label": "扩容 8→32", + "note": "capacity 8->32, 搬 8 格", + "duration": 11.65, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row_8", + "indicate": "row:row", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "_grow8:row", + "g": { + "kind": "cells", + "cap": 32, + "side": 0.3, + "cx": -0.75, + "cy": -3.45, + "w": 5.7, + "h": 0.66, + "cells": [ + { + "i": 0, + "x": -3.45, + "y": -3.27, + "s": 0.3 + }, + { + "i": 1, + "x": -3.09, + "y": -3.27, + "s": 0.3 + }, + { + "i": 2, + "x": -2.73, + "y": -3.27, + "s": 0.3 + }, + { + "i": 3, + "x": -2.37, + "y": -3.27, + "s": 0.3 + }, + { + "i": 4, + "x": -2.01, + "y": -3.27, + "s": 0.3 + }, + { + "i": 5, + "x": -1.65, + "y": -3.27, + "s": 0.3 + }, + { + "i": 6, + "x": -1.29, + "y": -3.27, + "s": 0.3 + }, + { + "i": 7, + "x": -0.93, + "y": -3.27, + "s": 0.3 + }, + { + "i": 8, + "x": -0.57, + "y": -3.27, + "s": 0.3 + }, + { + "i": 9, + "x": -0.21, + "y": -3.27, + "s": 0.3 + }, + { + "i": 10, + "x": 0.15, + "y": -3.27, + "s": 0.3 + }, + { + "i": 11, + "x": 0.51, + "y": -3.27, + "s": 0.3 + }, + { + "i": 12, + "x": 0.87, + "y": -3.27, + "s": 0.3 + }, + { + "i": 13, + "x": 1.23, + "y": -3.27, + "s": 0.3 + }, + { + "i": 14, + "x": 1.59, + "y": -3.27, + "s": 0.3 + }, + { + "i": 15, + "x": 1.95, + "y": -3.27, + "s": 0.3 + }, + { + "i": 16, + "x": -3.45, + "y": -3.63, + "s": 0.3 + }, + { + "i": 17, + "x": -3.09, + "y": -3.63, + "s": 0.3 + }, + { + "i": 18, + "x": -2.73, + "y": -3.63, + "s": 0.3 + }, + { + "i": 19, + "x": -2.37, + "y": -3.63, + "s": 0.3 + }, + { + "i": 20, + "x": -2.01, + "y": -3.63, + "s": 0.3 + }, + { + "i": 21, + "x": -1.65, + "y": -3.63, + "s": 0.3 + }, + { + "i": 22, + "x": -1.29, + "y": -3.63, + "s": 0.3 + }, + { + "i": 23, + "x": -0.93, + "y": -3.63, + "s": 0.3 + }, + { + "i": 24, + "x": -0.57, + "y": -3.63, + "s": 0.3 + }, + { + "i": 25, + "x": -0.21, + "y": -3.63, + "s": 0.3 + }, + { + "i": 26, + "x": 0.15, + "y": -3.63, + "s": 0.3 + }, + { + "i": 27, + "x": 0.51, + "y": -3.63, + "s": 0.3 + }, + { + "i": 28, + "x": 0.87, + "y": -3.63, + "s": 0.3 + }, + { + "i": 29, + "x": 1.23, + "y": -3.63, + "s": 0.3 + }, + { + "i": 30, + "x": 1.59, + "y": -3.63, + "s": 0.3 + }, + { + "i": 31, + "x": 1.95, + "y": -3.63, + "s": 0.3 + } + ], + "idx": [] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "relocate", + "src": "row:row", + "dst": "_grow8:row", + "count": 8, + "t": 3.1, + "dur": 1.0 + }, + { + "type": "row_destroy", + "target": "row:row", + "write": "_raii_row_8", + "t": 4.1, + "dur": 2.4 + }, + { + "type": "fadeout", + "target": "_cap_row_8", + "t": 9.7, + "dur": 0.3 + }, + { + "type": "fadeout", + "target": "_raii_row_8", + "t": 10.0, + "dur": 0.3 + }, + { + "type": "row_swap", + "target": "row:row", + "tmp": "_grow8:row", + "to": [ + -0.75, + -1.0 + ], + "t": 10.3, + "dur": 0.5 + }, + { + "type": "counter", + "text": "size = 8 capacity = 32", + "t": 10.8, + "dur": 0.25 + }, + { + "type": "ptr_move", + "target": "p_from", + "to": [ + -2.73, + -0.43 + ], + "t": 11.05, + "dur": 0.3 + }, + { + "type": "ptr_move", + "target": "p_to", + "to": [ + -1.29, + -0.43 + ], + "t": 11.35, + "dur": 0.3 + } + ] + }, + { + "kind": "highlight", + "label": "高亮 [8,16) green", + "note": "", + "duration": 1.6, + "speed": 1.0, + "events": [ + { + "type": "hl_show", + "frame": { + "kind": "frame", + "color": "#7BC96A", + "cx": 0.69, + "cy": -0.82, + "w": 2.92, + "h": 0.4 + }, + "t": 0.0, + "dur": 0.4 + }, + { + "type": "hl_hide", + "frame": { + "kind": "frame", + "color": "#7BC96A", + "cx": 0.69, + "cy": -0.82, + "w": 2.92, + "h": 0.4 + }, + "t": 1.3, + "dur": 0.3 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "0.3s", + "duration": 0.3, + "speed": 1.0, + "events": [] + }, + { + "kind": "show", + "label": "show code_t3", + "note": "", + "duration": 2.8, + "speed": 1.0, + "events": [ + { + "type": "code_show", + "target": "show:code_t3", + "t": 0.0, + "dur": 2.8 + } + ] + }, + { + "kind": "show", + "label": "show lb_t3", + "note": "", + "duration": 2.39, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "show:lb_t3", + "t": 0.0, + "dur": 2.39 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "1.2s", + "duration": 1.2, + "speed": 1.0, + "events": [] + }, + { + "kind": "push", + "label": "push ×24 (turbo)", + "note": "[8,32)", + "duration": 1.2, + "speed": 3.6, + "events": [ + { + "type": "fill", + "target": "row:row", + "i": 8, + "s": 9, + "cap": 32, + "counter": true, + "t": 0.0, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 9, + "s": 10, + "cap": 32, + "counter": true, + "t": 0.05, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 10, + "s": 11, + "cap": 32, + "counter": true, + "t": 0.1, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 11, + "s": 12, + "cap": 32, + "counter": true, + "t": 0.15, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 12, + "s": 13, + "cap": 32, + "counter": true, + "t": 0.2, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 13, + "s": 14, + "cap": 32, + "counter": true, + "t": 0.25, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 14, + "s": 15, + "cap": 32, + "counter": true, + "t": 0.3, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 15, + "s": 16, + "cap": 32, + "counter": true, + "t": 0.35, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 16, + "s": 17, + "cap": 32, + "counter": true, + "t": 0.4, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 17, + "s": 18, + "cap": 32, + "counter": true, + "t": 0.45, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 18, + "s": 19, + "cap": 32, + "counter": true, + "t": 0.5, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 19, + "s": 20, + "cap": 32, + "counter": true, + "t": 0.55, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 20, + "s": 21, + "cap": 32, + "counter": true, + "t": 0.6, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 21, + "s": 22, + "cap": 32, + "counter": true, + "t": 0.65, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 22, + "s": 23, + "cap": 32, + "counter": true, + "t": 0.7, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 23, + "s": 24, + "cap": 32, + "counter": true, + "t": 0.75, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 24, + "s": 25, + "cap": 32, + "counter": true, + "t": 0.8, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 25, + "s": 26, + "cap": 32, + "counter": true, + "t": 0.85, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 26, + "s": 27, + "cap": 32, + "counter": true, + "t": 0.9, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 27, + "s": 28, + "cap": 32, + "counter": true, + "t": 0.95, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 28, + "s": 29, + "cap": 32, + "counter": true, + "t": 1.0, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 29, + "s": 30, + "cap": 32, + "counter": true, + "t": 1.05, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 30, + "s": 31, + "cap": 32, + "counter": true, + "t": 1.1, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 31, + "s": 32, + "cap": 32, + "counter": true, + "t": 1.15, + "dur": 0.05 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "1.2s", + "duration": 1.2, + "speed": 1.0, + "events": [] + }, + { + "kind": "hide", + "label": "hide lb_t3", + "note": "", + "duration": 0.75, + "speed": 1.0, + "events": [ + { + "type": "fadeout", + "target": "show:lb_t3", + "t": 0.35, + "dur": 0.4 + } + ] + }, + { + "kind": "hide", + "label": "hide code_t3", + "note": "", + "duration": 0.75, + "speed": 1.0, + "events": [ + { + "type": "fadeout", + "target": "show:code_t3", + "t": 0.35, + "dur": 0.4 + } + ] + }, + { + "kind": "grow_to", + "label": "扩容 32→64", + "note": "capacity 32->64, 搬 32 格", + "duration": 11.65, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row_32", + "indicate": "row:row", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "_grow32:row", + "g": { + "kind": "cells", + "cap": 64, + "side": 0.22, + "cx": -0.75, + "cy": -3.53, + "w": 4.42, + "h": 1.06, + "cells": [ + { + "i": 0, + "x": -2.85, + "y": -3.11, + "s": 0.22 + }, + { + "i": 1, + "x": -2.57, + "y": -3.11, + "s": 0.22 + }, + { + "i": 2, + "x": -2.29, + "y": -3.11, + "s": 0.22 + }, + { + "i": 3, + "x": -2.01, + "y": -3.11, + "s": 0.22 + }, + { + "i": 4, + "x": -1.73, + "y": -3.11, + "s": 0.22 + }, + { + "i": 5, + "x": -1.45, + "y": -3.11, + "s": 0.22 + }, + { + "i": 6, + "x": -1.17, + "y": -3.11, + "s": 0.22 + }, + { + "i": 7, + "x": -0.89, + "y": -3.11, + "s": 0.22 + }, + { + "i": 8, + "x": -0.61, + "y": -3.11, + "s": 0.22 + }, + { + "i": 9, + "x": -0.33, + "y": -3.11, + "s": 0.22 + }, + { + "i": 10, + "x": -0.05, + "y": -3.11, + "s": 0.22 + }, + { + "i": 11, + "x": 0.23, + "y": -3.11, + "s": 0.22 + }, + { + "i": 12, + "x": 0.51, + "y": -3.11, + "s": 0.22 + }, + { + "i": 13, + "x": 0.79, + "y": -3.11, + "s": 0.22 + }, + { + "i": 14, + "x": 1.07, + "y": -3.11, + "s": 0.22 + }, + { + "i": 15, + "x": 1.35, + "y": -3.11, + "s": 0.22 + }, + { + "i": 16, + "x": -2.85, + "y": -3.39, + "s": 0.22 + }, + { + "i": 17, + "x": -2.57, + "y": -3.39, + "s": 0.22 + }, + { + "i": 18, + "x": -2.29, + "y": -3.39, + "s": 0.22 + }, + { + "i": 19, + "x": -2.01, + "y": -3.39, + "s": 0.22 + }, + { + "i": 20, + "x": -1.73, + "y": -3.39, + "s": 0.22 + }, + { + "i": 21, + "x": -1.45, + "y": -3.39, + "s": 0.22 + }, + { + "i": 22, + "x": -1.17, + "y": -3.39, + "s": 0.22 + }, + { + "i": 23, + "x": -0.89, + "y": -3.39, + "s": 0.22 + }, + { + "i": 24, + "x": -0.61, + "y": -3.39, + "s": 0.22 + }, + { + "i": 25, + "x": -0.33, + "y": -3.39, + "s": 0.22 + }, + { + "i": 26, + "x": -0.05, + "y": -3.39, + "s": 0.22 + }, + { + "i": 27, + "x": 0.23, + "y": -3.39, + "s": 0.22 + }, + { + "i": 28, + "x": 0.51, + "y": -3.39, + "s": 0.22 + }, + { + "i": 29, + "x": 0.79, + "y": -3.39, + "s": 0.22 + }, + { + "i": 30, + "x": 1.07, + "y": -3.39, + "s": 0.22 + }, + { + "i": 31, + "x": 1.35, + "y": -3.39, + "s": 0.22 + }, + { + "i": 32, + "x": -2.85, + "y": -3.67, + "s": 0.22 + }, + { + "i": 33, + "x": -2.57, + "y": -3.67, + "s": 0.22 + }, + { + "i": 34, + "x": -2.29, + "y": -3.67, + "s": 0.22 + }, + { + "i": 35, + "x": -2.01, + "y": -3.67, + "s": 0.22 + }, + { + "i": 36, + "x": -1.73, + "y": -3.67, + "s": 0.22 + }, + { + "i": 37, + "x": -1.45, + "y": -3.67, + "s": 0.22 + }, + { + "i": 38, + "x": -1.17, + "y": -3.67, + "s": 0.22 + }, + { + "i": 39, + "x": -0.89, + "y": -3.67, + "s": 0.22 + }, + { + "i": 40, + "x": -0.61, + "y": -3.67, + "s": 0.22 + }, + { + "i": 41, + "x": -0.33, + "y": -3.67, + "s": 0.22 + }, + { + "i": 42, + "x": -0.05, + "y": -3.67, + "s": 0.22 + }, + { + "i": 43, + "x": 0.23, + "y": -3.67, + "s": 0.22 + }, + { + "i": 44, + "x": 0.51, + "y": -3.67, + "s": 0.22 + }, + { + "i": 45, + "x": 0.79, + "y": -3.67, + "s": 0.22 + }, + { + "i": 46, + "x": 1.07, + "y": -3.67, + "s": 0.22 + }, + { + "i": 47, + "x": 1.35, + "y": -3.67, + "s": 0.22 + }, + { + "i": 48, + "x": -2.85, + "y": -3.95, + "s": 0.22 + }, + { + "i": 49, + "x": -2.57, + "y": -3.95, + "s": 0.22 + }, + { + "i": 50, + "x": -2.29, + "y": -3.95, + "s": 0.22 + }, + { + "i": 51, + "x": -2.01, + "y": -3.95, + "s": 0.22 + }, + { + "i": 52, + "x": -1.73, + "y": -3.95, + "s": 0.22 + }, + { + "i": 53, + "x": -1.45, + "y": -3.95, + "s": 0.22 + }, + { + "i": 54, + "x": -1.17, + "y": -3.95, + "s": 0.22 + }, + { + "i": 55, + "x": -0.89, + "y": -3.95, + "s": 0.22 + }, + { + "i": 56, + "x": -0.61, + "y": -3.95, + "s": 0.22 + }, + { + "i": 57, + "x": -0.33, + "y": -3.95, + "s": 0.22 + }, + { + "i": 58, + "x": -0.05, + "y": -3.95, + "s": 0.22 + }, + { + "i": 59, + "x": 0.23, + "y": -3.95, + "s": 0.22 + }, + { + "i": 60, + "x": 0.51, + "y": -3.95, + "s": 0.22 + }, + { + "i": 61, + "x": 0.79, + "y": -3.95, + "s": 0.22 + }, + { + "i": 62, + "x": 1.07, + "y": -3.95, + "s": 0.22 + }, + { + "i": 63, + "x": 1.35, + "y": -3.95, + "s": 0.22 + } + ], + "idx": [] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "relocate", + "src": "row:row", + "dst": "_grow32:row", + "count": 32, + "t": 3.1, + "dur": 1.0 + }, + { + "type": "row_destroy", + "target": "row:row", + "write": "_raii_row_32", + "t": 4.1, + "dur": 2.4 + }, + { + "type": "fadeout", + "target": "_cap_row_32", + "t": 9.7, + "dur": 0.3 + }, + { + "type": "fadeout", + "target": "_raii_row_32", + "t": 10.0, + "dur": 0.3 + }, + { + "type": "row_swap", + "target": "row:row", + "tmp": "_grow32:row", + "to": [ + -0.75, + -1.0 + ], + "t": 10.3, + "dur": 0.5 + }, + { + "type": "counter", + "text": "size = 32 capacity = 64", + "t": 10.8, + "dur": 0.25 + }, + { + "type": "ptr_move", + "target": "p_from", + "to": [ + -2.29, + -0.23 + ], + "t": 11.05, + "dur": 0.3 + }, + { + "type": "ptr_move", + "target": "p_to", + "to": [ + -1.17, + -0.23 + ], + "t": 11.35, + "dur": 0.3 + } + ] + }, + { + "kind": "highlight", + "label": "高亮 [32,64) red", + "note": "", + "duration": 1.6, + "speed": 1.0, + "events": [ + { + "type": "hl_show", + "frame": { + "kind": "frame", + "color": "#E06C75", + "cx": -0.75, + "cy": -1.28, + "w": 4.52, + "h": 0.6 + }, + "t": 0.0, + "dur": 0.4 + }, + { + "type": "hl_hide", + "frame": { + "kind": "frame", + "color": "#E06C75", + "cx": -0.75, + "cy": -1.28, + "w": 4.52, + "h": 0.6 + }, + "t": 1.3, + "dur": 0.3 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "0.5s", + "duration": 0.5, + "speed": 1.0, + "events": [] + }, + { + "kind": "conclude", + "label": "结论", + "note": "压轴结论墙", + "duration": 14.09, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "concl:0", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "write", + "target": "concl:1", + "t": 2.75, + "dur": 2.39 + }, + { + "type": "write", + "target": "concl:2", + "t": 5.49, + "dur": 2.4 + }, + { + "type": "pulse", + "target": "counter", + "t": 11.09, + "dur": 1.0 + } + ] + } + ] +} diff --git a/site/.vitepress/theme/components/animations/data/opp1-vector-growth.json b/site/.vitepress/theme/components/animations/data/opp1-vector-growth.json new file mode 100644 index 000000000..26fe9c421 --- /dev/null +++ b/site/.vitepress/theme/components/animations/data/opp1-vector-growth.json @@ -0,0 +1,3016 @@ +{ + "version": 1, + "id": "opp1-vector-growth", + "title": "ministl::Vector 扩容轨迹", + "subtitle": "连塞 40 个数:40 次 push_back,只有 5 次扩容", + "source": "projects/vol8-vector-growth/02-dsl/opp1-vector-growth.yaml", + "backend": "web", + "frame": { + "w": 14.2222, + "h": 8.0 + }, + "palette": { + "bg": "#17171f", + "text": "#ECECE4", + "muted": "#9a9aad", + "fill": "#5EC8E0", + "fillEdge": "#2E86AB", + "emptyEdge": "#4a4a5e", + "grow": "#FFB454", + "numOnFill": "#0e2430", + "ok": "#7BC96A", + "bad": "#E06C75", + "cardBg": "#1e1e2a" + }, + "actors": { + "title": { + "kind": "text", + "text": "ministl::Vector 扩容轨迹", + "x": 0.0, + "y": 3.4324, + "fs": 0.32, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 4.864, + "h": 0.4352 + }, + "sub": { + "kind": "text", + "text": "连塞 40 个数:40 次 push_back,只有 5 次扩容", + "x": 0.0, + "y": 2.8988, + "fs": 0.2, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 5.648, + "h": 0.272 + }, + "counter": { + "kind": "text", + "text": "size = 0 capacity = 0", + "x": 0.0, + "y": 1.6, + "fs": 0.3, + "color": "#ECECE4", + "mono": true, + "anchor": "middle", + "w": 5.148, + "h": 0.3 + }, + "_empty": { + "kind": "text", + "text": "还没申请内存", + "x": 0.0, + "y": -1.0, + "fs": 0.2, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 1.584, + "h": 0.272 + }, + "_cap_row": { + "kind": "text", + "text": "申请内存: capacity 0 → 4", + "x": 0.0, + "y": 0.1632, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 3.816, + "h": 0.3264 + }, + "row:row": { + "kind": "cells", + "cap": 64, + "side": 0.22, + "cx": 0.0, + "cy": -1.0, + "w": 4.42, + "h": 1.06, + "cells": [ + { + "i": 0, + "x": -2.1, + "y": -0.58, + "s": 0.22 + }, + { + "i": 1, + "x": -1.82, + "y": -0.58, + "s": 0.22 + }, + { + "i": 2, + "x": -1.54, + "y": -0.58, + "s": 0.22 + }, + { + "i": 3, + "x": -1.26, + "y": -0.58, + "s": 0.22 + }, + { + "i": 4, + "x": -0.98, + "y": -0.58, + "s": 0.22 + }, + { + "i": 5, + "x": -0.7, + "y": -0.58, + "s": 0.22 + }, + { + "i": 6, + "x": -0.42, + "y": -0.58, + "s": 0.22 + }, + { + "i": 7, + "x": -0.14, + "y": -0.58, + "s": 0.22 + }, + { + "i": 8, + "x": 0.14, + "y": -0.58, + "s": 0.22 + }, + { + "i": 9, + "x": 0.42, + "y": -0.58, + "s": 0.22 + }, + { + "i": 10, + "x": 0.7, + "y": -0.58, + "s": 0.22 + }, + { + "i": 11, + "x": 0.98, + "y": -0.58, + "s": 0.22 + }, + { + "i": 12, + "x": 1.26, + "y": -0.58, + "s": 0.22 + }, + { + "i": 13, + "x": 1.54, + "y": -0.58, + "s": 0.22 + }, + { + "i": 14, + "x": 1.82, + "y": -0.58, + "s": 0.22 + }, + { + "i": 15, + "x": 2.1, + "y": -0.58, + "s": 0.22 + }, + { + "i": 16, + "x": -2.1, + "y": -0.86, + "s": 0.22 + }, + { + "i": 17, + "x": -1.82, + "y": -0.86, + "s": 0.22 + }, + { + "i": 18, + "x": -1.54, + "y": -0.86, + "s": 0.22 + }, + { + "i": 19, + "x": -1.26, + "y": -0.86, + "s": 0.22 + }, + { + "i": 20, + "x": -0.98, + "y": -0.86, + "s": 0.22 + }, + { + "i": 21, + "x": -0.7, + "y": -0.86, + "s": 0.22 + }, + { + "i": 22, + "x": -0.42, + "y": -0.86, + "s": 0.22 + }, + { + "i": 23, + "x": -0.14, + "y": -0.86, + "s": 0.22 + }, + { + "i": 24, + "x": 0.14, + "y": -0.86, + "s": 0.22 + }, + { + "i": 25, + "x": 0.42, + "y": -0.86, + "s": 0.22 + }, + { + "i": 26, + "x": 0.7, + "y": -0.86, + "s": 0.22 + }, + { + "i": 27, + "x": 0.98, + "y": -0.86, + "s": 0.22 + }, + { + "i": 28, + "x": 1.26, + "y": -0.86, + "s": 0.22 + }, + { + "i": 29, + "x": 1.54, + "y": -0.86, + "s": 0.22 + }, + { + "i": 30, + "x": 1.82, + "y": -0.86, + "s": 0.22 + }, + { + "i": 31, + "x": 2.1, + "y": -0.86, + "s": 0.22 + }, + { + "i": 32, + "x": -2.1, + "y": -1.14, + "s": 0.22 + }, + { + "i": 33, + "x": -1.82, + "y": -1.14, + "s": 0.22 + }, + { + "i": 34, + "x": -1.54, + "y": -1.14, + "s": 0.22 + }, + { + "i": 35, + "x": -1.26, + "y": -1.14, + "s": 0.22 + }, + { + "i": 36, + "x": -0.98, + "y": -1.14, + "s": 0.22 + }, + { + "i": 37, + "x": -0.7, + "y": -1.14, + "s": 0.22 + }, + { + "i": 38, + "x": -0.42, + "y": -1.14, + "s": 0.22 + }, + { + "i": 39, + "x": -0.14, + "y": -1.14, + "s": 0.22 + }, + { + "i": 40, + "x": 0.14, + "y": -1.14, + "s": 0.22 + }, + { + "i": 41, + "x": 0.42, + "y": -1.14, + "s": 0.22 + }, + { + "i": 42, + "x": 0.7, + "y": -1.14, + "s": 0.22 + }, + { + "i": 43, + "x": 0.98, + "y": -1.14, + "s": 0.22 + }, + { + "i": 44, + "x": 1.26, + "y": -1.14, + "s": 0.22 + }, + { + "i": 45, + "x": 1.54, + "y": -1.14, + "s": 0.22 + }, + { + "i": 46, + "x": 1.82, + "y": -1.14, + "s": 0.22 + }, + { + "i": 47, + "x": 2.1, + "y": -1.14, + "s": 0.22 + }, + { + "i": 48, + "x": -2.1, + "y": -1.42, + "s": 0.22 + }, + { + "i": 49, + "x": -1.82, + "y": -1.42, + "s": 0.22 + }, + { + "i": 50, + "x": -1.54, + "y": -1.42, + "s": 0.22 + }, + { + "i": 51, + "x": -1.26, + "y": -1.42, + "s": 0.22 + }, + { + "i": 52, + "x": -0.98, + "y": -1.42, + "s": 0.22 + }, + { + "i": 53, + "x": -0.7, + "y": -1.42, + "s": 0.22 + }, + { + "i": 54, + "x": -0.42, + "y": -1.42, + "s": 0.22 + }, + { + "i": 55, + "x": -0.14, + "y": -1.42, + "s": 0.22 + }, + { + "i": 56, + "x": 0.14, + "y": -1.42, + "s": 0.22 + }, + { + "i": 57, + "x": 0.42, + "y": -1.42, + "s": 0.22 + }, + { + "i": 58, + "x": 0.7, + "y": -1.42, + "s": 0.22 + }, + { + "i": 59, + "x": 0.98, + "y": -1.42, + "s": 0.22 + }, + { + "i": 60, + "x": 1.26, + "y": -1.42, + "s": 0.22 + }, + { + "i": 61, + "x": 1.54, + "y": -1.42, + "s": 0.22 + }, + { + "i": 62, + "x": 1.82, + "y": -1.42, + "s": 0.22 + }, + { + "i": 63, + "x": 2.1, + "y": -1.42, + "s": 0.22 + } + ], + "idx": [] + }, + "_cap_row_4": { + "kind": "text", + "text": "满了!capacity 4 → 8,grow_to!", + "x": 0.0, + "y": -2.1732, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 4.8768, + "h": 0.3264 + }, + "_grow4:row": { + "kind": "cells", + "cap": 8, + "side": 0.5, + "cx": 0.0, + "cy": -3.51, + "w": 4.42, + "h": 0.5, + "cells": [ + { + "i": 0, + "x": -1.96, + "y": -3.51, + "s": 0.5 + }, + { + "i": 1, + "x": -1.4, + "y": -3.51, + "s": 0.5 + }, + { + "i": 2, + "x": -0.84, + "y": -3.51, + "s": 0.5 + }, + { + "i": 3, + "x": -0.28, + "y": -3.51, + "s": 0.5 + }, + { + "i": 4, + "x": 0.28, + "y": -3.51, + "s": 0.5 + }, + { + "i": 5, + "x": 0.84, + "y": -3.51, + "s": 0.5 + }, + { + "i": 6, + "x": 1.4, + "y": -3.51, + "s": 0.5 + }, + { + "i": 7, + "x": 1.96, + "y": -3.51, + "s": 0.5 + } + ], + "idx": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ] + }, + "_raii_row_4": { + "kind": "text", + "text": "旧对象已逐个析构, 内存 RAII 归还", + "x": 0.0, + "y": -0.3176, + "fs": 0.18, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 3.744, + "h": 0.2448 + }, + "_cap_row_8": { + "kind": "text", + "text": "满了!capacity 8 → 16,grow_to!", + "x": 0.0, + "y": -2.1132, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 5.0256, + "h": 0.3264 + }, + "_grow8:row": { + "kind": "cells", + "cap": 16, + "side": 0.4, + "cx": 0.0, + "cy": -3.45, + "w": 7.3, + "h": 0.4, + "cells": [ + { + "i": 0, + "x": -3.45, + "y": -3.45, + "s": 0.4 + }, + { + "i": 1, + "x": -2.99, + "y": -3.45, + "s": 0.4 + }, + { + "i": 2, + "x": -2.53, + "y": -3.45, + "s": 0.4 + }, + { + "i": 3, + "x": -2.07, + "y": -3.45, + "s": 0.4 + }, + { + "i": 4, + "x": -1.61, + "y": -3.45, + "s": 0.4 + }, + { + "i": 5, + "x": -1.15, + "y": -3.45, + "s": 0.4 + }, + { + "i": 6, + "x": -0.69, + "y": -3.45, + "s": 0.4 + }, + { + "i": 7, + "x": -0.23, + "y": -3.45, + "s": 0.4 + }, + { + "i": 8, + "x": 0.23, + "y": -3.45, + "s": 0.4 + }, + { + "i": 9, + "x": 0.69, + "y": -3.45, + "s": 0.4 + }, + { + "i": 10, + "x": 1.15, + "y": -3.45, + "s": 0.4 + }, + { + "i": 11, + "x": 1.61, + "y": -3.45, + "s": 0.4 + }, + { + "i": 12, + "x": 2.07, + "y": -3.45, + "s": 0.4 + }, + { + "i": 13, + "x": 2.53, + "y": -3.45, + "s": 0.4 + }, + { + "i": 14, + "x": 2.99, + "y": -3.45, + "s": 0.4 + }, + { + "i": 15, + "x": 3.45, + "y": -3.45, + "s": 0.4 + } + ], + "idx": [] + }, + "_raii_row_8": { + "kind": "text", + "text": "旧对象已逐个析构, 内存 RAII 归还", + "x": 0.0, + "y": -0.3776, + "fs": 0.18, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 3.744, + "h": 0.2448 + }, + "_cap_row_16": { + "kind": "text", + "text": "满了!capacity 16 → 32,grow_to!", + "x": 0.0, + "y": -2.0632, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 5.1744, + "h": 0.3264 + }, + "_grow16:row": { + "kind": "cells", + "cap": 32, + "side": 0.3, + "cx": 0.0, + "cy": -3.4, + "w": 5.7, + "h": 0.66, + "cells": [ + { + "i": 0, + "x": -2.7, + "y": -3.22, + "s": 0.3 + }, + { + "i": 1, + "x": -2.34, + "y": -3.22, + "s": 0.3 + }, + { + "i": 2, + "x": -1.98, + "y": -3.22, + "s": 0.3 + }, + { + "i": 3, + "x": -1.62, + "y": -3.22, + "s": 0.3 + }, + { + "i": 4, + "x": -1.26, + "y": -3.22, + "s": 0.3 + }, + { + "i": 5, + "x": -0.9, + "y": -3.22, + "s": 0.3 + }, + { + "i": 6, + "x": -0.54, + "y": -3.22, + "s": 0.3 + }, + { + "i": 7, + "x": -0.18, + "y": -3.22, + "s": 0.3 + }, + { + "i": 8, + "x": 0.18, + "y": -3.22, + "s": 0.3 + }, + { + "i": 9, + "x": 0.54, + "y": -3.22, + "s": 0.3 + }, + { + "i": 10, + "x": 0.9, + "y": -3.22, + "s": 0.3 + }, + { + "i": 11, + "x": 1.26, + "y": -3.22, + "s": 0.3 + }, + { + "i": 12, + "x": 1.62, + "y": -3.22, + "s": 0.3 + }, + { + "i": 13, + "x": 1.98, + "y": -3.22, + "s": 0.3 + }, + { + "i": 14, + "x": 2.34, + "y": -3.22, + "s": 0.3 + }, + { + "i": 15, + "x": 2.7, + "y": -3.22, + "s": 0.3 + }, + { + "i": 16, + "x": -2.7, + "y": -3.58, + "s": 0.3 + }, + { + "i": 17, + "x": -2.34, + "y": -3.58, + "s": 0.3 + }, + { + "i": 18, + "x": -1.98, + "y": -3.58, + "s": 0.3 + }, + { + "i": 19, + "x": -1.62, + "y": -3.58, + "s": 0.3 + }, + { + "i": 20, + "x": -1.26, + "y": -3.58, + "s": 0.3 + }, + { + "i": 21, + "x": -0.9, + "y": -3.58, + "s": 0.3 + }, + { + "i": 22, + "x": -0.54, + "y": -3.58, + "s": 0.3 + }, + { + "i": 23, + "x": -0.18, + "y": -3.58, + "s": 0.3 + }, + { + "i": 24, + "x": 0.18, + "y": -3.58, + "s": 0.3 + }, + { + "i": 25, + "x": 0.54, + "y": -3.58, + "s": 0.3 + }, + { + "i": 26, + "x": 0.9, + "y": -3.58, + "s": 0.3 + }, + { + "i": 27, + "x": 1.26, + "y": -3.58, + "s": 0.3 + }, + { + "i": 28, + "x": 1.62, + "y": -3.58, + "s": 0.3 + }, + { + "i": 29, + "x": 1.98, + "y": -3.58, + "s": 0.3 + }, + { + "i": 30, + "x": 2.34, + "y": -3.58, + "s": 0.3 + }, + { + "i": 31, + "x": 2.7, + "y": -3.58, + "s": 0.3 + } + ], + "idx": [] + }, + "_raii_row_16": { + "kind": "text", + "text": "旧对象已逐个析构, 内存 RAII 归还", + "x": 0.0, + "y": -0.4276, + "fs": 0.18, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 3.744, + "h": 0.2448 + }, + "_cap_row_32": { + "kind": "text", + "text": "满了!capacity 32 → 64,grow_to!", + "x": 0.0, + "y": -2.1932, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 5.1744, + "h": 0.3264 + }, + "_grow32:row": { + "kind": "cells", + "cap": 64, + "side": 0.22, + "cx": 0.0, + "cy": -3.53, + "w": 4.42, + "h": 1.06, + "cells": [ + { + "i": 0, + "x": -2.1, + "y": -3.11, + "s": 0.22 + }, + { + "i": 1, + "x": -1.82, + "y": -3.11, + "s": 0.22 + }, + { + "i": 2, + "x": -1.54, + "y": -3.11, + "s": 0.22 + }, + { + "i": 3, + "x": -1.26, + "y": -3.11, + "s": 0.22 + }, + { + "i": 4, + "x": -0.98, + "y": -3.11, + "s": 0.22 + }, + { + "i": 5, + "x": -0.7, + "y": -3.11, + "s": 0.22 + }, + { + "i": 6, + "x": -0.42, + "y": -3.11, + "s": 0.22 + }, + { + "i": 7, + "x": -0.14, + "y": -3.11, + "s": 0.22 + }, + { + "i": 8, + "x": 0.14, + "y": -3.11, + "s": 0.22 + }, + { + "i": 9, + "x": 0.42, + "y": -3.11, + "s": 0.22 + }, + { + "i": 10, + "x": 0.7, + "y": -3.11, + "s": 0.22 + }, + { + "i": 11, + "x": 0.98, + "y": -3.11, + "s": 0.22 + }, + { + "i": 12, + "x": 1.26, + "y": -3.11, + "s": 0.22 + }, + { + "i": 13, + "x": 1.54, + "y": -3.11, + "s": 0.22 + }, + { + "i": 14, + "x": 1.82, + "y": -3.11, + "s": 0.22 + }, + { + "i": 15, + "x": 2.1, + "y": -3.11, + "s": 0.22 + }, + { + "i": 16, + "x": -2.1, + "y": -3.39, + "s": 0.22 + }, + { + "i": 17, + "x": -1.82, + "y": -3.39, + "s": 0.22 + }, + { + "i": 18, + "x": -1.54, + "y": -3.39, + "s": 0.22 + }, + { + "i": 19, + "x": -1.26, + "y": -3.39, + "s": 0.22 + }, + { + "i": 20, + "x": -0.98, + "y": -3.39, + "s": 0.22 + }, + { + "i": 21, + "x": -0.7, + "y": -3.39, + "s": 0.22 + }, + { + "i": 22, + "x": -0.42, + "y": -3.39, + "s": 0.22 + }, + { + "i": 23, + "x": -0.14, + "y": -3.39, + "s": 0.22 + }, + { + "i": 24, + "x": 0.14, + "y": -3.39, + "s": 0.22 + }, + { + "i": 25, + "x": 0.42, + "y": -3.39, + "s": 0.22 + }, + { + "i": 26, + "x": 0.7, + "y": -3.39, + "s": 0.22 + }, + { + "i": 27, + "x": 0.98, + "y": -3.39, + "s": 0.22 + }, + { + "i": 28, + "x": 1.26, + "y": -3.39, + "s": 0.22 + }, + { + "i": 29, + "x": 1.54, + "y": -3.39, + "s": 0.22 + }, + { + "i": 30, + "x": 1.82, + "y": -3.39, + "s": 0.22 + }, + { + "i": 31, + "x": 2.1, + "y": -3.39, + "s": 0.22 + }, + { + "i": 32, + "x": -2.1, + "y": -3.67, + "s": 0.22 + }, + { + "i": 33, + "x": -1.82, + "y": -3.67, + "s": 0.22 + }, + { + "i": 34, + "x": -1.54, + "y": -3.67, + "s": 0.22 + }, + { + "i": 35, + "x": -1.26, + "y": -3.67, + "s": 0.22 + }, + { + "i": 36, + "x": -0.98, + "y": -3.67, + "s": 0.22 + }, + { + "i": 37, + "x": -0.7, + "y": -3.67, + "s": 0.22 + }, + { + "i": 38, + "x": -0.42, + "y": -3.67, + "s": 0.22 + }, + { + "i": 39, + "x": -0.14, + "y": -3.67, + "s": 0.22 + }, + { + "i": 40, + "x": 0.14, + "y": -3.67, + "s": 0.22 + }, + { + "i": 41, + "x": 0.42, + "y": -3.67, + "s": 0.22 + }, + { + "i": 42, + "x": 0.7, + "y": -3.67, + "s": 0.22 + }, + { + "i": 43, + "x": 0.98, + "y": -3.67, + "s": 0.22 + }, + { + "i": 44, + "x": 1.26, + "y": -3.67, + "s": 0.22 + }, + { + "i": 45, + "x": 1.54, + "y": -3.67, + "s": 0.22 + }, + { + "i": 46, + "x": 1.82, + "y": -3.67, + "s": 0.22 + }, + { + "i": 47, + "x": 2.1, + "y": -3.67, + "s": 0.22 + }, + { + "i": 48, + "x": -2.1, + "y": -3.95, + "s": 0.22 + }, + { + "i": 49, + "x": -1.82, + "y": -3.95, + "s": 0.22 + }, + { + "i": 50, + "x": -1.54, + "y": -3.95, + "s": 0.22 + }, + { + "i": 51, + "x": -1.26, + "y": -3.95, + "s": 0.22 + }, + { + "i": 52, + "x": -0.98, + "y": -3.95, + "s": 0.22 + }, + { + "i": 53, + "x": -0.7, + "y": -3.95, + "s": 0.22 + }, + { + "i": 54, + "x": -0.42, + "y": -3.95, + "s": 0.22 + }, + { + "i": 55, + "x": -0.14, + "y": -3.95, + "s": 0.22 + }, + { + "i": 56, + "x": 0.14, + "y": -3.95, + "s": 0.22 + }, + { + "i": 57, + "x": 0.42, + "y": -3.95, + "s": 0.22 + }, + { + "i": 58, + "x": 0.7, + "y": -3.95, + "s": 0.22 + }, + { + "i": 59, + "x": 0.98, + "y": -3.95, + "s": 0.22 + }, + { + "i": 60, + "x": 1.26, + "y": -3.95, + "s": 0.22 + }, + { + "i": 61, + "x": 1.54, + "y": -3.95, + "s": 0.22 + }, + { + "i": 62, + "x": 1.82, + "y": -3.95, + "s": 0.22 + }, + { + "i": 63, + "x": 2.1, + "y": -3.95, + "s": 0.22 + } + ], + "idx": [] + }, + "_raii_row_32": { + "kind": "text", + "text": "旧对象已逐个析构, 内存 RAII 归还", + "x": 0.0, + "y": -0.2976, + "fs": 0.18, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 3.744, + "h": 0.2448 + }, + "concl:0": { + "kind": "text", + "text": "40 次 push_back,只有 5 次扩容", + "x": 0.0, + "y": -2.6604, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 4.5984, + "h": 0.3264 + }, + "concl:1": { + "kind": "text", + "text": "总搬迁 4+8+16+32 = 60 < 2×40 —— push_back 摊还 O(1)", + "x": 0.0, + "y": -3.2368, + "fs": 0.24, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 8.0208, + "h": 0.3264 + } + }, + "steps": [ + { + "kind": "intro", + "label": "开场", + "note": "", + "duration": 5.8, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "title", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "fadein", + "target": "sub", + "t": 2.4, + "dur": 0.5 + }, + { + "type": "fadein", + "target": "counter", + "t": 2.4, + "dur": 0.5 + }, + { + "type": "write", + "target": "_empty", + "t": 3.4, + "dur": 1.07 + }, + { + "type": "fadeout", + "target": "_empty", + "t": 5.5, + "dur": 0.3 + } + ] + }, + { + "kind": "grow_to", + "label": "申请 4", + "note": "capacity 0->4, 搬 0 格", + "duration": 6.15, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "row:row", + "g": { + "kind": "cells", + "cap": 4, + "side": 0.62, + "cx": 0.0, + "cy": -1.0, + "w": 2.66, + "h": 0.62, + "cells": [ + { + "i": 0, + "x": -1.02, + "y": -1.0, + "s": 0.62 + }, + { + "i": 1, + "x": -0.34, + "y": -1.0, + "s": 0.62 + }, + { + "i": 2, + "x": 0.34, + "y": -1.0, + "s": 0.62 + }, + { + "i": 3, + "x": 1.02, + "y": -1.0, + "s": 0.62 + } + ], + "idx": [ + 1, + 2, + 3, + 4 + ] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "fadeout", + "target": "_cap_row", + "t": 5.6, + "dur": 0.3 + }, + { + "type": "counter", + "text": "size = 0 capacity = 4", + "t": 5.9, + "dur": 0.25 + } + ] + }, + { + "kind": "push", + "label": "push ×4 (slow)", + "note": "[0,4)", + "duration": 1.2, + "speed": 0.6, + "events": [ + { + "type": "fill", + "target": "row:row", + "i": 0, + "s": 1, + "cap": 4, + "counter": true, + "t": 0.0, + "dur": 0.3 + }, + { + "type": "fill", + "target": "row:row", + "i": 1, + "s": 2, + "cap": 4, + "counter": true, + "t": 0.3, + "dur": 0.3 + }, + { + "type": "fill", + "target": "row:row", + "i": 2, + "s": 3, + "cap": 4, + "counter": true, + "t": 0.6, + "dur": 0.3 + }, + { + "type": "fill", + "target": "row:row", + "i": 3, + "s": 4, + "cap": 4, + "counter": true, + "t": 0.9, + "dur": 0.3 + } + ] + }, + { + "kind": "grow_to", + "label": "扩容 4→8", + "note": "capacity 4->8, 搬 4 格", + "duration": 11.05, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row_4", + "indicate": "row:row", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "_grow4:row", + "g": { + "kind": "cells", + "cap": 8, + "side": 0.5, + "cx": 0.0, + "cy": -3.51, + "w": 4.42, + "h": 0.5, + "cells": [ + { + "i": 0, + "x": -1.96, + "y": -3.51, + "s": 0.5 + }, + { + "i": 1, + "x": -1.4, + "y": -3.51, + "s": 0.5 + }, + { + "i": 2, + "x": -0.84, + "y": -3.51, + "s": 0.5 + }, + { + "i": 3, + "x": -0.28, + "y": -3.51, + "s": 0.5 + }, + { + "i": 4, + "x": 0.28, + "y": -3.51, + "s": 0.5 + }, + { + "i": 5, + "x": 0.84, + "y": -3.51, + "s": 0.5 + }, + { + "i": 6, + "x": 1.4, + "y": -3.51, + "s": 0.5 + }, + { + "i": 7, + "x": 1.96, + "y": -3.51, + "s": 0.5 + } + ], + "idx": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "relocate", + "src": "row:row", + "dst": "_grow4:row", + "count": 4, + "t": 3.1, + "dur": 1.0 + }, + { + "type": "row_destroy", + "target": "row:row", + "write": "_raii_row_4", + "t": 4.1, + "dur": 2.4 + }, + { + "type": "fadeout", + "target": "_cap_row_4", + "t": 9.7, + "dur": 0.3 + }, + { + "type": "fadeout", + "target": "_raii_row_4", + "t": 10.0, + "dur": 0.3 + }, + { + "type": "row_swap", + "target": "row:row", + "tmp": "_grow4:row", + "to": [ + 0.0, + -1.0 + ], + "t": 10.3, + "dur": 0.5 + }, + { + "type": "counter", + "text": "size = 4 capacity = 8", + "t": 10.8, + "dur": 0.25 + } + ] + }, + { + "kind": "push", + "label": "push ×4 (normal)", + "note": "[4,8)", + "duration": 0.72, + "speed": 1.0, + "events": [ + { + "type": "fill", + "target": "row:row", + "i": 4, + "s": 5, + "cap": 8, + "counter": true, + "t": 0.0, + "dur": 0.18 + }, + { + "type": "fill", + "target": "row:row", + "i": 5, + "s": 6, + "cap": 8, + "counter": true, + "t": 0.18, + "dur": 0.18 + }, + { + "type": "fill", + "target": "row:row", + "i": 6, + "s": 7, + "cap": 8, + "counter": true, + "t": 0.36, + "dur": 0.18 + }, + { + "type": "fill", + "target": "row:row", + "i": 7, + "s": 8, + "cap": 8, + "counter": true, + "t": 0.54, + "dur": 0.18 + } + ] + }, + { + "kind": "grow_to", + "label": "扩容 8→16", + "note": "capacity 8->16, 搬 8 格", + "duration": 11.05, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row_8", + "indicate": "row:row", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "_grow8:row", + "g": { + "kind": "cells", + "cap": 16, + "side": 0.4, + "cx": 0.0, + "cy": -3.45, + "w": 7.3, + "h": 0.4, + "cells": [ + { + "i": 0, + "x": -3.45, + "y": -3.45, + "s": 0.4 + }, + { + "i": 1, + "x": -2.99, + "y": -3.45, + "s": 0.4 + }, + { + "i": 2, + "x": -2.53, + "y": -3.45, + "s": 0.4 + }, + { + "i": 3, + "x": -2.07, + "y": -3.45, + "s": 0.4 + }, + { + "i": 4, + "x": -1.61, + "y": -3.45, + "s": 0.4 + }, + { + "i": 5, + "x": -1.15, + "y": -3.45, + "s": 0.4 + }, + { + "i": 6, + "x": -0.69, + "y": -3.45, + "s": 0.4 + }, + { + "i": 7, + "x": -0.23, + "y": -3.45, + "s": 0.4 + }, + { + "i": 8, + "x": 0.23, + "y": -3.45, + "s": 0.4 + }, + { + "i": 9, + "x": 0.69, + "y": -3.45, + "s": 0.4 + }, + { + "i": 10, + "x": 1.15, + "y": -3.45, + "s": 0.4 + }, + { + "i": 11, + "x": 1.61, + "y": -3.45, + "s": 0.4 + }, + { + "i": 12, + "x": 2.07, + "y": -3.45, + "s": 0.4 + }, + { + "i": 13, + "x": 2.53, + "y": -3.45, + "s": 0.4 + }, + { + "i": 14, + "x": 2.99, + "y": -3.45, + "s": 0.4 + }, + { + "i": 15, + "x": 3.45, + "y": -3.45, + "s": 0.4 + } + ], + "idx": [] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "relocate", + "src": "row:row", + "dst": "_grow8:row", + "count": 8, + "t": 3.1, + "dur": 1.0 + }, + { + "type": "row_destroy", + "target": "row:row", + "write": "_raii_row_8", + "t": 4.1, + "dur": 2.4 + }, + { + "type": "fadeout", + "target": "_cap_row_8", + "t": 9.7, + "dur": 0.3 + }, + { + "type": "fadeout", + "target": "_raii_row_8", + "t": 10.0, + "dur": 0.3 + }, + { + "type": "row_swap", + "target": "row:row", + "tmp": "_grow8:row", + "to": [ + 0.0, + -1.0 + ], + "t": 10.3, + "dur": 0.5 + }, + { + "type": "counter", + "text": "size = 8 capacity = 16", + "t": 10.8, + "dur": 0.25 + } + ] + }, + { + "kind": "push", + "label": "push ×8 (fast)", + "note": "[8,16)", + "duration": 0.8, + "speed": 1.8, + "events": [ + { + "type": "fill", + "target": "row:row", + "i": 8, + "s": 9, + "cap": 16, + "counter": true, + "t": 0.0, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 9, + "s": 10, + "cap": 16, + "counter": true, + "t": 0.1, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 10, + "s": 11, + "cap": 16, + "counter": true, + "t": 0.2, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 11, + "s": 12, + "cap": 16, + "counter": true, + "t": 0.3, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 12, + "s": 13, + "cap": 16, + "counter": true, + "t": 0.4, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 13, + "s": 14, + "cap": 16, + "counter": true, + "t": 0.5, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 14, + "s": 15, + "cap": 16, + "counter": true, + "t": 0.6, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 15, + "s": 16, + "cap": 16, + "counter": true, + "t": 0.7, + "dur": 0.1 + } + ] + }, + { + "kind": "grow_to", + "label": "扩容 16→32", + "note": "capacity 16->32, 搬 16 格", + "duration": 11.05, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row_16", + "indicate": "row:row", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "_grow16:row", + "g": { + "kind": "cells", + "cap": 32, + "side": 0.3, + "cx": 0.0, + "cy": -3.4, + "w": 5.7, + "h": 0.66, + "cells": [ + { + "i": 0, + "x": -2.7, + "y": -3.22, + "s": 0.3 + }, + { + "i": 1, + "x": -2.34, + "y": -3.22, + "s": 0.3 + }, + { + "i": 2, + "x": -1.98, + "y": -3.22, + "s": 0.3 + }, + { + "i": 3, + "x": -1.62, + "y": -3.22, + "s": 0.3 + }, + { + "i": 4, + "x": -1.26, + "y": -3.22, + "s": 0.3 + }, + { + "i": 5, + "x": -0.9, + "y": -3.22, + "s": 0.3 + }, + { + "i": 6, + "x": -0.54, + "y": -3.22, + "s": 0.3 + }, + { + "i": 7, + "x": -0.18, + "y": -3.22, + "s": 0.3 + }, + { + "i": 8, + "x": 0.18, + "y": -3.22, + "s": 0.3 + }, + { + "i": 9, + "x": 0.54, + "y": -3.22, + "s": 0.3 + }, + { + "i": 10, + "x": 0.9, + "y": -3.22, + "s": 0.3 + }, + { + "i": 11, + "x": 1.26, + "y": -3.22, + "s": 0.3 + }, + { + "i": 12, + "x": 1.62, + "y": -3.22, + "s": 0.3 + }, + { + "i": 13, + "x": 1.98, + "y": -3.22, + "s": 0.3 + }, + { + "i": 14, + "x": 2.34, + "y": -3.22, + "s": 0.3 + }, + { + "i": 15, + "x": 2.7, + "y": -3.22, + "s": 0.3 + }, + { + "i": 16, + "x": -2.7, + "y": -3.58, + "s": 0.3 + }, + { + "i": 17, + "x": -2.34, + "y": -3.58, + "s": 0.3 + }, + { + "i": 18, + "x": -1.98, + "y": -3.58, + "s": 0.3 + }, + { + "i": 19, + "x": -1.62, + "y": -3.58, + "s": 0.3 + }, + { + "i": 20, + "x": -1.26, + "y": -3.58, + "s": 0.3 + }, + { + "i": 21, + "x": -0.9, + "y": -3.58, + "s": 0.3 + }, + { + "i": 22, + "x": -0.54, + "y": -3.58, + "s": 0.3 + }, + { + "i": 23, + "x": -0.18, + "y": -3.58, + "s": 0.3 + }, + { + "i": 24, + "x": 0.18, + "y": -3.58, + "s": 0.3 + }, + { + "i": 25, + "x": 0.54, + "y": -3.58, + "s": 0.3 + }, + { + "i": 26, + "x": 0.9, + "y": -3.58, + "s": 0.3 + }, + { + "i": 27, + "x": 1.26, + "y": -3.58, + "s": 0.3 + }, + { + "i": 28, + "x": 1.62, + "y": -3.58, + "s": 0.3 + }, + { + "i": 29, + "x": 1.98, + "y": -3.58, + "s": 0.3 + }, + { + "i": 30, + "x": 2.34, + "y": -3.58, + "s": 0.3 + }, + { + "i": 31, + "x": 2.7, + "y": -3.58, + "s": 0.3 + } + ], + "idx": [] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "relocate", + "src": "row:row", + "dst": "_grow16:row", + "count": 16, + "t": 3.1, + "dur": 1.0 + }, + { + "type": "row_destroy", + "target": "row:row", + "write": "_raii_row_16", + "t": 4.1, + "dur": 2.4 + }, + { + "type": "fadeout", + "target": "_cap_row_16", + "t": 9.7, + "dur": 0.3 + }, + { + "type": "fadeout", + "target": "_raii_row_16", + "t": 10.0, + "dur": 0.3 + }, + { + "type": "row_swap", + "target": "row:row", + "tmp": "_grow16:row", + "to": [ + 0.0, + -1.0 + ], + "t": 10.3, + "dur": 0.5 + }, + { + "type": "counter", + "text": "size = 16 capacity = 32", + "t": 10.8, + "dur": 0.25 + } + ] + }, + { + "kind": "push", + "label": "push ×16 (fast)", + "note": "[16,32)", + "duration": 1.6, + "speed": 1.8, + "events": [ + { + "type": "fill", + "target": "row:row", + "i": 16, + "s": 17, + "cap": 32, + "counter": true, + "t": 0.0, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 17, + "s": 18, + "cap": 32, + "counter": true, + "t": 0.1, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 18, + "s": 19, + "cap": 32, + "counter": true, + "t": 0.2, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 19, + "s": 20, + "cap": 32, + "counter": true, + "t": 0.3, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 20, + "s": 21, + "cap": 32, + "counter": true, + "t": 0.4, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 21, + "s": 22, + "cap": 32, + "counter": true, + "t": 0.5, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 22, + "s": 23, + "cap": 32, + "counter": true, + "t": 0.6, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 23, + "s": 24, + "cap": 32, + "counter": true, + "t": 0.7, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 24, + "s": 25, + "cap": 32, + "counter": true, + "t": 0.8, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 25, + "s": 26, + "cap": 32, + "counter": true, + "t": 0.9, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 26, + "s": 27, + "cap": 32, + "counter": true, + "t": 1.0, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 27, + "s": 28, + "cap": 32, + "counter": true, + "t": 1.1, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 28, + "s": 29, + "cap": 32, + "counter": true, + "t": 1.2, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 29, + "s": 30, + "cap": 32, + "counter": true, + "t": 1.3, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 30, + "s": 31, + "cap": 32, + "counter": true, + "t": 1.4, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 31, + "s": 32, + "cap": 32, + "counter": true, + "t": 1.5, + "dur": 0.1 + } + ] + }, + { + "kind": "grow_to", + "label": "扩容 32→64", + "note": "capacity 32->64, 搬 32 格", + "duration": 11.05, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row_32", + "indicate": "row:row", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "_grow32:row", + "g": { + "kind": "cells", + "cap": 64, + "side": 0.22, + "cx": 0.0, + "cy": -3.53, + "w": 4.42, + "h": 1.06, + "cells": [ + { + "i": 0, + "x": -2.1, + "y": -3.11, + "s": 0.22 + }, + { + "i": 1, + "x": -1.82, + "y": -3.11, + "s": 0.22 + }, + { + "i": 2, + "x": -1.54, + "y": -3.11, + "s": 0.22 + }, + { + "i": 3, + "x": -1.26, + "y": -3.11, + "s": 0.22 + }, + { + "i": 4, + "x": -0.98, + "y": -3.11, + "s": 0.22 + }, + { + "i": 5, + "x": -0.7, + "y": -3.11, + "s": 0.22 + }, + { + "i": 6, + "x": -0.42, + "y": -3.11, + "s": 0.22 + }, + { + "i": 7, + "x": -0.14, + "y": -3.11, + "s": 0.22 + }, + { + "i": 8, + "x": 0.14, + "y": -3.11, + "s": 0.22 + }, + { + "i": 9, + "x": 0.42, + "y": -3.11, + "s": 0.22 + }, + { + "i": 10, + "x": 0.7, + "y": -3.11, + "s": 0.22 + }, + { + "i": 11, + "x": 0.98, + "y": -3.11, + "s": 0.22 + }, + { + "i": 12, + "x": 1.26, + "y": -3.11, + "s": 0.22 + }, + { + "i": 13, + "x": 1.54, + "y": -3.11, + "s": 0.22 + }, + { + "i": 14, + "x": 1.82, + "y": -3.11, + "s": 0.22 + }, + { + "i": 15, + "x": 2.1, + "y": -3.11, + "s": 0.22 + }, + { + "i": 16, + "x": -2.1, + "y": -3.39, + "s": 0.22 + }, + { + "i": 17, + "x": -1.82, + "y": -3.39, + "s": 0.22 + }, + { + "i": 18, + "x": -1.54, + "y": -3.39, + "s": 0.22 + }, + { + "i": 19, + "x": -1.26, + "y": -3.39, + "s": 0.22 + }, + { + "i": 20, + "x": -0.98, + "y": -3.39, + "s": 0.22 + }, + { + "i": 21, + "x": -0.7, + "y": -3.39, + "s": 0.22 + }, + { + "i": 22, + "x": -0.42, + "y": -3.39, + "s": 0.22 + }, + { + "i": 23, + "x": -0.14, + "y": -3.39, + "s": 0.22 + }, + { + "i": 24, + "x": 0.14, + "y": -3.39, + "s": 0.22 + }, + { + "i": 25, + "x": 0.42, + "y": -3.39, + "s": 0.22 + }, + { + "i": 26, + "x": 0.7, + "y": -3.39, + "s": 0.22 + }, + { + "i": 27, + "x": 0.98, + "y": -3.39, + "s": 0.22 + }, + { + "i": 28, + "x": 1.26, + "y": -3.39, + "s": 0.22 + }, + { + "i": 29, + "x": 1.54, + "y": -3.39, + "s": 0.22 + }, + { + "i": 30, + "x": 1.82, + "y": -3.39, + "s": 0.22 + }, + { + "i": 31, + "x": 2.1, + "y": -3.39, + "s": 0.22 + }, + { + "i": 32, + "x": -2.1, + "y": -3.67, + "s": 0.22 + }, + { + "i": 33, + "x": -1.82, + "y": -3.67, + "s": 0.22 + }, + { + "i": 34, + "x": -1.54, + "y": -3.67, + "s": 0.22 + }, + { + "i": 35, + "x": -1.26, + "y": -3.67, + "s": 0.22 + }, + { + "i": 36, + "x": -0.98, + "y": -3.67, + "s": 0.22 + }, + { + "i": 37, + "x": -0.7, + "y": -3.67, + "s": 0.22 + }, + { + "i": 38, + "x": -0.42, + "y": -3.67, + "s": 0.22 + }, + { + "i": 39, + "x": -0.14, + "y": -3.67, + "s": 0.22 + }, + { + "i": 40, + "x": 0.14, + "y": -3.67, + "s": 0.22 + }, + { + "i": 41, + "x": 0.42, + "y": -3.67, + "s": 0.22 + }, + { + "i": 42, + "x": 0.7, + "y": -3.67, + "s": 0.22 + }, + { + "i": 43, + "x": 0.98, + "y": -3.67, + "s": 0.22 + }, + { + "i": 44, + "x": 1.26, + "y": -3.67, + "s": 0.22 + }, + { + "i": 45, + "x": 1.54, + "y": -3.67, + "s": 0.22 + }, + { + "i": 46, + "x": 1.82, + "y": -3.67, + "s": 0.22 + }, + { + "i": 47, + "x": 2.1, + "y": -3.67, + "s": 0.22 + }, + { + "i": 48, + "x": -2.1, + "y": -3.95, + "s": 0.22 + }, + { + "i": 49, + "x": -1.82, + "y": -3.95, + "s": 0.22 + }, + { + "i": 50, + "x": -1.54, + "y": -3.95, + "s": 0.22 + }, + { + "i": 51, + "x": -1.26, + "y": -3.95, + "s": 0.22 + }, + { + "i": 52, + "x": -0.98, + "y": -3.95, + "s": 0.22 + }, + { + "i": 53, + "x": -0.7, + "y": -3.95, + "s": 0.22 + }, + { + "i": 54, + "x": -0.42, + "y": -3.95, + "s": 0.22 + }, + { + "i": 55, + "x": -0.14, + "y": -3.95, + "s": 0.22 + }, + { + "i": 56, + "x": 0.14, + "y": -3.95, + "s": 0.22 + }, + { + "i": 57, + "x": 0.42, + "y": -3.95, + "s": 0.22 + }, + { + "i": 58, + "x": 0.7, + "y": -3.95, + "s": 0.22 + }, + { + "i": 59, + "x": 0.98, + "y": -3.95, + "s": 0.22 + }, + { + "i": 60, + "x": 1.26, + "y": -3.95, + "s": 0.22 + }, + { + "i": 61, + "x": 1.54, + "y": -3.95, + "s": 0.22 + }, + { + "i": 62, + "x": 1.82, + "y": -3.95, + "s": 0.22 + }, + { + "i": 63, + "x": 2.1, + "y": -3.95, + "s": 0.22 + } + ], + "idx": [] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "relocate", + "src": "row:row", + "dst": "_grow32:row", + "count": 32, + "t": 3.1, + "dur": 1.0 + }, + { + "type": "row_destroy", + "target": "row:row", + "write": "_raii_row_32", + "t": 4.1, + "dur": 2.4 + }, + { + "type": "fadeout", + "target": "_cap_row_32", + "t": 9.7, + "dur": 0.3 + }, + { + "type": "fadeout", + "target": "_raii_row_32", + "t": 10.0, + "dur": 0.3 + }, + { + "type": "row_swap", + "target": "row:row", + "tmp": "_grow32:row", + "to": [ + 0.0, + -1.0 + ], + "t": 10.3, + "dur": 0.5 + }, + { + "type": "counter", + "text": "size = 32 capacity = 64", + "t": 10.8, + "dur": 0.25 + } + ] + }, + { + "kind": "push", + "label": "push ×8 (turbo)", + "note": "[32,40)", + "duration": 0.4, + "speed": 3.6, + "events": [ + { + "type": "fill", + "target": "row:row", + "i": 32, + "s": 33, + "cap": 64, + "counter": true, + "t": 0.0, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 33, + "s": 34, + "cap": 64, + "counter": true, + "t": 0.05, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 34, + "s": 35, + "cap": 64, + "counter": true, + "t": 0.1, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 35, + "s": 36, + "cap": 64, + "counter": true, + "t": 0.15, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 36, + "s": 37, + "cap": 64, + "counter": true, + "t": 0.2, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 37, + "s": 38, + "cap": 64, + "counter": true, + "t": 0.25, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 38, + "s": 39, + "cap": 64, + "counter": true, + "t": 0.3, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 39, + "s": 40, + "cap": 64, + "counter": true, + "t": 0.35, + "dur": 0.05 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "0.5s", + "duration": 0.5, + "speed": 1.0, + "events": [] + }, + { + "kind": "conclude", + "label": "结论", + "note": "压轴结论墙", + "duration": 18.35, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "concl:0", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "write", + "target": "concl:1", + "t": 2.75, + "dur": 2.4 + }, + { + "type": "pulse", + "target": "counter", + "t": 15.35, + "dur": 1.0 + } + ] + } + ] +} diff --git a/site/.vitepress/theme/components/animations/data/opp2-grow-to-three-step.json b/site/.vitepress/theme/components/animations/data/opp2-grow-to-three-step.json new file mode 100644 index 000000000..3ca2baccc --- /dev/null +++ b/site/.vitepress/theme/components/animations/data/opp2-grow-to-three-step.json @@ -0,0 +1,875 @@ +{ + "version": 1, + "id": "opp2-grow-to-three-step", + "title": "扩容三步搬迁:申请 → Relocate → move", + "subtitle": "grow_to 源码逐行对应,搬迁零新增代码", + "source": "projects/vol8-vector-growth/02-dsl/opp2-grow-to-three-step.yaml", + "backend": "web", + "frame": { + "w": 14.2222, + "h": 8.0 + }, + "palette": { + "bg": "#17171f", + "text": "#ECECE4", + "muted": "#9a9aad", + "fill": "#5EC8E0", + "fillEdge": "#2E86AB", + "emptyEdge": "#4a4a5e", + "grow": "#FFB454", + "numOnFill": "#0e2430", + "ok": "#7BC96A", + "bad": "#E06C75", + "cardBg": "#1e1e2a" + }, + "actors": { + "title": { + "kind": "text", + "text": "扩容三步搬迁:申请 → Relocate → move", + "x": 0.0, + "y": 3.4324, + "fs": 0.32, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 7.8208, + "h": 0.4352 + }, + "sub": { + "kind": "text", + "text": "grow_to 源码逐行对应,搬迁零新增代码", + "x": 0.0, + "y": 2.8988, + "fs": 0.2, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 4.688, + "h": 0.272 + }, + "counter": { + "kind": "text", + "text": "size = 0 capacity = 0", + "x": 0.0, + "y": 1.6, + "fs": 0.3, + "color": "#ECECE4", + "mono": true, + "anchor": "middle", + "w": 4.752, + "h": 0.3 + }, + "_empty": { + "kind": "text", + "text": "还没申请内存", + "x": 0.0, + "y": -1.0, + "fs": 0.2, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 1.584, + "h": 0.272 + }, + "_cap_row": { + "kind": "text", + "text": "申请内存: capacity 0 → 4", + "x": 0.0, + "y": 0.1632, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 3.816, + "h": 0.3264 + }, + "row:row": { + "kind": "cells", + "cap": 8, + "side": 0.5, + "cx": 0.0, + "cy": -1.0, + "w": 4.42, + "h": 0.5, + "cells": [ + { + "i": 0, + "x": -1.96, + "y": -1.0, + "s": 0.5 + }, + { + "i": 1, + "x": -1.4, + "y": -1.0, + "s": 0.5 + }, + { + "i": 2, + "x": -0.84, + "y": -1.0, + "s": 0.5 + }, + { + "i": 3, + "x": -0.28, + "y": -1.0, + "s": 0.5 + }, + { + "i": 4, + "x": 0.28, + "y": -1.0, + "s": 0.5 + }, + { + "i": 5, + "x": 0.84, + "y": -1.0, + "s": 0.5 + }, + { + "i": 6, + "x": 1.4, + "y": -1.0, + "s": 0.5 + }, + { + "i": 7, + "x": 1.96, + "y": -1.0, + "s": 0.5 + } + ], + "idx": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ] + }, + "show:code": { + "kind": "code", + "fs": 0.2, + "lh": 0.258, + "pitch": 0.478, + "gutW": 0.1056, + "bodyW": 3.96, + "w": 4.8856, + "h": 3.646, + "rows": [ + { + "text": "void grow_to(size_t ncap) {", + "w": 3.564 + }, + { + "text": " RawBuffer next(ncap); // 1", + "w": 3.96 + }, + { + "text": " T* p = buf_.data();", + "w": 2.772 + }, + { + "text": " helper::Relocate( // 2", + "w": 3.96 + }, + { + "text": " p, p + cnt_, next.data());", + "w": 3.96 + }, + { + "text": " buf_ = std::move(next); // 3", + "w": 3.96 + }, + { + "text": "}", + "w": 0.132 + } + ], + "cx": 4.5983, + "cy": -1.22 + }, + "ptr:p_data": { + "kind": "ptr", + "id": "p_data", + "name": "data", + "above": true, + "x": -1.02, + "tipY": -0.45, + "baseY": -0.06, + "txt": { + "text": "data", + "x": -1.02, + "y": 0.1, + "fs": 0.22, + "color": "#ECECE4", + "mono": true, + "anchor": "middle", + "w": 0.5808, + "h": 0.22 + }, + "cx": -1.02, + "cy": -0.12, + "w": 0.5808, + "h": 0.66 + }, + "_cap_row_4": { + "kind": "text", + "text": "满了!capacity 4 → 8,grow_to!", + "x": 0.0, + "y": -2.1732, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 4.8768, + "h": 0.3264 + }, + "_grow4:row": { + "kind": "cells", + "cap": 8, + "side": 0.5, + "cx": 0.0, + "cy": -3.51, + "w": 4.42, + "h": 0.5, + "cells": [ + { + "i": 0, + "x": -1.96, + "y": -3.51, + "s": 0.5 + }, + { + "i": 1, + "x": -1.4, + "y": -3.51, + "s": 0.5 + }, + { + "i": 2, + "x": -0.84, + "y": -3.51, + "s": 0.5 + }, + { + "i": 3, + "x": -0.28, + "y": -3.51, + "s": 0.5 + }, + { + "i": 4, + "x": 0.28, + "y": -3.51, + "s": 0.5 + }, + { + "i": 5, + "x": 0.84, + "y": -3.51, + "s": 0.5 + }, + { + "i": 6, + "x": 1.4, + "y": -3.51, + "s": 0.5 + }, + { + "i": 7, + "x": 1.96, + "y": -3.51, + "s": 0.5 + } + ], + "idx": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ] + }, + "_raii_row_4": { + "kind": "text", + "text": "旧对象已逐个析构, 内存 RAII 归还", + "x": 0.0, + "y": -0.3176, + "fs": 0.18, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 3.744, + "h": 0.2448 + }, + "show:lb_move": { + "kind": "text", + "text": "data 已指向新内存", + "x": -1.96, + "y": -1.736, + "fs": 0.2, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 2.204, + "h": 0.272, + "id": "lb_move" + }, + "concl:0": { + "kind": "text", + "text": "扩容三步:申请新内存 → 搬迁并析构 → move 交还", + "x": 0.0, + "y": -2.084, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 7.3584, + "h": 0.3264 + }, + "concl:1": { + "kind": "text", + "text": "搬迁零新增代码:Relocate 原班人马", + "x": 0.0, + "y": -2.6604, + "fs": 0.24, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 5.1408, + "h": 0.3264 + }, + "concl:2": { + "kind": "text", + "text": "size / capacity 对外语义不变", + "x": 0.0, + "y": -3.2368, + "fs": 0.24, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 4.2816, + "h": 0.3264 + } + }, + "steps": [ + { + "kind": "intro", + "label": "开场", + "note": "", + "duration": 5.8, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "title", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "fadein", + "target": "sub", + "t": 2.4, + "dur": 0.5 + }, + { + "type": "fadein", + "target": "counter", + "t": 2.4, + "dur": 0.5 + }, + { + "type": "write", + "target": "_empty", + "t": 3.4, + "dur": 1.07 + }, + { + "type": "fadeout", + "target": "_empty", + "t": 5.5, + "dur": 0.3 + } + ] + }, + { + "kind": "grow_to", + "label": "申请 4", + "note": "capacity 0->4, 搬 0 格", + "duration": 6.15, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "row:row", + "g": { + "kind": "cells", + "cap": 4, + "side": 0.62, + "cx": 0.0, + "cy": -1.0, + "w": 2.66, + "h": 0.62, + "cells": [ + { + "i": 0, + "x": -1.02, + "y": -1.0, + "s": 0.62 + }, + { + "i": 1, + "x": -0.34, + "y": -1.0, + "s": 0.62 + }, + { + "i": 2, + "x": 0.34, + "y": -1.0, + "s": 0.62 + }, + { + "i": 3, + "x": 1.02, + "y": -1.0, + "s": 0.62 + } + ], + "idx": [ + 1, + 2, + 3, + 4 + ] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "fadeout", + "target": "_cap_row", + "t": 5.6, + "dur": 0.3 + }, + { + "type": "counter", + "text": "size = 0 capacity = 4", + "t": 5.9, + "dur": 0.25 + } + ] + }, + { + "kind": "push", + "label": "push ×4 (slow)", + "note": "[0,4)", + "duration": 1.2, + "speed": 0.6, + "events": [ + { + "type": "fill", + "target": "row:row", + "i": 0, + "s": 1, + "cap": 4, + "counter": true, + "t": 0.0, + "dur": 0.3 + }, + { + "type": "fill", + "target": "row:row", + "i": 1, + "s": 2, + "cap": 4, + "counter": true, + "t": 0.3, + "dur": 0.3 + }, + { + "type": "fill", + "target": "row:row", + "i": 2, + "s": 3, + "cap": 4, + "counter": true, + "t": 0.6, + "dur": 0.3 + }, + { + "type": "fill", + "target": "row:row", + "i": 3, + "s": 4, + "cap": 4, + "counter": true, + "t": 0.9, + "dur": 0.3 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "0.4s", + "duration": 0.4, + "speed": 1.0, + "events": [] + }, + { + "kind": "show", + "label": "show code", + "note": "", + "duration": 2.8, + "speed": 1.0, + "events": [ + { + "type": "code_show", + "target": "show:code", + "t": 0.0, + "dur": 2.8 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "1.2s", + "duration": 1.2, + "speed": 1.0, + "events": [] + }, + { + "kind": "hide", + "label": "hide code", + "note": "", + "duration": 0.75, + "speed": 1.0, + "events": [ + { + "type": "fadeout", + "target": "show:code", + "t": 0.35, + "dur": 0.4 + } + ] + }, + { + "kind": "point_to", + "label": "指针 data 出场", + "note": "index 0", + "duration": 0.4, + "speed": 1.0, + "events": [ + { + "type": "ptr_show", + "target": "p_data", + "t": 0.0, + "dur": 0.4 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "0.3s", + "duration": 0.3, + "speed": 1.0, + "events": [] + }, + { + "kind": "grow_to", + "label": "扩容 4→8", + "note": "capacity 4->8, 搬 4 格", + "duration": 11.35, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row_4", + "indicate": "row:row", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "_grow4:row", + "g": { + "kind": "cells", + "cap": 8, + "side": 0.5, + "cx": 0.0, + "cy": -3.51, + "w": 4.42, + "h": 0.5, + "cells": [ + { + "i": 0, + "x": -1.96, + "y": -3.51, + "s": 0.5 + }, + { + "i": 1, + "x": -1.4, + "y": -3.51, + "s": 0.5 + }, + { + "i": 2, + "x": -0.84, + "y": -3.51, + "s": 0.5 + }, + { + "i": 3, + "x": -0.28, + "y": -3.51, + "s": 0.5 + }, + { + "i": 4, + "x": 0.28, + "y": -3.51, + "s": 0.5 + }, + { + "i": 5, + "x": 0.84, + "y": -3.51, + "s": 0.5 + }, + { + "i": 6, + "x": 1.4, + "y": -3.51, + "s": 0.5 + }, + { + "i": 7, + "x": 1.96, + "y": -3.51, + "s": 0.5 + } + ], + "idx": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "relocate", + "src": "row:row", + "dst": "_grow4:row", + "count": 4, + "t": 3.1, + "dur": 1.0 + }, + { + "type": "row_destroy", + "target": "row:row", + "write": "_raii_row_4", + "t": 4.1, + "dur": 2.4 + }, + { + "type": "fadeout", + "target": "_cap_row_4", + "t": 9.7, + "dur": 0.3 + }, + { + "type": "fadeout", + "target": "_raii_row_4", + "t": 10.0, + "dur": 0.3 + }, + { + "type": "row_swap", + "target": "row:row", + "tmp": "_grow4:row", + "to": [ + 0.0, + -1.0 + ], + "t": 10.3, + "dur": 0.5 + }, + { + "type": "counter", + "text": "size = 4 capacity = 8", + "t": 10.8, + "dur": 0.25 + }, + { + "type": "ptr_move", + "target": "p_data", + "to": [ + -1.96, + -0.51 + ], + "t": 11.05, + "dur": 0.3 + } + ] + }, + { + "kind": "show", + "label": "show lb_move", + "note": "", + "duration": 1.67, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "show:lb_move", + "t": 0.0, + "dur": 1.67 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "0.8s", + "duration": 0.8, + "speed": 1.0, + "events": [] + }, + { + "kind": "hide", + "label": "hide lb_move", + "note": "", + "duration": 1.28, + "speed": 1.0, + "events": [ + { + "type": "fadeout", + "target": "show:lb_move", + "t": 0.88, + "dur": 0.4 + } + ] + }, + { + "kind": "push", + "label": "push ×1 (normal)", + "note": "[4,5)", + "duration": 0.18, + "speed": 1.0, + "events": [ + { + "type": "fill", + "target": "row:row", + "i": 4, + "s": 5, + "cap": 8, + "counter": true, + "t": 0.0, + "dur": 0.18 + } + ] + }, + { + "kind": "highlight", + "label": "高亮 [0,4) gold", + "note": "", + "duration": 1.6, + "speed": 1.0, + "events": [ + { + "type": "hl_show", + "frame": { + "kind": "frame", + "color": "#FFB454", + "cx": -1.12, + "cy": -1.0, + "w": 2.28, + "h": 0.6 + }, + "t": 0.0, + "dur": 0.4 + }, + { + "type": "hl_hide", + "frame": { + "kind": "frame", + "color": "#FFB454", + "cx": -1.12, + "cy": -1.0, + "w": 2.28, + "h": 0.6 + }, + "t": 1.3, + "dur": 0.3 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "0.5s", + "duration": 0.5, + "speed": 1.0, + "events": [] + }, + { + "kind": "conclude", + "label": "结论", + "note": "压轴结论墙", + "duration": 15.1, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "concl:0", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "write", + "target": "concl:1", + "t": 2.75, + "dur": 2.4 + }, + { + "type": "write", + "target": "concl:2", + "t": 5.5, + "dur": 2.4 + }, + { + "type": "pulse", + "target": "counter", + "t": 12.1, + "dur": 1.0 + } + ] + } + ] +} diff --git a/site/.vitepress/theme/components/animations/data/opp2-mirror-pair.json b/site/.vitepress/theme/components/animations/data/opp2-mirror-pair.json new file mode 100644 index 000000000..3ced2ae0a --- /dev/null +++ b/site/.vitepress/theme/components/animations/data/opp2-mirror-pair.json @@ -0,0 +1,718 @@ +{ + "version": 1, + "id": "opp2-mirror-pair", + "title": "placement new 与显式析构:一对镜像操作", + "subtitle": "内存和对象是两回事 —— 生在内存上,取走只剩裸内存", + "source": "projects/vol8-raw-buffer/02-dsl/opp2-mirror-pair.yaml", + "backend": "web", + "frame": { + "w": 14.2222, + "h": 8.0 + }, + "palette": { + "bg": "#17171f", + "text": "#ECECE4", + "muted": "#9a9aad", + "fill": "#5EC8E0", + "fillEdge": "#2E86AB", + "emptyEdge": "#4a4a5e", + "grow": "#FFB454", + "numOnFill": "#0e2430", + "ok": "#7BC96A", + "bad": "#E06C75", + "cardBg": "#1e1e2a" + }, + "actors": { + "title": { + "kind": "text", + "text": "placement new 与显式析构:一对镜像操作", + "x": 0.0, + "y": 3.4324, + "fs": 0.32, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 7.8464, + "h": 0.4352 + }, + "sub": { + "kind": "text", + "text": "内存和对象是两回事 —— 生在内存上,取走只剩裸内存", + "x": 0.0, + "y": 2.8988, + "fs": 0.2, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 6.584, + "h": 0.272 + }, + "counter": { + "kind": "text", + "text": "size = 0 capacity = 0", + "x": 0.0, + "y": 1.6, + "fs": 0.3, + "color": "#ECECE4", + "mono": true, + "anchor": "middle", + "w": 4.752, + "h": 0.3 + }, + "_empty": { + "kind": "text", + "text": "还没申请内存", + "x": 0.0, + "y": -1.0, + "fs": 0.2, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 1.584, + "h": 0.272 + }, + "_cap_row_l": { + "kind": "text", + "text": "申请内存: capacity 0 → 4", + "x": -3.4, + "y": 0.2632, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 3.816, + "h": 0.3264 + }, + "row:row_l": { + "kind": "cells", + "cap": 4, + "side": 0.62, + "cx": -3.4, + "cy": -0.9, + "w": 2.66, + "h": 0.62, + "cells": [ + { + "i": 0, + "x": -4.42, + "y": -0.9, + "s": 0.62 + }, + { + "i": 1, + "x": -3.74, + "y": -0.9, + "s": 0.62 + }, + { + "i": 2, + "x": -3.06, + "y": -0.9, + "s": 0.62 + }, + { + "i": 3, + "x": -2.38, + "y": -0.9, + "s": 0.62 + } + ], + "idx": [] + }, + "_cap_row_r": { + "kind": "text", + "text": "申请内存: capacity 0 → 4", + "x": 3.4, + "y": 0.2632, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 3.816, + "h": 0.3264 + }, + "row:row_r": { + "kind": "cells", + "cap": 4, + "side": 0.62, + "cx": 3.4, + "cy": -0.9, + "w": 2.66, + "h": 0.62, + "cells": [ + { + "i": 0, + "x": 2.38, + "y": -0.9, + "s": 0.62 + }, + { + "i": 1, + "x": 3.06, + "y": -0.9, + "s": 0.62 + }, + { + "i": 2, + "x": 3.74, + "y": -0.9, + "s": 0.62 + }, + { + "i": 3, + "x": 4.42, + "y": -0.9, + "s": 0.62 + } + ], + "idx": [] + }, + "ptr:p_l": { + "kind": "ptr", + "id": "p_l", + "name": "p", + "above": true, + "x": -4.42, + "tipY": -0.35, + "baseY": 0.04, + "txt": { + "text": "p", + "x": -4.42, + "y": 0.2, + "fs": 0.22, + "color": "#ECECE4", + "mono": true, + "anchor": "middle", + "w": 0.1452, + "h": 0.22 + }, + "cx": -4.42, + "cy": -0.02, + "w": 0.1452, + "h": 0.66 + }, + "ptr:p_r": { + "kind": "ptr", + "id": "p_r", + "name": "p", + "above": true, + "x": 2.38, + "tipY": -0.35, + "baseY": 0.04, + "txt": { + "text": "p", + "x": 2.38, + "y": 0.2, + "fs": 0.22, + "color": "#ECECE4", + "mono": true, + "anchor": "middle", + "w": 0.1452, + "h": 0.22 + }, + "cx": 2.38, + "cy": -0.02, + "w": 0.1452, + "h": 0.66 + }, + "show:lb_l": { + "kind": "text", + "text": "对象活在内存上(已构造)", + "x": -3.4, + "y": 0.6, + "fs": 0.2, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 3.168, + "h": 0.272, + "id": "lb_l" + }, + "show:lb_r": { + "kind": "text", + "text": "对象已取走(已析构)", + "x": 3.4, + "y": 0.6, + "fs": 0.2, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 2.64, + "h": 0.272, + "id": "lb_r" + }, + "show:lb_mid": { + "kind": "text", + "text": "同一段内存 · 两种时刻", + "x": 0, + "y": -0.9, + "fs": 0.2, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 2.748, + "h": 0.272, + "id": "lb_mid" + }, + "show:code_l": { + "kind": "code", + "fs": 0.2, + "lh": 0.258, + "pitch": 0.478, + "gutW": 0.1056, + "bodyW": 2.904, + "w": 3.8296, + "h": 0.778, + "rows": [ + { + "text": "new (p) T(args); // 生", + "w": 2.904 + } + ], + "cx": -3.4, + "cy": -2.75 + }, + "show:code_r": { + "kind": "code", + "fs": 0.2, + "lh": 0.258, + "pitch": 0.478, + "gutW": 0.1056, + "bodyW": 2.112, + "w": 3.0376, + "h": 0.778, + "rows": [ + { + "text": "p->~T(); // 取走", + "w": 2.112 + } + ], + "cx": 3.4, + "cy": -2.75 + }, + "concl:0": { + "kind": "text", + "text": "placement new: 只构造, 不分配", + "x": 0.0, + "y": -2.084, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 4.4304, + "h": 0.3264 + }, + "concl:1": { + "kind": "text", + "text": "显式析构: 只销毁, 不释放", + "x": 0.0, + "y": -2.6604, + "fs": 0.24, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 3.7632, + "h": 0.3264 + }, + "concl:2": { + "kind": "text", + "text": "内存和对象, 是两回事", + "x": 0.0, + "y": -3.2368, + "fs": 0.24, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 3.1488, + "h": 0.3264 + } + }, + "steps": [ + { + "kind": "intro", + "label": "开场", + "note": "", + "duration": 5.8, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "title", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "fadein", + "target": "sub", + "t": 2.4, + "dur": 0.5 + }, + { + "type": "fadein", + "target": "counter", + "t": 2.4, + "dur": 0.5 + }, + { + "type": "write", + "target": "_empty", + "t": 3.4, + "dur": 1.07 + }, + { + "type": "fadeout", + "target": "_empty", + "t": 5.5, + "dur": 0.3 + } + ] + }, + { + "kind": "grow_to", + "label": "申请 4", + "note": "capacity 0->4, 搬 0 格", + "duration": 6.15, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row_l", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "row:row_l", + "g": { + "kind": "cells", + "cap": 4, + "side": 0.62, + "cx": -3.4, + "cy": -0.9, + "w": 2.66, + "h": 0.62, + "cells": [ + { + "i": 0, + "x": -4.42, + "y": -0.9, + "s": 0.62 + }, + { + "i": 1, + "x": -3.74, + "y": -0.9, + "s": 0.62 + }, + { + "i": 2, + "x": -3.06, + "y": -0.9, + "s": 0.62 + }, + { + "i": 3, + "x": -2.38, + "y": -0.9, + "s": 0.62 + } + ], + "idx": [] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "fadeout", + "target": "_cap_row_l", + "t": 5.6, + "dur": 0.3 + }, + { + "type": "counter", + "text": "size = 0 capacity = 4", + "t": 5.9, + "dur": 0.25 + } + ] + }, + { + "kind": "push", + "label": "push ×3 (slow)", + "note": "[0,3)", + "duration": 0.9, + "speed": 0.6, + "events": [ + { + "type": "fill", + "target": "row:row_l", + "i": 0, + "s": 1, + "cap": 4, + "counter": true, + "t": 0.0, + "dur": 0.3 + }, + { + "type": "fill", + "target": "row:row_l", + "i": 1, + "s": 2, + "cap": 4, + "counter": true, + "t": 0.3, + "dur": 0.3 + }, + { + "type": "fill", + "target": "row:row_l", + "i": 2, + "s": 3, + "cap": 4, + "counter": true, + "t": 0.6, + "dur": 0.3 + } + ] + }, + { + "kind": "grow_to", + "label": "申请 4", + "note": "capacity 0->4, 搬 0 格", + "duration": 5.9, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row_r", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "row:row_r", + "g": { + "kind": "cells", + "cap": 4, + "side": 0.62, + "cx": 3.4, + "cy": -0.9, + "w": 2.66, + "h": 0.62, + "cells": [ + { + "i": 0, + "x": 2.38, + "y": -0.9, + "s": 0.62 + }, + { + "i": 1, + "x": 3.06, + "y": -0.9, + "s": 0.62 + }, + { + "i": 2, + "x": 3.74, + "y": -0.9, + "s": 0.62 + }, + { + "i": 3, + "x": 4.42, + "y": -0.9, + "s": 0.62 + } + ], + "idx": [] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "fadeout", + "target": "_cap_row_r", + "t": 5.6, + "dur": 0.3 + } + ] + }, + { + "kind": "point_to", + "label": "指针 p 出场", + "note": "index 0", + "duration": 0.4, + "speed": 1.0, + "events": [ + { + "type": "ptr_show", + "target": "p_l", + "t": 0.0, + "dur": 0.4 + } + ] + }, + { + "kind": "point_to", + "label": "指针 p 出场", + "note": "index 0", + "duration": 0.4, + "speed": 1.0, + "events": [ + { + "type": "ptr_show", + "target": "p_r", + "t": 0.0, + "dur": 0.4 + } + ] + }, + { + "kind": "show", + "label": "show lb_l", + "note": "", + "duration": 1.79, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "show:lb_l", + "t": 0.0, + "dur": 1.79 + } + ] + }, + { + "kind": "show", + "label": "show lb_r", + "note": "", + "duration": 1.55, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "show:lb_r", + "t": 0.0, + "dur": 1.55 + } + ] + }, + { + "kind": "show", + "label": "show lb_mid", + "note": "", + "duration": 1.79, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "show:lb_mid", + "t": 0.0, + "dur": 1.79 + } + ] + }, + { + "kind": "show", + "label": "show code_l", + "note": "", + "duration": 2.8, + "speed": 1.0, + "events": [ + { + "type": "code_show", + "target": "show:code_l", + "t": 0.0, + "dur": 2.8 + } + ] + }, + { + "kind": "show", + "label": "show code_r", + "note": "", + "duration": 2.43, + "speed": 1.0, + "events": [ + { + "type": "code_show", + "target": "show:code_r", + "t": 0.0, + "dur": 2.43 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "1.0s", + "duration": 1.0, + "speed": 1.0, + "events": [] + }, + { + "kind": "conclude", + "label": "结论", + "note": "压轴结论墙", + "duration": 13.48, + "speed": 1.0, + "events": [ + { + "type": "fadeout", + "target": "show:code_l", + "t": 0.0, + "dur": 0.3 + }, + { + "type": "fadeout", + "target": "show:code_r", + "t": 0.3, + "dur": 0.3 + }, + { + "type": "fadeout", + "target": "show:lb_l", + "t": 0.6, + "dur": 0.3 + }, + { + "type": "fadeout", + "target": "show:lb_mid", + "t": 0.9, + "dur": 0.3 + }, + { + "type": "fadeout", + "target": "show:lb_r", + "t": 1.2, + "dur": 0.3 + }, + { + "type": "write", + "target": "concl:0", + "t": 1.5, + "dur": 2.4 + }, + { + "type": "write", + "target": "concl:1", + "t": 4.25, + "dur": 2.03 + }, + { + "type": "write", + "target": "concl:2", + "t": 6.63, + "dur": 1.67 + }, + { + "type": "pulse", + "target": "counter", + "t": 10.48, + "dur": 1.0 + } + ] + } + ] +} diff --git a/site/.vitepress/theme/components/animations/data/opp3-candidate-matrix.json b/site/.vitepress/theme/components/animations/data/opp3-candidate-matrix.json new file mode 100644 index 000000000..374b8a6f6 --- /dev/null +++ b/site/.vitepress/theme/components/animations/data/opp3-candidate-matrix.json @@ -0,0 +1,480 @@ +{ + "version": 1, + "id": "opp3-candidate-matrix", + "title": "裸内存三选一:operator new / new T[n] / malloc", + "subtitle": "大小对、对齐对、内容未定义 —— 三项考核", + "source": "projects/vol8-raw-buffer/02-dsl/opp3-candidate-matrix.yaml", + "backend": "web", + "frame": { + "w": 14.2222, + "h": 8.0 + }, + "palette": { + "bg": "#17171f", + "text": "#ECECE4", + "muted": "#9a9aad", + "fill": "#5EC8E0", + "fillEdge": "#2E86AB", + "emptyEdge": "#4a4a5e", + "grow": "#FFB454", + "numOnFill": "#0e2430", + "ok": "#7BC96A", + "bad": "#E06C75", + "cardBg": "#1e1e2a" + }, + "actors": { + "title": { + "kind": "text", + "text": "裸内存三选一:operator new / new T[n] / malloc", + "x": 0.0, + "y": 3.4324, + "fs": 0.32, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 9.3056, + "h": 0.4352 + }, + "sub": { + "kind": "text", + "text": "大小对、对齐对、内容未定义 —— 三项考核", + "x": 0.0, + "y": 2.8988, + "fs": 0.2, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 5.264, + "h": 0.272 + }, + "counter": { + "kind": "text", + "text": "size = 0 capacity = 0", + "x": 0.0, + "y": 1.6, + "fs": 0.3, + "color": "#ECECE4", + "mono": true, + "anchor": "middle", + "w": 4.752, + "h": 0.3 + }, + "_empty": { + "kind": "text", + "text": "还没申请内存", + "x": 0.0, + "y": -1.0, + "fs": 0.2, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 1.584, + "h": 0.272 + }, + "_cap_row": { + "kind": "text", + "text": "申请内存: capacity 0 → 4", + "x": 0.0, + "y": 0.1632, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 3.816, + "h": 0.3264 + }, + "row:row": { + "kind": "cells", + "cap": 4, + "side": 0.62, + "cx": 5.0, + "cy": 1.55, + "w": 2.66, + "h": 0.62, + "cells": [ + { + "i": 0, + "x": 3.98, + "y": 1.55, + "s": 0.62 + }, + { + "i": 1, + "x": 4.66, + "y": 1.55, + "s": 0.62 + }, + { + "i": 2, + "x": 5.34, + "y": 1.55, + "s": 0.62 + }, + { + "i": 3, + "x": 6.02, + "y": 1.55, + "s": 0.62 + } + ], + "idx": [] + }, + "show:matrix": { + "kind": "rowlist", + "w": 9.5616, + "h": 3.034, + "noteX": 2.8108, + "entries": [ + { + "card": { + "kind": "card", + "fs": 0.2, + "lh": 0.258, + "pitch": 0.478, + "gutW": 0.1056, + "bodyW": 3.696, + "w": 4.6216, + "h": 0.778, + "rows": [ + { + "text": "void* p = ::operator new(n);", + "w": 3.696 + } + ] + }, + "note": { + "text": "当选:大小对 · 对齐对 · 内容未定义", + "x": 0, + "y": 0, + "fs": 0.2, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 4.44, + "h": 0.272 + }, + "tone": "ok" + }, + { + "card": { + "kind": "card", + "fs": 0.2, + "lh": 0.258, + "pitch": 0.478, + "gutW": 0.1056, + "bodyW": 3.696, + "w": 4.6216, + "h": 0.778, + "rows": [ + { + "text": "Sources* p = new Sources[n];", + "w": 3.696 + } + ] + }, + "note": { + "text": "落选:越位——无对象处也构造", + "x": 0, + "y": 0, + "fs": 0.2, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 3.696, + "h": 0.272 + }, + "tone": "bad" + }, + { + "card": { + "kind": "card", + "fs": 0.2, + "lh": 0.258, + "pitch": 0.478, + "gutW": 0.1056, + "bodyW": 3.3, + "w": 4.2256, + "h": 0.778, + "rows": [ + { + "text": "void* p = std::malloc(n);", + "w": 3.3 + } + ] + }, + "note": { + "text": "落选:对齐不保证 · 要手动转型", + "x": 0, + "y": 0, + "fs": 0.2, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 3.804, + "h": 0.272 + }, + "tone": "bad" + } + ], + "rowHs": [ + 0.778, + 0.778, + 0.778 + ], + "cx": 0, + "cy": -0.75 + }, + "show:row_note": { + "kind": "text", + "text": "要的只是一段空格子", + "x": 5.0, + "y": 2.25, + "fs": 0.2, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 2.376, + "h": 0.272, + "id": "row_note" + }, + "concl:0": { + "kind": "text", + "text": "裸内存三选一: ::operator new 当选", + "x": 0.0, + "y": -2.6604, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 5.064, + "h": 0.3264 + }, + "concl:1": { + "kind": "text", + "text": "new T[n] 越位构造, malloc 欠对齐", + "x": 0.0, + "y": -3.2368, + "fs": 0.24, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 4.896, + "h": 0.3264 + } + }, + "steps": [ + { + "kind": "intro", + "label": "开场", + "note": "", + "duration": 5.8, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "title", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "fadein", + "target": "sub", + "t": 2.4, + "dur": 0.5 + }, + { + "type": "fadein", + "target": "counter", + "t": 2.4, + "dur": 0.5 + }, + { + "type": "write", + "target": "_empty", + "t": 3.4, + "dur": 1.07 + }, + { + "type": "fadeout", + "target": "_empty", + "t": 5.5, + "dur": 0.3 + } + ] + }, + { + "kind": "grow_to", + "label": "申请 4", + "note": "capacity 0->4, 搬 0 格", + "duration": 6.15, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "row:row", + "g": { + "kind": "cells", + "cap": 4, + "side": 0.62, + "cx": 0.0, + "cy": -1.0, + "w": 2.66, + "h": 0.62, + "cells": [ + { + "i": 0, + "x": -1.02, + "y": -1.0, + "s": 0.62 + }, + { + "i": 1, + "x": -0.34, + "y": -1.0, + "s": 0.62 + }, + { + "i": 2, + "x": 0.34, + "y": -1.0, + "s": 0.62 + }, + { + "i": 3, + "x": 1.02, + "y": -1.0, + "s": 0.62 + } + ], + "idx": [] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "fadeout", + "target": "_cap_row", + "t": 5.6, + "dur": 0.3 + }, + { + "type": "counter", + "text": "size = 0 capacity = 4", + "t": 5.9, + "dur": 0.25 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "0.5s", + "duration": 0.5, + "speed": 1.0, + "events": [] + }, + { + "kind": "hide", + "label": "counter 退场", + "note": "", + "duration": 0.4, + "speed": 1.0, + "events": [ + { + "type": "fadeout", + "target": "counter", + "t": 0.0, + "dur": 0.4 + } + ] + }, + { + "kind": "move", + "label": "move row", + "note": "to [5.0, 1.55]", + "duration": 0.5, + "speed": 1.0, + "events": [ + { + "type": "move", + "target": "row:row", + "frm": [ + 0.0, + -1.0 + ], + "to": [ + 5.0, + 1.55 + ], + "t": 0.0, + "dur": 0.5 + } + ] + }, + { + "kind": "show", + "label": "show matrix", + "note": "", + "duration": 3.6, + "speed": 1.0, + "events": [ + { + "type": "rowlist_show", + "target": "show:matrix", + "t": 0.0, + "dur": 3.6 + } + ] + }, + { + "kind": "show", + "label": "show row_note", + "note": "", + "duration": 1.43, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "show:row_note", + "t": 0.0, + "dur": 1.43 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "1.0s", + "duration": 1.0, + "speed": 1.0, + "events": [] + }, + { + "kind": "conclude", + "label": "结论", + "note": "压轴结论墙", + "duration": 12.1, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "concl:0", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "write", + "target": "concl:1", + "t": 2.75, + "dur": 2.4 + } + ] + } + ] +} diff --git a/site/.vitepress/theme/components/animations/data/opp3-two-representations.json b/site/.vitepress/theme/components/animations/data/opp3-two-representations.json new file mode 100644 index 000000000..b7803678f --- /dev/null +++ b/site/.vitepress/theme/components/animations/data/opp3-two-representations.json @@ -0,0 +1,739 @@ +{ + "version": 1, + "id": "opp3-two-representations", + "title": "双表示并排:三指针 vs 指针+计数", + "subtitle": "libstdc++ 内部三指针,语义与指针+计数完全等价", + "source": "projects/vol8-vector-growth/02-dsl/opp3-two-representations.yaml", + "backend": "web", + "frame": { + "w": 14.2222, + "h": 8.0 + }, + "palette": { + "bg": "#17171f", + "text": "#ECECE4", + "muted": "#9a9aad", + "fill": "#5EC8E0", + "fillEdge": "#2E86AB", + "emptyEdge": "#4a4a5e", + "grow": "#FFB454", + "numOnFill": "#0e2430", + "ok": "#7BC96A", + "bad": "#E06C75", + "cardBg": "#1e1e2a" + }, + "actors": { + "title": { + "kind": "text", + "text": "双表示并排:三指针 vs 指针+计数", + "x": 0.0, + "y": 3.4324, + "fs": 0.32, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 6.4832, + "h": 0.4352 + }, + "sub": { + "kind": "text", + "text": "libstdc++ 内部三指针,语义与指针+计数完全等价", + "x": 0.0, + "y": 2.8988, + "fs": 0.2, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 5.852, + "h": 0.272 + }, + "counter": { + "kind": "text", + "text": "size = 0 capacity = 0", + "x": 0.0, + "y": 1.6, + "fs": 0.3, + "color": "#ECECE4", + "mono": true, + "anchor": "middle", + "w": 4.752, + "h": 0.3 + }, + "_empty": { + "kind": "text", + "text": "还没申请内存", + "x": 0.0, + "y": -1.0, + "fs": 0.2, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 1.584, + "h": 0.272 + }, + "_cap_row_b": { + "kind": "text", + "text": "申请内存: capacity 0 → 4", + "x": 3.4, + "y": 0.2632, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 3.816, + "h": 0.3264 + }, + "row:row_b": { + "kind": "cells", + "cap": 4, + "side": 0.62, + "cx": 3.4, + "cy": -0.9, + "w": 2.66, + "h": 0.62, + "cells": [ + { + "i": 0, + "x": 2.38, + "y": -0.9, + "s": 0.62 + }, + { + "i": 1, + "x": 3.06, + "y": -0.9, + "s": 0.62 + }, + { + "i": 2, + "x": 3.74, + "y": -0.9, + "s": 0.62 + }, + { + "i": 3, + "x": 4.42, + "y": -0.9, + "s": 0.62 + } + ], + "idx": [] + }, + "_cap_row_a": { + "kind": "text", + "text": "申请内存: capacity 0 → 4", + "x": -3.4, + "y": 0.2632, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 3.816, + "h": 0.3264 + }, + "row:row_a": { + "kind": "cells", + "cap": 4, + "side": 0.62, + "cx": -3.4, + "cy": -0.9, + "w": 2.66, + "h": 0.62, + "cells": [ + { + "i": 0, + "x": -4.42, + "y": -0.9, + "s": 0.62 + }, + { + "i": 1, + "x": -3.74, + "y": -0.9, + "s": 0.62 + }, + { + "i": 2, + "x": -3.06, + "y": -0.9, + "s": 0.62 + }, + { + "i": 3, + "x": -2.38, + "y": -0.9, + "s": 0.62 + } + ], + "idx": [] + }, + "ptr:p_data": { + "kind": "ptr", + "id": "p_data", + "name": "data", + "above": true, + "x": 2.38, + "tipY": -0.35, + "baseY": 0.04, + "txt": { + "text": "data", + "x": 2.38, + "y": 0.2, + "fs": 0.22, + "color": "#ECECE4", + "mono": true, + "anchor": "middle", + "w": 0.5808, + "h": 0.22 + }, + "cx": 2.38, + "cy": -0.02, + "w": 0.5808, + "h": 0.66 + }, + "ptr:p_begin": { + "kind": "ptr", + "id": "p_begin", + "name": "start", + "above": true, + "x": -4.42, + "tipY": -0.35, + "baseY": 0.04, + "txt": { + "text": "start", + "x": -4.42, + "y": 0.2, + "fs": 0.22, + "color": "#ECECE4", + "mono": true, + "anchor": "middle", + "w": 0.726, + "h": 0.22 + }, + "cx": -4.42, + "cy": -0.02, + "w": 0.726, + "h": 0.66 + }, + "ptr:p_finish": { + "kind": "ptr", + "id": "p_finish", + "name": "finish", + "above": false, + "x": -3.06, + "tipY": -1.45, + "baseY": -1.84, + "txt": { + "text": "finish", + "x": -3.06, + "y": -2.0, + "fs": 0.22, + "color": "#ECECE4", + "mono": true, + "anchor": "middle", + "w": 0.8712, + "h": 0.22 + }, + "cx": -3.06, + "cy": -1.78, + "w": 0.8712, + "h": 0.66 + }, + "ptr:p_capend": { + "kind": "ptr", + "id": "p_capend", + "name": "cap_end", + "above": true, + "x": -2.07, + "tipY": -0.35, + "baseY": 0.04, + "txt": { + "text": "cap_end", + "x": -2.07, + "y": 0.2, + "fs": 0.22, + "color": "#ECECE4", + "mono": true, + "anchor": "middle", + "w": 1.0164, + "h": 0.22 + }, + "cx": -2.07, + "cy": -0.02, + "w": 1.0164, + "h": 0.66 + }, + "show:lb_eq": { + "kind": "text", + "text": "同一个 vector,两种画法", + "x": 0, + "y": -0.9, + "fs": 0.2, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 2.98, + "h": 0.272, + "id": "lb_eq" + }, + "concl:0": { + "kind": "text", + "text": "三指针: start / finish / cap_end", + "x": 0.0, + "y": -2.084, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 4.8192, + "h": 0.3264 + }, + "concl:1": { + "kind": "text", + "text": "指针 + 计数: data + size + capacity", + "x": 0.0, + "y": -2.6604, + "fs": 0.24, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 5.2848, + "h": 0.3264 + }, + "concl:2": { + "kind": "text", + "text": "等价表示, sizeof 都是 24 字节", + "x": 0.0, + "y": -3.2368, + "fs": 0.24, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 4.4688, + "h": 0.3264 + } + }, + "steps": [ + { + "kind": "intro", + "label": "开场", + "note": "", + "duration": 5.8, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "title", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "fadein", + "target": "sub", + "t": 2.4, + "dur": 0.5 + }, + { + "type": "fadein", + "target": "counter", + "t": 2.4, + "dur": 0.5 + }, + { + "type": "write", + "target": "_empty", + "t": 3.4, + "dur": 1.07 + }, + { + "type": "fadeout", + "target": "_empty", + "t": 5.5, + "dur": 0.3 + } + ] + }, + { + "kind": "grow_to", + "label": "申请 4", + "note": "capacity 0->4, 搬 0 格", + "duration": 6.15, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row_b", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "row:row_b", + "g": { + "kind": "cells", + "cap": 4, + "side": 0.62, + "cx": 3.4, + "cy": -0.9, + "w": 2.66, + "h": 0.62, + "cells": [ + { + "i": 0, + "x": 2.38, + "y": -0.9, + "s": 0.62 + }, + { + "i": 1, + "x": 3.06, + "y": -0.9, + "s": 0.62 + }, + { + "i": 2, + "x": 3.74, + "y": -0.9, + "s": 0.62 + }, + { + "i": 3, + "x": 4.42, + "y": -0.9, + "s": 0.62 + } + ], + "idx": [] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "fadeout", + "target": "_cap_row_b", + "t": 5.6, + "dur": 0.3 + }, + { + "type": "counter", + "text": "size = 0 capacity = 4", + "t": 5.9, + "dur": 0.25 + } + ] + }, + { + "kind": "push", + "label": "push ×2 (slow)", + "note": "[0,2)", + "duration": 0.6, + "speed": 0.6, + "events": [ + { + "type": "fill", + "target": "row:row_b", + "i": 0, + "s": 1, + "cap": 4, + "counter": true, + "t": 0.0, + "dur": 0.3 + }, + { + "type": "fill", + "target": "row:row_b", + "i": 1, + "s": 2, + "cap": 4, + "counter": true, + "t": 0.3, + "dur": 0.3 + } + ] + }, + { + "kind": "grow_to", + "label": "申请 4", + "note": "capacity 0->4, 搬 0 格", + "duration": 5.9, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row_a", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "row:row_a", + "g": { + "kind": "cells", + "cap": 4, + "side": 0.62, + "cx": -3.4, + "cy": -0.9, + "w": 2.66, + "h": 0.62, + "cells": [ + { + "i": 0, + "x": -4.42, + "y": -0.9, + "s": 0.62 + }, + { + "i": 1, + "x": -3.74, + "y": -0.9, + "s": 0.62 + }, + { + "i": 2, + "x": -3.06, + "y": -0.9, + "s": 0.62 + }, + { + "i": 3, + "x": -2.38, + "y": -0.9, + "s": 0.62 + } + ], + "idx": [] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "fadeout", + "target": "_cap_row_a", + "t": 5.6, + "dur": 0.3 + } + ] + }, + { + "kind": "push", + "label": "push ×2 (fast)", + "note": "[0,2)", + "duration": 0.2, + "speed": 1.8, + "events": [ + { + "type": "fill", + "target": "row:row_a", + "i": 0, + "s": 1, + "cap": 4, + "counter": false, + "t": 0.0, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row_a", + "i": 1, + "s": 2, + "cap": 4, + "counter": false, + "t": 0.1, + "dur": 0.1 + } + ] + }, + { + "kind": "point_to", + "label": "指针 data 出场", + "note": "index 0", + "duration": 0.4, + "speed": 1.0, + "events": [ + { + "type": "ptr_show", + "target": "p_data", + "t": 0.0, + "dur": 0.4 + } + ] + }, + { + "kind": "point_to", + "label": "指针 start 出场", + "note": "index 0", + "duration": 0.4, + "speed": 1.0, + "events": [ + { + "type": "ptr_show", + "target": "p_begin", + "t": 0.0, + "dur": 0.4 + } + ] + }, + { + "kind": "point_to", + "label": "指针 finish 出场", + "note": "index 2", + "duration": 0.4, + "speed": 1.0, + "events": [ + { + "type": "ptr_show", + "target": "p_finish", + "t": 0.0, + "dur": 0.4 + } + ] + }, + { + "kind": "point_to", + "label": "指针 cap_end 出场", + "note": "index 4", + "duration": 0.4, + "speed": 1.0, + "events": [ + { + "type": "ptr_show", + "target": "p_capend", + "t": 0.0, + "dur": 0.4 + } + ] + }, + { + "kind": "highlight", + "label": "高亮 [0,2) gold", + "note": "", + "duration": 1.6, + "speed": 1.0, + "events": [ + { + "type": "hl_show", + "frame": { + "kind": "frame", + "color": "#FFB454", + "cx": 2.72, + "cy": -0.9, + "w": 1.4, + "h": 0.72 + }, + "t": 0.0, + "dur": 0.4 + }, + { + "type": "hl_hide", + "frame": { + "kind": "frame", + "color": "#FFB454", + "cx": 2.72, + "cy": -0.9, + "w": 1.4, + "h": 0.72 + }, + "t": 1.3, + "dur": 0.3 + } + ] + }, + { + "kind": "highlight", + "label": "高亮 [0,2) gold", + "note": "", + "duration": 1.6, + "speed": 1.0, + "events": [ + { + "type": "hl_show", + "frame": { + "kind": "frame", + "color": "#FFB454", + "cx": -4.08, + "cy": -0.9, + "w": 1.4, + "h": 0.72 + }, + "t": 0.0, + "dur": 0.4 + }, + { + "type": "hl_hide", + "frame": { + "kind": "frame", + "color": "#FFB454", + "cx": -4.08, + "cy": -0.9, + "w": 1.4, + "h": 0.72 + }, + "t": 1.3, + "dur": 0.3 + } + ] + }, + { + "kind": "show", + "label": "show lb_eq", + "note": "", + "duration": 2.15, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "show:lb_eq", + "t": 0.0, + "dur": 2.15 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "1.0s", + "duration": 1.0, + "speed": 1.0, + "events": [] + }, + { + "kind": "conclude", + "label": "结论", + "note": "压轴结论墙", + "duration": 15.15, + "speed": 1.0, + "events": [ + { + "type": "fadeout", + "target": "show:lb_eq", + "t": 0.0, + "dur": 0.3 + }, + { + "type": "write", + "target": "concl:0", + "t": 0.3, + "dur": 2.4 + }, + { + "type": "write", + "target": "concl:1", + "t": 3.05, + "dur": 2.4 + }, + { + "type": "write", + "target": "concl:2", + "t": 5.8, + "dur": 2.4 + }, + { + "type": "pulse", + "target": "counter", + "t": 12.15, + "dur": 1.0 + } + ] + } + ] +} diff --git a/site/.vitepress/theme/components/animations/data/opp4-crash-receipt.json b/site/.vitepress/theme/components/animations/data/opp4-crash-receipt.json new file mode 100644 index 000000000..c24a4ff54 --- /dev/null +++ b/site/.vitepress/theme/components/animations/data/opp4-crash-receipt.json @@ -0,0 +1,457 @@ +{ + "version": 1, + "id": "opp4-crash-receipt", + "title": "乘法先验溢出检查:宁可崩,不带病跑", + "subtitle": "SIZE_MAX/4+1 个 int 的请求,当场被拦", + "source": "projects/vol8-raw-buffer/02-dsl/opp4-crash-receipt.yaml", + "backend": "web", + "frame": { + "w": 14.2222, + "h": 8.0 + }, + "palette": { + "bg": "#17171f", + "text": "#ECECE4", + "muted": "#9a9aad", + "fill": "#5EC8E0", + "fillEdge": "#2E86AB", + "emptyEdge": "#4a4a5e", + "grow": "#FFB454", + "numOnFill": "#0e2430", + "ok": "#7BC96A", + "bad": "#E06C75", + "cardBg": "#1e1e2a" + }, + "actors": { + "title": { + "kind": "text", + "text": "乘法先验溢出检查:宁可崩,不带病跑", + "x": 0.0, + "y": 3.4324, + "fs": 0.32, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 7.1808, + "h": 0.4352 + }, + "sub": { + "kind": "text", + "text": "SIZE_MAX/4+1 个 int 的请求,当场被拦", + "x": 0.0, + "y": 2.8988, + "fs": 0.2, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 4.608, + "h": 0.272 + }, + "counter": { + "kind": "text", + "text": "size = 0 capacity = 0", + "x": 0.0, + "y": 1.6, + "fs": 0.3, + "color": "#ECECE4", + "mono": true, + "anchor": "middle", + "w": 4.752, + "h": 0.3 + }, + "_empty": { + "kind": "text", + "text": "还没申请内存", + "x": 0.0, + "y": -1.0, + "fs": 0.2, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 1.584, + "h": 0.272 + }, + "_cap_row": { + "kind": "text", + "text": "申请内存: capacity 0 → 4", + "x": 4.9, + "y": -0.9368, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 3.816, + "h": 0.3264 + }, + "row:row": { + "kind": "cells", + "cap": 4, + "side": 0.62, + "cx": 4.9, + "cy": -2.1, + "w": 2.66, + "h": 0.62, + "cells": [ + { + "i": 0, + "x": 3.88, + "y": -2.1, + "s": 0.62 + }, + { + "i": 1, + "x": 4.56, + "y": -2.1, + "s": 0.62 + }, + { + "i": 2, + "x": 5.24, + "y": -2.1, + "s": 0.62 + }, + { + "i": 3, + "x": 5.92, + "y": -2.1, + "s": 0.62 + } + ], + "idx": [] + }, + "show:code_req": { + "kind": "code", + "fs": 0.2, + "lh": 0.258, + "pitch": 0.478, + "gutW": 0.1056, + "bodyW": 4.356, + "w": 5.2816, + "h": 0.778, + "rows": [ + { + "text": "Sources s(SIZE_MAX / 4 + 1);", + "w": 4.356 + } + ], + "cx": 0, + "cy": 0.65 + }, + "show:code_crash": { + "kind": "code", + "fs": 0.3, + "lh": 0.387, + "pitch": 0.607, + "gutW": 0.1584, + "bodyW": 7.128, + "w": 8.1064, + "h": 1.514, + "rows": [ + { + "text": "[TAMCPP Check Crash]", + "w": 3.96 + }, + { + "text": "capacity * sizeof(Sources) overflows", + "w": 7.128 + } + ], + "cx": -1, + "cy": -1.1 + }, + "show:row_note": { + "kind": "text", + "text": "对照:正常请求——检查通过", + "x": 3.88, + "y": -2.896, + "fs": 0.2, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 3.432, + "h": 0.272, + "id": "row_note" + }, + "concl:0": { + "kind": "text", + "text": "SIZE_MAX/4+1 个 int: 乘法必溢出", + "x": 0.0, + "y": -2.6604, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 4.728, + "h": 0.3264 + }, + "concl:1": { + "kind": "text", + "text": "检查在前——宁可崩, 不带病跑", + "x": 0.0, + "y": -3.2368, + "fs": 0.24, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 4.416, + "h": 0.3264 + } + }, + "steps": [ + { + "kind": "intro", + "label": "开场", + "note": "", + "duration": 5.79, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "title", + "t": 0.0, + "dur": 2.39 + }, + { + "type": "fadein", + "target": "sub", + "t": 2.39, + "dur": 0.5 + }, + { + "type": "fadein", + "target": "counter", + "t": 2.39, + "dur": 0.5 + }, + { + "type": "write", + "target": "_empty", + "t": 3.39, + "dur": 1.07 + }, + { + "type": "fadeout", + "target": "_empty", + "t": 5.49, + "dur": 0.3 + } + ] + }, + { + "kind": "grow_to", + "label": "申请 4", + "note": "capacity 0->4, 搬 0 格", + "duration": 6.15, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "row:row", + "g": { + "kind": "cells", + "cap": 4, + "side": 0.62, + "cx": 4.9, + "cy": -2.1, + "w": 2.66, + "h": 0.62, + "cells": [ + { + "i": 0, + "x": 3.88, + "y": -2.1, + "s": 0.62 + }, + { + "i": 1, + "x": 4.56, + "y": -2.1, + "s": 0.62 + }, + { + "i": 2, + "x": 5.24, + "y": -2.1, + "s": 0.62 + }, + { + "i": 3, + "x": 5.92, + "y": -2.1, + "s": 0.62 + } + ], + "idx": [] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "fadeout", + "target": "_cap_row", + "t": 5.6, + "dur": 0.3 + }, + { + "type": "counter", + "text": "size = 0 capacity = 4", + "t": 5.9, + "dur": 0.25 + } + ] + }, + { + "kind": "push", + "label": "push ×4 (slow)", + "note": "[0,4)", + "duration": 1.2, + "speed": 0.6, + "events": [ + { + "type": "fill", + "target": "row:row", + "i": 0, + "s": 1, + "cap": 4, + "counter": true, + "t": 0.0, + "dur": 0.3 + }, + { + "type": "fill", + "target": "row:row", + "i": 1, + "s": 2, + "cap": 4, + "counter": true, + "t": 0.3, + "dur": 0.3 + }, + { + "type": "fill", + "target": "row:row", + "i": 2, + "s": 3, + "cap": 4, + "counter": true, + "t": 0.6, + "dur": 0.3 + }, + { + "type": "fill", + "target": "row:row", + "i": 3, + "s": 4, + "cap": 4, + "counter": true, + "t": 0.9, + "dur": 0.3 + } + ] + }, + { + "kind": "show", + "label": "show code_req", + "note": "", + "duration": 2.8, + "speed": 1.0, + "events": [ + { + "type": "code_show", + "target": "show:code_req", + "t": 0.0, + "dur": 2.8 + } + ] + }, + { + "kind": "show", + "label": "show code_crash", + "note": "", + "duration": 2.8, + "speed": 1.0, + "events": [ + { + "type": "code_show", + "target": "show:code_crash", + "t": 0.0, + "dur": 2.8 + } + ] + }, + { + "kind": "show", + "label": "show row_note", + "note": "", + "duration": 1.91, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "show:row_note", + "t": 0.0, + "dur": 1.91 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "1.0s", + "duration": 1.0, + "speed": 1.0, + "events": [] + }, + { + "kind": "conclude", + "label": "结论", + "note": "压轴结论墙", + "duration": 11.5, + "speed": 1.0, + "events": [ + { + "type": "fadeout", + "target": "show:code_req", + "t": 0.0, + "dur": 0.3 + }, + { + "type": "fadeout", + "target": "show:code_crash", + "t": 0.3, + "dur": 0.3 + }, + { + "type": "fadeout", + "target": "show:row_note", + "t": 0.6, + "dur": 0.3 + }, + { + "type": "write", + "target": "concl:0", + "t": 0.9, + "dur": 2.4 + }, + { + "type": "write", + "target": "concl:1", + "t": 3.65, + "dur": 2.15 + }, + { + "type": "pulse", + "target": "counter", + "t": 8.5, + "dur": 1.0 + } + ] + } + ] +} diff --git a/site/.vitepress/theme/components/animations/data/opp4-off-by-one.json b/site/.vitepress/theme/components/animations/data/opp4-off-by-one.json new file mode 100644 index 000000000..ea258e937 --- /dev/null +++ b/site/.vitepress/theme/components/animations/data/opp4-off-by-one.json @@ -0,0 +1,689 @@ +{ + "version": 1, + "id": "opp4-off-by-one", + "title": "析构边界:多杀一格是 UB,少杀一格是泄漏", + "subtitle": "为什么笔者每次都掰手指数格子", + "source": "projects/vol8-vector-growth/02-dsl/opp4-off-by-one.yaml", + "backend": "web", + "frame": { + "w": 14.2222, + "h": 8.0 + }, + "palette": { + "bg": "#17171f", + "text": "#ECECE4", + "muted": "#9a9aad", + "fill": "#5EC8E0", + "fillEdge": "#2E86AB", + "emptyEdge": "#4a4a5e", + "grow": "#FFB454", + "numOnFill": "#0e2430", + "ok": "#7BC96A", + "bad": "#E06C75", + "cardBg": "#1e1e2a" + }, + "actors": { + "title": { + "kind": "text", + "text": "析构边界:多杀一格是 UB,少杀一格是泄漏", + "x": 0.0, + "y": 3.4324, + "fs": 0.32, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 8.1984, + "h": 0.4352 + }, + "sub": { + "kind": "text", + "text": "为什么笔者每次都掰手指数格子", + "x": 0.0, + "y": 2.8988, + "fs": 0.2, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 3.696, + "h": 0.272 + }, + "counter": { + "kind": "text", + "text": "size = 0 capacity = 0", + "x": 0.0, + "y": 1.6, + "fs": 0.3, + "color": "#ECECE4", + "mono": true, + "anchor": "middle", + "w": 4.752, + "h": 0.3 + }, + "_empty": { + "kind": "text", + "text": "还没申请内存", + "x": 0.0, + "y": -1.0, + "fs": 0.2, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 1.584, + "h": 0.272 + }, + "_cap_row": { + "kind": "text", + "text": "申请内存: capacity 0 → 4", + "x": 0.0, + "y": 0.1632, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 3.816, + "h": 0.3264 + }, + "row:row": { + "kind": "cells", + "cap": 4, + "side": 0.62, + "cx": 0.0, + "cy": -1.0, + "w": 2.66, + "h": 0.62, + "cells": [ + { + "i": 0, + "x": -1.02, + "y": -1.0, + "s": 0.62 + }, + { + "i": 1, + "x": -0.34, + "y": -1.0, + "s": 0.62 + }, + { + "i": 2, + "x": 0.34, + "y": -1.0, + "s": 0.62 + }, + { + "i": 3, + "x": 1.02, + "y": -1.0, + "s": 0.62 + } + ], + "idx": [ + 1, + 2, + 3, + 4 + ] + }, + "ptr:p_begin": { + "kind": "ptr", + "id": "p_begin", + "name": "begin", + "above": true, + "x": -1.02, + "tipY": -0.45, + "baseY": -0.06, + "txt": { + "text": "begin", + "x": -1.02, + "y": 0.1, + "fs": 0.22, + "color": "#ECECE4", + "mono": true, + "anchor": "middle", + "w": 0.726, + "h": 0.22 + }, + "cx": -1.02, + "cy": -0.12, + "w": 0.726, + "h": 0.66 + }, + "ptr:p_end": { + "kind": "ptr", + "id": "p_end", + "name": "end", + "above": true, + "x": 1.02, + "tipY": -0.45, + "baseY": -0.06, + "txt": { + "text": "end", + "x": 1.02, + "y": 0.1, + "fs": 0.22, + "color": "#ECECE4", + "mono": true, + "anchor": "middle", + "w": 0.4356, + "h": 0.22 + }, + "cx": 1.02, + "cy": -0.12, + "w": 0.4356, + "h": 0.66 + }, + "show:lb_ok": { + "kind": "text", + "text": "该析构的:恰好这三格", + "x": -0.34, + "y": -1.796, + "fs": 0.2, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 2.64, + "h": 0.272, + "id": "lb_ok" + }, + "show:lb_bad": { + "kind": "text", + "text": "多杀一格 = 对未构造内存调析构(UB)", + "x": 1.02, + "y": -1.796, + "fs": 0.2, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 4.58, + "h": 0.272, + "id": "lb_bad" + }, + "show:code": { + "kind": "code", + "fs": 0.2, + "lh": 0.258, + "pitch": 0.478, + "gutW": 0.1056, + "bodyW": 4.62, + "w": 5.5456, + "h": 2.69, + "rows": [ + { + "text": "~Vector() {", + "w": 1.452 + }, + { + "text": " helper::DestroySources(", + "w": 3.3 + }, + { + "text": " buffer_.data(),", + "w": 2.508 + }, + { + "text": " buffer_.data() + current_cnt_);", + "w": 4.62 + }, + { + "text": "}", + "w": 0.132 + } + ], + "cx": 4.2683, + "cy": -0.68 + }, + "concl:0": { + "kind": "text", + "text": "析构区间 = [data, data + current_cnt_)", + "x": 0.0, + "y": -2.084, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 5.7312, + "h": 0.3264 + }, + "concl:1": { + "kind": "text", + "text": "多杀一格 UB,少杀一格泄漏", + "x": 0.0, + "y": -2.6604, + "fs": 0.24, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 3.9312, + "h": 0.3264 + }, + "concl:2": { + "kind": "text", + "text": "内存归还交给 RawBuffer 的 RAII", + "x": 0.0, + "y": -3.2368, + "fs": 0.24, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 4.5984, + "h": 0.3264 + } + }, + "steps": [ + { + "kind": "intro", + "label": "开场", + "note": "", + "duration": 5.8, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "title", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "fadein", + "target": "sub", + "t": 2.4, + "dur": 0.5 + }, + { + "type": "fadein", + "target": "counter", + "t": 2.4, + "dur": 0.5 + }, + { + "type": "write", + "target": "_empty", + "t": 3.4, + "dur": 1.07 + }, + { + "type": "fadeout", + "target": "_empty", + "t": 5.5, + "dur": 0.3 + } + ] + }, + { + "kind": "grow_to", + "label": "申请 4", + "note": "capacity 0->4, 搬 0 格", + "duration": 6.15, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "row:row", + "g": { + "kind": "cells", + "cap": 4, + "side": 0.62, + "cx": 0.0, + "cy": -1.0, + "w": 2.66, + "h": 0.62, + "cells": [ + { + "i": 0, + "x": -1.02, + "y": -1.0, + "s": 0.62 + }, + { + "i": 1, + "x": -0.34, + "y": -1.0, + "s": 0.62 + }, + { + "i": 2, + "x": 0.34, + "y": -1.0, + "s": 0.62 + }, + { + "i": 3, + "x": 1.02, + "y": -1.0, + "s": 0.62 + } + ], + "idx": [ + 1, + 2, + 3, + 4 + ] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "fadeout", + "target": "_cap_row", + "t": 5.6, + "dur": 0.3 + }, + { + "type": "counter", + "text": "size = 0 capacity = 4", + "t": 5.9, + "dur": 0.25 + } + ] + }, + { + "kind": "push", + "label": "push ×3 (slow)", + "note": "[0,3)", + "duration": 0.9, + "speed": 0.6, + "events": [ + { + "type": "fill", + "target": "row:row", + "i": 0, + "s": 1, + "cap": 4, + "counter": true, + "t": 0.0, + "dur": 0.3 + }, + { + "type": "fill", + "target": "row:row", + "i": 1, + "s": 2, + "cap": 4, + "counter": true, + "t": 0.3, + "dur": 0.3 + }, + { + "type": "fill", + "target": "row:row", + "i": 2, + "s": 3, + "cap": 4, + "counter": true, + "t": 0.6, + "dur": 0.3 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "0.3s", + "duration": 0.3, + "speed": 1.0, + "events": [] + }, + { + "kind": "point_to", + "label": "指针 begin 出场", + "note": "index 0", + "duration": 0.4, + "speed": 1.0, + "events": [ + { + "type": "ptr_show", + "target": "p_begin", + "t": 0.0, + "dur": 0.4 + } + ] + }, + { + "kind": "point_to", + "label": "指针 end 出场", + "note": "index 3", + "duration": 0.4, + "speed": 1.0, + "events": [ + { + "type": "ptr_show", + "target": "p_end", + "t": 0.0, + "dur": 0.4 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "0.4s", + "duration": 0.4, + "speed": 1.0, + "events": [] + }, + { + "kind": "highlight", + "label": "高亮 [0,3) green", + "note": "", + "duration": 1.6, + "speed": 1.0, + "events": [ + { + "type": "hl_show", + "frame": { + "kind": "frame", + "color": "#7BC96A", + "cx": -0.34, + "cy": -1.0, + "w": 2.08, + "h": 0.72 + }, + "t": 0.0, + "dur": 0.4 + }, + { + "type": "hl_hide", + "frame": { + "kind": "frame", + "color": "#7BC96A", + "cx": -0.34, + "cy": -1.0, + "w": 2.08, + "h": 0.72 + }, + "t": 1.3, + "dur": 0.3 + } + ] + }, + { + "kind": "show", + "label": "show lb_ok", + "note": "", + "duration": 1.55, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "show:lb_ok", + "t": 0.0, + "dur": 1.55 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "1.0s", + "duration": 1.0, + "speed": 1.0, + "events": [] + }, + { + "kind": "hide", + "label": "hide lb_ok", + "note": "", + "duration": 0.95, + "speed": 1.0, + "events": [ + { + "type": "fadeout", + "target": "show:lb_ok", + "t": 0.55, + "dur": 0.4 + } + ] + }, + { + "kind": "highlight", + "label": "高亮 [3,4) red", + "note": "", + "duration": 1.6, + "speed": 1.0, + "events": [ + { + "type": "hl_show", + "frame": { + "kind": "frame", + "color": "#E06C75", + "cx": 1.02, + "cy": -1.0, + "w": 0.72, + "h": 0.72 + }, + "t": 0.0, + "dur": 0.4 + }, + { + "type": "hl_hide", + "frame": { + "kind": "frame", + "color": "#E06C75", + "cx": 1.02, + "cy": -1.0, + "w": 0.72, + "h": 0.72 + }, + "t": 1.3, + "dur": 0.3 + } + ] + }, + { + "kind": "show", + "label": "show lb_bad", + "note": "", + "duration": 2.4, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "show:lb_bad", + "t": 0.0, + "dur": 2.4 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "1.0s", + "duration": 1.0, + "speed": 1.0, + "events": [] + }, + { + "kind": "hide", + "label": "hide lb_bad", + "note": "", + "duration": 2.6, + "speed": 1.0, + "events": [ + { + "type": "fadeout", + "target": "show:lb_bad", + "t": 2.2, + "dur": 0.4 + } + ] + }, + { + "kind": "show", + "label": "show code", + "note": "", + "duration": 2.8, + "speed": 1.0, + "events": [ + { + "type": "code_show", + "target": "show:code", + "t": 0.0, + "dur": 2.8 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "1.2s", + "duration": 1.2, + "speed": 1.0, + "events": [] + }, + { + "kind": "hide", + "label": "hide code", + "note": "", + "duration": 0.75, + "speed": 1.0, + "events": [ + { + "type": "fadeout", + "target": "show:code", + "t": 0.35, + "dur": 0.4 + } + ] + }, + { + "kind": "conclude", + "label": "结论", + "note": "压轴结论墙", + "duration": 14.98, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "concl:0", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "write", + "target": "concl:1", + "t": 2.75, + "dur": 2.03 + }, + { + "type": "write", + "target": "concl:2", + "t": 5.13, + "dur": 2.4 + }, + { + "type": "pulse", + "target": "counter", + "t": 11.98, + "dur": 1.0 + } + ] + } + ] +} diff --git a/site/.vitepress/theme/components/animations/data/opp5-cost-ledger.json b/site/.vitepress/theme/components/animations/data/opp5-cost-ledger.json new file mode 100644 index 000000000..0f07cb023 --- /dev/null +++ b/site/.vitepress/theme/components/animations/data/opp5-cost-ledger.json @@ -0,0 +1,3095 @@ +{ + "version": 1, + "id": "opp5-cost-ledger", + "title": "摊还账本:40 次 push,总搬迁 60 格", + "subtitle": "搬迁总和 < 2 × push 次数,所以摊还 O(1)", + "source": "projects/vol8-vector-growth/02-dsl/opp5-cost-ledger.yaml", + "backend": "web", + "frame": { + "w": 14.2222, + "h": 8.0 + }, + "palette": { + "bg": "#17171f", + "text": "#ECECE4", + "muted": "#9a9aad", + "fill": "#5EC8E0", + "fillEdge": "#2E86AB", + "emptyEdge": "#4a4a5e", + "grow": "#FFB454", + "numOnFill": "#0e2430", + "ok": "#7BC96A", + "bad": "#E06C75", + "cardBg": "#1e1e2a" + }, + "actors": { + "title": { + "kind": "text", + "text": "摊还账本:40 次 push,总搬迁 60 格", + "x": 0.0, + "y": 3.4324, + "fs": 0.32, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 7.0272, + "h": 0.4352 + }, + "sub": { + "kind": "text", + "text": "搬迁总和 < 2 × push 次数,所以摊还 O(1)", + "x": 0.0, + "y": 2.8988, + "fs": 0.2, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 5.012, + "h": 0.272 + }, + "counter": { + "kind": "text", + "text": "size = 0 capacity = 0", + "x": 0.0, + "y": 1.6, + "fs": 0.3, + "color": "#ECECE4", + "mono": true, + "anchor": "middle", + "w": 5.148, + "h": 0.3 + }, + "_empty": { + "kind": "text", + "text": "还没申请内存", + "x": 0.0, + "y": -1.0, + "fs": 0.2, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 1.584, + "h": 0.272 + }, + "_cap_row": { + "kind": "text", + "text": "申请内存: capacity 0 → 4", + "x": 0.0, + "y": 0.1632, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 3.816, + "h": 0.3264 + }, + "row:row": { + "kind": "cells", + "cap": 64, + "side": 0.22, + "cx": 0.0, + "cy": -1.0, + "w": 4.42, + "h": 1.06, + "cells": [ + { + "i": 0, + "x": -2.1, + "y": -0.58, + "s": 0.22 + }, + { + "i": 1, + "x": -1.82, + "y": -0.58, + "s": 0.22 + }, + { + "i": 2, + "x": -1.54, + "y": -0.58, + "s": 0.22 + }, + { + "i": 3, + "x": -1.26, + "y": -0.58, + "s": 0.22 + }, + { + "i": 4, + "x": -0.98, + "y": -0.58, + "s": 0.22 + }, + { + "i": 5, + "x": -0.7, + "y": -0.58, + "s": 0.22 + }, + { + "i": 6, + "x": -0.42, + "y": -0.58, + "s": 0.22 + }, + { + "i": 7, + "x": -0.14, + "y": -0.58, + "s": 0.22 + }, + { + "i": 8, + "x": 0.14, + "y": -0.58, + "s": 0.22 + }, + { + "i": 9, + "x": 0.42, + "y": -0.58, + "s": 0.22 + }, + { + "i": 10, + "x": 0.7, + "y": -0.58, + "s": 0.22 + }, + { + "i": 11, + "x": 0.98, + "y": -0.58, + "s": 0.22 + }, + { + "i": 12, + "x": 1.26, + "y": -0.58, + "s": 0.22 + }, + { + "i": 13, + "x": 1.54, + "y": -0.58, + "s": 0.22 + }, + { + "i": 14, + "x": 1.82, + "y": -0.58, + "s": 0.22 + }, + { + "i": 15, + "x": 2.1, + "y": -0.58, + "s": 0.22 + }, + { + "i": 16, + "x": -2.1, + "y": -0.86, + "s": 0.22 + }, + { + "i": 17, + "x": -1.82, + "y": -0.86, + "s": 0.22 + }, + { + "i": 18, + "x": -1.54, + "y": -0.86, + "s": 0.22 + }, + { + "i": 19, + "x": -1.26, + "y": -0.86, + "s": 0.22 + }, + { + "i": 20, + "x": -0.98, + "y": -0.86, + "s": 0.22 + }, + { + "i": 21, + "x": -0.7, + "y": -0.86, + "s": 0.22 + }, + { + "i": 22, + "x": -0.42, + "y": -0.86, + "s": 0.22 + }, + { + "i": 23, + "x": -0.14, + "y": -0.86, + "s": 0.22 + }, + { + "i": 24, + "x": 0.14, + "y": -0.86, + "s": 0.22 + }, + { + "i": 25, + "x": 0.42, + "y": -0.86, + "s": 0.22 + }, + { + "i": 26, + "x": 0.7, + "y": -0.86, + "s": 0.22 + }, + { + "i": 27, + "x": 0.98, + "y": -0.86, + "s": 0.22 + }, + { + "i": 28, + "x": 1.26, + "y": -0.86, + "s": 0.22 + }, + { + "i": 29, + "x": 1.54, + "y": -0.86, + "s": 0.22 + }, + { + "i": 30, + "x": 1.82, + "y": -0.86, + "s": 0.22 + }, + { + "i": 31, + "x": 2.1, + "y": -0.86, + "s": 0.22 + }, + { + "i": 32, + "x": -2.1, + "y": -1.14, + "s": 0.22 + }, + { + "i": 33, + "x": -1.82, + "y": -1.14, + "s": 0.22 + }, + { + "i": 34, + "x": -1.54, + "y": -1.14, + "s": 0.22 + }, + { + "i": 35, + "x": -1.26, + "y": -1.14, + "s": 0.22 + }, + { + "i": 36, + "x": -0.98, + "y": -1.14, + "s": 0.22 + }, + { + "i": 37, + "x": -0.7, + "y": -1.14, + "s": 0.22 + }, + { + "i": 38, + "x": -0.42, + "y": -1.14, + "s": 0.22 + }, + { + "i": 39, + "x": -0.14, + "y": -1.14, + "s": 0.22 + }, + { + "i": 40, + "x": 0.14, + "y": -1.14, + "s": 0.22 + }, + { + "i": 41, + "x": 0.42, + "y": -1.14, + "s": 0.22 + }, + { + "i": 42, + "x": 0.7, + "y": -1.14, + "s": 0.22 + }, + { + "i": 43, + "x": 0.98, + "y": -1.14, + "s": 0.22 + }, + { + "i": 44, + "x": 1.26, + "y": -1.14, + "s": 0.22 + }, + { + "i": 45, + "x": 1.54, + "y": -1.14, + "s": 0.22 + }, + { + "i": 46, + "x": 1.82, + "y": -1.14, + "s": 0.22 + }, + { + "i": 47, + "x": 2.1, + "y": -1.14, + "s": 0.22 + }, + { + "i": 48, + "x": -2.1, + "y": -1.42, + "s": 0.22 + }, + { + "i": 49, + "x": -1.82, + "y": -1.42, + "s": 0.22 + }, + { + "i": 50, + "x": -1.54, + "y": -1.42, + "s": 0.22 + }, + { + "i": 51, + "x": -1.26, + "y": -1.42, + "s": 0.22 + }, + { + "i": 52, + "x": -0.98, + "y": -1.42, + "s": 0.22 + }, + { + "i": 53, + "x": -0.7, + "y": -1.42, + "s": 0.22 + }, + { + "i": 54, + "x": -0.42, + "y": -1.42, + "s": 0.22 + }, + { + "i": 55, + "x": -0.14, + "y": -1.42, + "s": 0.22 + }, + { + "i": 56, + "x": 0.14, + "y": -1.42, + "s": 0.22 + }, + { + "i": 57, + "x": 0.42, + "y": -1.42, + "s": 0.22 + }, + { + "i": 58, + "x": 0.7, + "y": -1.42, + "s": 0.22 + }, + { + "i": 59, + "x": 0.98, + "y": -1.42, + "s": 0.22 + }, + { + "i": 60, + "x": 1.26, + "y": -1.42, + "s": 0.22 + }, + { + "i": 61, + "x": 1.54, + "y": -1.42, + "s": 0.22 + }, + { + "i": 62, + "x": 1.82, + "y": -1.42, + "s": 0.22 + }, + { + "i": 63, + "x": 2.1, + "y": -1.42, + "s": 0.22 + } + ], + "idx": [] + }, + "_cap_row_4": { + "kind": "text", + "text": "满了!capacity 4 → 8,grow_to!", + "x": 0.0, + "y": -2.1732, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 4.8768, + "h": 0.3264 + }, + "_grow4:row": { + "kind": "cells", + "cap": 8, + "side": 0.5, + "cx": 0.0, + "cy": -3.51, + "w": 4.42, + "h": 0.5, + "cells": [ + { + "i": 0, + "x": -1.96, + "y": -3.51, + "s": 0.5 + }, + { + "i": 1, + "x": -1.4, + "y": -3.51, + "s": 0.5 + }, + { + "i": 2, + "x": -0.84, + "y": -3.51, + "s": 0.5 + }, + { + "i": 3, + "x": -0.28, + "y": -3.51, + "s": 0.5 + }, + { + "i": 4, + "x": 0.28, + "y": -3.51, + "s": 0.5 + }, + { + "i": 5, + "x": 0.84, + "y": -3.51, + "s": 0.5 + }, + { + "i": 6, + "x": 1.4, + "y": -3.51, + "s": 0.5 + }, + { + "i": 7, + "x": 1.96, + "y": -3.51, + "s": 0.5 + } + ], + "idx": [] + }, + "_raii_row_4": { + "kind": "text", + "text": "旧对象已逐个析构, 内存 RAII 归还", + "x": 0.0, + "y": -0.3176, + "fs": 0.18, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 3.744, + "h": 0.2448 + }, + "_cap_row_8": { + "kind": "text", + "text": "满了!capacity 8 → 16,grow_to!", + "x": 0.0, + "y": -2.1132, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 5.0256, + "h": 0.3264 + }, + "_grow8:row": { + "kind": "cells", + "cap": 16, + "side": 0.4, + "cx": 0.0, + "cy": -3.45, + "w": 7.3, + "h": 0.4, + "cells": [ + { + "i": 0, + "x": -3.45, + "y": -3.45, + "s": 0.4 + }, + { + "i": 1, + "x": -2.99, + "y": -3.45, + "s": 0.4 + }, + { + "i": 2, + "x": -2.53, + "y": -3.45, + "s": 0.4 + }, + { + "i": 3, + "x": -2.07, + "y": -3.45, + "s": 0.4 + }, + { + "i": 4, + "x": -1.61, + "y": -3.45, + "s": 0.4 + }, + { + "i": 5, + "x": -1.15, + "y": -3.45, + "s": 0.4 + }, + { + "i": 6, + "x": -0.69, + "y": -3.45, + "s": 0.4 + }, + { + "i": 7, + "x": -0.23, + "y": -3.45, + "s": 0.4 + }, + { + "i": 8, + "x": 0.23, + "y": -3.45, + "s": 0.4 + }, + { + "i": 9, + "x": 0.69, + "y": -3.45, + "s": 0.4 + }, + { + "i": 10, + "x": 1.15, + "y": -3.45, + "s": 0.4 + }, + { + "i": 11, + "x": 1.61, + "y": -3.45, + "s": 0.4 + }, + { + "i": 12, + "x": 2.07, + "y": -3.45, + "s": 0.4 + }, + { + "i": 13, + "x": 2.53, + "y": -3.45, + "s": 0.4 + }, + { + "i": 14, + "x": 2.99, + "y": -3.45, + "s": 0.4 + }, + { + "i": 15, + "x": 3.45, + "y": -3.45, + "s": 0.4 + } + ], + "idx": [] + }, + "_raii_row_8": { + "kind": "text", + "text": "旧对象已逐个析构, 内存 RAII 归还", + "x": 0.0, + "y": -0.3776, + "fs": 0.18, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 3.744, + "h": 0.2448 + }, + "_cap_row_16": { + "kind": "text", + "text": "满了!capacity 16 → 32,grow_to!", + "x": 0.0, + "y": -2.0632, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 5.1744, + "h": 0.3264 + }, + "_grow16:row": { + "kind": "cells", + "cap": 32, + "side": 0.3, + "cx": 0.0, + "cy": -3.4, + "w": 5.7, + "h": 0.66, + "cells": [ + { + "i": 0, + "x": -2.7, + "y": -3.22, + "s": 0.3 + }, + { + "i": 1, + "x": -2.34, + "y": -3.22, + "s": 0.3 + }, + { + "i": 2, + "x": -1.98, + "y": -3.22, + "s": 0.3 + }, + { + "i": 3, + "x": -1.62, + "y": -3.22, + "s": 0.3 + }, + { + "i": 4, + "x": -1.26, + "y": -3.22, + "s": 0.3 + }, + { + "i": 5, + "x": -0.9, + "y": -3.22, + "s": 0.3 + }, + { + "i": 6, + "x": -0.54, + "y": -3.22, + "s": 0.3 + }, + { + "i": 7, + "x": -0.18, + "y": -3.22, + "s": 0.3 + }, + { + "i": 8, + "x": 0.18, + "y": -3.22, + "s": 0.3 + }, + { + "i": 9, + "x": 0.54, + "y": -3.22, + "s": 0.3 + }, + { + "i": 10, + "x": 0.9, + "y": -3.22, + "s": 0.3 + }, + { + "i": 11, + "x": 1.26, + "y": -3.22, + "s": 0.3 + }, + { + "i": 12, + "x": 1.62, + "y": -3.22, + "s": 0.3 + }, + { + "i": 13, + "x": 1.98, + "y": -3.22, + "s": 0.3 + }, + { + "i": 14, + "x": 2.34, + "y": -3.22, + "s": 0.3 + }, + { + "i": 15, + "x": 2.7, + "y": -3.22, + "s": 0.3 + }, + { + "i": 16, + "x": -2.7, + "y": -3.58, + "s": 0.3 + }, + { + "i": 17, + "x": -2.34, + "y": -3.58, + "s": 0.3 + }, + { + "i": 18, + "x": -1.98, + "y": -3.58, + "s": 0.3 + }, + { + "i": 19, + "x": -1.62, + "y": -3.58, + "s": 0.3 + }, + { + "i": 20, + "x": -1.26, + "y": -3.58, + "s": 0.3 + }, + { + "i": 21, + "x": -0.9, + "y": -3.58, + "s": 0.3 + }, + { + "i": 22, + "x": -0.54, + "y": -3.58, + "s": 0.3 + }, + { + "i": 23, + "x": -0.18, + "y": -3.58, + "s": 0.3 + }, + { + "i": 24, + "x": 0.18, + "y": -3.58, + "s": 0.3 + }, + { + "i": 25, + "x": 0.54, + "y": -3.58, + "s": 0.3 + }, + { + "i": 26, + "x": 0.9, + "y": -3.58, + "s": 0.3 + }, + { + "i": 27, + "x": 1.26, + "y": -3.58, + "s": 0.3 + }, + { + "i": 28, + "x": 1.62, + "y": -3.58, + "s": 0.3 + }, + { + "i": 29, + "x": 1.98, + "y": -3.58, + "s": 0.3 + }, + { + "i": 30, + "x": 2.34, + "y": -3.58, + "s": 0.3 + }, + { + "i": 31, + "x": 2.7, + "y": -3.58, + "s": 0.3 + } + ], + "idx": [] + }, + "_raii_row_16": { + "kind": "text", + "text": "旧对象已逐个析构, 内存 RAII 归还", + "x": 0.0, + "y": -0.4276, + "fs": 0.18, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 3.744, + "h": 0.2448 + }, + "_cap_row_32": { + "kind": "text", + "text": "满了!capacity 32 → 64,grow_to!", + "x": 0.0, + "y": -2.1932, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 5.1744, + "h": 0.3264 + }, + "_grow32:row": { + "kind": "cells", + "cap": 64, + "side": 0.22, + "cx": 0.0, + "cy": -3.53, + "w": 4.42, + "h": 1.06, + "cells": [ + { + "i": 0, + "x": -2.1, + "y": -3.11, + "s": 0.22 + }, + { + "i": 1, + "x": -1.82, + "y": -3.11, + "s": 0.22 + }, + { + "i": 2, + "x": -1.54, + "y": -3.11, + "s": 0.22 + }, + { + "i": 3, + "x": -1.26, + "y": -3.11, + "s": 0.22 + }, + { + "i": 4, + "x": -0.98, + "y": -3.11, + "s": 0.22 + }, + { + "i": 5, + "x": -0.7, + "y": -3.11, + "s": 0.22 + }, + { + "i": 6, + "x": -0.42, + "y": -3.11, + "s": 0.22 + }, + { + "i": 7, + "x": -0.14, + "y": -3.11, + "s": 0.22 + }, + { + "i": 8, + "x": 0.14, + "y": -3.11, + "s": 0.22 + }, + { + "i": 9, + "x": 0.42, + "y": -3.11, + "s": 0.22 + }, + { + "i": 10, + "x": 0.7, + "y": -3.11, + "s": 0.22 + }, + { + "i": 11, + "x": 0.98, + "y": -3.11, + "s": 0.22 + }, + { + "i": 12, + "x": 1.26, + "y": -3.11, + "s": 0.22 + }, + { + "i": 13, + "x": 1.54, + "y": -3.11, + "s": 0.22 + }, + { + "i": 14, + "x": 1.82, + "y": -3.11, + "s": 0.22 + }, + { + "i": 15, + "x": 2.1, + "y": -3.11, + "s": 0.22 + }, + { + "i": 16, + "x": -2.1, + "y": -3.39, + "s": 0.22 + }, + { + "i": 17, + "x": -1.82, + "y": -3.39, + "s": 0.22 + }, + { + "i": 18, + "x": -1.54, + "y": -3.39, + "s": 0.22 + }, + { + "i": 19, + "x": -1.26, + "y": -3.39, + "s": 0.22 + }, + { + "i": 20, + "x": -0.98, + "y": -3.39, + "s": 0.22 + }, + { + "i": 21, + "x": -0.7, + "y": -3.39, + "s": 0.22 + }, + { + "i": 22, + "x": -0.42, + "y": -3.39, + "s": 0.22 + }, + { + "i": 23, + "x": -0.14, + "y": -3.39, + "s": 0.22 + }, + { + "i": 24, + "x": 0.14, + "y": -3.39, + "s": 0.22 + }, + { + "i": 25, + "x": 0.42, + "y": -3.39, + "s": 0.22 + }, + { + "i": 26, + "x": 0.7, + "y": -3.39, + "s": 0.22 + }, + { + "i": 27, + "x": 0.98, + "y": -3.39, + "s": 0.22 + }, + { + "i": 28, + "x": 1.26, + "y": -3.39, + "s": 0.22 + }, + { + "i": 29, + "x": 1.54, + "y": -3.39, + "s": 0.22 + }, + { + "i": 30, + "x": 1.82, + "y": -3.39, + "s": 0.22 + }, + { + "i": 31, + "x": 2.1, + "y": -3.39, + "s": 0.22 + }, + { + "i": 32, + "x": -2.1, + "y": -3.67, + "s": 0.22 + }, + { + "i": 33, + "x": -1.82, + "y": -3.67, + "s": 0.22 + }, + { + "i": 34, + "x": -1.54, + "y": -3.67, + "s": 0.22 + }, + { + "i": 35, + "x": -1.26, + "y": -3.67, + "s": 0.22 + }, + { + "i": 36, + "x": -0.98, + "y": -3.67, + "s": 0.22 + }, + { + "i": 37, + "x": -0.7, + "y": -3.67, + "s": 0.22 + }, + { + "i": 38, + "x": -0.42, + "y": -3.67, + "s": 0.22 + }, + { + "i": 39, + "x": -0.14, + "y": -3.67, + "s": 0.22 + }, + { + "i": 40, + "x": 0.14, + "y": -3.67, + "s": 0.22 + }, + { + "i": 41, + "x": 0.42, + "y": -3.67, + "s": 0.22 + }, + { + "i": 42, + "x": 0.7, + "y": -3.67, + "s": 0.22 + }, + { + "i": 43, + "x": 0.98, + "y": -3.67, + "s": 0.22 + }, + { + "i": 44, + "x": 1.26, + "y": -3.67, + "s": 0.22 + }, + { + "i": 45, + "x": 1.54, + "y": -3.67, + "s": 0.22 + }, + { + "i": 46, + "x": 1.82, + "y": -3.67, + "s": 0.22 + }, + { + "i": 47, + "x": 2.1, + "y": -3.67, + "s": 0.22 + }, + { + "i": 48, + "x": -2.1, + "y": -3.95, + "s": 0.22 + }, + { + "i": 49, + "x": -1.82, + "y": -3.95, + "s": 0.22 + }, + { + "i": 50, + "x": -1.54, + "y": -3.95, + "s": 0.22 + }, + { + "i": 51, + "x": -1.26, + "y": -3.95, + "s": 0.22 + }, + { + "i": 52, + "x": -0.98, + "y": -3.95, + "s": 0.22 + }, + { + "i": 53, + "x": -0.7, + "y": -3.95, + "s": 0.22 + }, + { + "i": 54, + "x": -0.42, + "y": -3.95, + "s": 0.22 + }, + { + "i": 55, + "x": -0.14, + "y": -3.95, + "s": 0.22 + }, + { + "i": 56, + "x": 0.14, + "y": -3.95, + "s": 0.22 + }, + { + "i": 57, + "x": 0.42, + "y": -3.95, + "s": 0.22 + }, + { + "i": 58, + "x": 0.7, + "y": -3.95, + "s": 0.22 + }, + { + "i": 59, + "x": 0.98, + "y": -3.95, + "s": 0.22 + }, + { + "i": 60, + "x": 1.26, + "y": -3.95, + "s": 0.22 + }, + { + "i": 61, + "x": 1.54, + "y": -3.95, + "s": 0.22 + }, + { + "i": 62, + "x": 1.82, + "y": -3.95, + "s": 0.22 + }, + { + "i": 63, + "x": 2.1, + "y": -3.95, + "s": 0.22 + } + ], + "idx": [] + }, + "_raii_row_32": { + "kind": "text", + "text": "旧对象已逐个析构, 内存 RAII 归还", + "x": 0.0, + "y": -0.2976, + "fs": 0.18, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 3.744, + "h": 0.2448 + }, + "show:lb_note": { + "kind": "text", + "text": "翻倍扩容 → 账本对比", + "x": 5.0, + "y": 2.3, + "fs": 0.2, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 2.624, + "h": 0.272, + "id": "lb_note" + }, + "show:bars": { + "kind": "bars", + "w": 2.5, + "h": 2.4944, + "cols": [ + { + "label": "push 次数", + "value": 40, + "h": 1.0667 + }, + { + "label": "搬迁格数", + "value": 60, + "h": 1.6 + } + ], + "colW": 0.9, + "pitch": 1.6, + "cx": 0, + "cy": -2.95 + }, + "concl:0": { + "kind": "text", + "text": "40 次 push,总搬迁 4+8+16+32 = 60", + "x": 0.0, + "y": -2.084, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 5.0064, + "h": 0.3264 + }, + "concl:1": { + "kind": "text", + "text": "搬迁总和 < 2 × push 次数 → 线性", + "x": 0.0, + "y": -2.6604, + "fs": 0.24, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 4.9344, + "h": 0.3264 + }, + "concl:2": { + "kind": "text", + "text": "所以 push_back 摊还 O(1)", + "x": 0.0, + "y": -3.2368, + "fs": 0.24, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 3.648, + "h": 0.3264 + } + }, + "steps": [ + { + "kind": "intro", + "label": "开场", + "note": "", + "duration": 5.8, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "title", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "fadein", + "target": "sub", + "t": 2.4, + "dur": 0.5 + }, + { + "type": "fadein", + "target": "counter", + "t": 2.4, + "dur": 0.5 + }, + { + "type": "write", + "target": "_empty", + "t": 3.4, + "dur": 1.07 + }, + { + "type": "fadeout", + "target": "_empty", + "t": 5.5, + "dur": 0.3 + } + ] + }, + { + "kind": "grow_to", + "label": "申请 4", + "note": "capacity 0->4, 搬 0 格", + "duration": 6.15, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "row:row", + "g": { + "kind": "cells", + "cap": 4, + "side": 0.62, + "cx": 0.0, + "cy": -1.0, + "w": 2.66, + "h": 0.62, + "cells": [ + { + "i": 0, + "x": -1.02, + "y": -1.0, + "s": 0.62 + }, + { + "i": 1, + "x": -0.34, + "y": -1.0, + "s": 0.62 + }, + { + "i": 2, + "x": 0.34, + "y": -1.0, + "s": 0.62 + }, + { + "i": 3, + "x": 1.02, + "y": -1.0, + "s": 0.62 + } + ], + "idx": [] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "fadeout", + "target": "_cap_row", + "t": 5.6, + "dur": 0.3 + }, + { + "type": "counter", + "text": "size = 0 capacity = 4", + "t": 5.9, + "dur": 0.25 + } + ] + }, + { + "kind": "push", + "label": "push ×4 (slow)", + "note": "[0,4)", + "duration": 1.2, + "speed": 0.6, + "events": [ + { + "type": "fill", + "target": "row:row", + "i": 0, + "s": 1, + "cap": 4, + "counter": true, + "t": 0.0, + "dur": 0.3 + }, + { + "type": "fill", + "target": "row:row", + "i": 1, + "s": 2, + "cap": 4, + "counter": true, + "t": 0.3, + "dur": 0.3 + }, + { + "type": "fill", + "target": "row:row", + "i": 2, + "s": 3, + "cap": 4, + "counter": true, + "t": 0.6, + "dur": 0.3 + }, + { + "type": "fill", + "target": "row:row", + "i": 3, + "s": 4, + "cap": 4, + "counter": true, + "t": 0.9, + "dur": 0.3 + } + ] + }, + { + "kind": "grow_to", + "label": "扩容 4→8", + "note": "capacity 4->8, 搬 4 格", + "duration": 11.05, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row_4", + "indicate": "row:row", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "_grow4:row", + "g": { + "kind": "cells", + "cap": 8, + "side": 0.5, + "cx": 0.0, + "cy": -3.51, + "w": 4.42, + "h": 0.5, + "cells": [ + { + "i": 0, + "x": -1.96, + "y": -3.51, + "s": 0.5 + }, + { + "i": 1, + "x": -1.4, + "y": -3.51, + "s": 0.5 + }, + { + "i": 2, + "x": -0.84, + "y": -3.51, + "s": 0.5 + }, + { + "i": 3, + "x": -0.28, + "y": -3.51, + "s": 0.5 + }, + { + "i": 4, + "x": 0.28, + "y": -3.51, + "s": 0.5 + }, + { + "i": 5, + "x": 0.84, + "y": -3.51, + "s": 0.5 + }, + { + "i": 6, + "x": 1.4, + "y": -3.51, + "s": 0.5 + }, + { + "i": 7, + "x": 1.96, + "y": -3.51, + "s": 0.5 + } + ], + "idx": [] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "relocate", + "src": "row:row", + "dst": "_grow4:row", + "count": 4, + "t": 3.1, + "dur": 1.0 + }, + { + "type": "row_destroy", + "target": "row:row", + "write": "_raii_row_4", + "t": 4.1, + "dur": 2.4 + }, + { + "type": "fadeout", + "target": "_cap_row_4", + "t": 9.7, + "dur": 0.3 + }, + { + "type": "fadeout", + "target": "_raii_row_4", + "t": 10.0, + "dur": 0.3 + }, + { + "type": "row_swap", + "target": "row:row", + "tmp": "_grow4:row", + "to": [ + 0.0, + -1.0 + ], + "t": 10.3, + "dur": 0.5 + }, + { + "type": "counter", + "text": "size = 4 capacity = 8", + "t": 10.8, + "dur": 0.25 + } + ] + }, + { + "kind": "push", + "label": "push ×4 (fast)", + "note": "[4,8)", + "duration": 0.4, + "speed": 1.8, + "events": [ + { + "type": "fill", + "target": "row:row", + "i": 4, + "s": 5, + "cap": 8, + "counter": true, + "t": 0.0, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 5, + "s": 6, + "cap": 8, + "counter": true, + "t": 0.1, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 6, + "s": 7, + "cap": 8, + "counter": true, + "t": 0.2, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 7, + "s": 8, + "cap": 8, + "counter": true, + "t": 0.3, + "dur": 0.1 + } + ] + }, + { + "kind": "grow_to", + "label": "扩容 8→16", + "note": "capacity 8->16, 搬 8 格", + "duration": 11.05, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row_8", + "indicate": "row:row", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "_grow8:row", + "g": { + "kind": "cells", + "cap": 16, + "side": 0.4, + "cx": 0.0, + "cy": -3.45, + "w": 7.3, + "h": 0.4, + "cells": [ + { + "i": 0, + "x": -3.45, + "y": -3.45, + "s": 0.4 + }, + { + "i": 1, + "x": -2.99, + "y": -3.45, + "s": 0.4 + }, + { + "i": 2, + "x": -2.53, + "y": -3.45, + "s": 0.4 + }, + { + "i": 3, + "x": -2.07, + "y": -3.45, + "s": 0.4 + }, + { + "i": 4, + "x": -1.61, + "y": -3.45, + "s": 0.4 + }, + { + "i": 5, + "x": -1.15, + "y": -3.45, + "s": 0.4 + }, + { + "i": 6, + "x": -0.69, + "y": -3.45, + "s": 0.4 + }, + { + "i": 7, + "x": -0.23, + "y": -3.45, + "s": 0.4 + }, + { + "i": 8, + "x": 0.23, + "y": -3.45, + "s": 0.4 + }, + { + "i": 9, + "x": 0.69, + "y": -3.45, + "s": 0.4 + }, + { + "i": 10, + "x": 1.15, + "y": -3.45, + "s": 0.4 + }, + { + "i": 11, + "x": 1.61, + "y": -3.45, + "s": 0.4 + }, + { + "i": 12, + "x": 2.07, + "y": -3.45, + "s": 0.4 + }, + { + "i": 13, + "x": 2.53, + "y": -3.45, + "s": 0.4 + }, + { + "i": 14, + "x": 2.99, + "y": -3.45, + "s": 0.4 + }, + { + "i": 15, + "x": 3.45, + "y": -3.45, + "s": 0.4 + } + ], + "idx": [] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "relocate", + "src": "row:row", + "dst": "_grow8:row", + "count": 8, + "t": 3.1, + "dur": 1.0 + }, + { + "type": "row_destroy", + "target": "row:row", + "write": "_raii_row_8", + "t": 4.1, + "dur": 2.4 + }, + { + "type": "fadeout", + "target": "_cap_row_8", + "t": 9.7, + "dur": 0.3 + }, + { + "type": "fadeout", + "target": "_raii_row_8", + "t": 10.0, + "dur": 0.3 + }, + { + "type": "row_swap", + "target": "row:row", + "tmp": "_grow8:row", + "to": [ + 0.0, + -1.0 + ], + "t": 10.3, + "dur": 0.5 + }, + { + "type": "counter", + "text": "size = 8 capacity = 16", + "t": 10.8, + "dur": 0.25 + } + ] + }, + { + "kind": "push", + "label": "push ×8 (fast)", + "note": "[8,16)", + "duration": 0.8, + "speed": 1.8, + "events": [ + { + "type": "fill", + "target": "row:row", + "i": 8, + "s": 9, + "cap": 16, + "counter": true, + "t": 0.0, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 9, + "s": 10, + "cap": 16, + "counter": true, + "t": 0.1, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 10, + "s": 11, + "cap": 16, + "counter": true, + "t": 0.2, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 11, + "s": 12, + "cap": 16, + "counter": true, + "t": 0.3, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 12, + "s": 13, + "cap": 16, + "counter": true, + "t": 0.4, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 13, + "s": 14, + "cap": 16, + "counter": true, + "t": 0.5, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 14, + "s": 15, + "cap": 16, + "counter": true, + "t": 0.6, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 15, + "s": 16, + "cap": 16, + "counter": true, + "t": 0.7, + "dur": 0.1 + } + ] + }, + { + "kind": "grow_to", + "label": "扩容 16→32", + "note": "capacity 16->32, 搬 16 格", + "duration": 11.05, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row_16", + "indicate": "row:row", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "_grow16:row", + "g": { + "kind": "cells", + "cap": 32, + "side": 0.3, + "cx": 0.0, + "cy": -3.4, + "w": 5.7, + "h": 0.66, + "cells": [ + { + "i": 0, + "x": -2.7, + "y": -3.22, + "s": 0.3 + }, + { + "i": 1, + "x": -2.34, + "y": -3.22, + "s": 0.3 + }, + { + "i": 2, + "x": -1.98, + "y": -3.22, + "s": 0.3 + }, + { + "i": 3, + "x": -1.62, + "y": -3.22, + "s": 0.3 + }, + { + "i": 4, + "x": -1.26, + "y": -3.22, + "s": 0.3 + }, + { + "i": 5, + "x": -0.9, + "y": -3.22, + "s": 0.3 + }, + { + "i": 6, + "x": -0.54, + "y": -3.22, + "s": 0.3 + }, + { + "i": 7, + "x": -0.18, + "y": -3.22, + "s": 0.3 + }, + { + "i": 8, + "x": 0.18, + "y": -3.22, + "s": 0.3 + }, + { + "i": 9, + "x": 0.54, + "y": -3.22, + "s": 0.3 + }, + { + "i": 10, + "x": 0.9, + "y": -3.22, + "s": 0.3 + }, + { + "i": 11, + "x": 1.26, + "y": -3.22, + "s": 0.3 + }, + { + "i": 12, + "x": 1.62, + "y": -3.22, + "s": 0.3 + }, + { + "i": 13, + "x": 1.98, + "y": -3.22, + "s": 0.3 + }, + { + "i": 14, + "x": 2.34, + "y": -3.22, + "s": 0.3 + }, + { + "i": 15, + "x": 2.7, + "y": -3.22, + "s": 0.3 + }, + { + "i": 16, + "x": -2.7, + "y": -3.58, + "s": 0.3 + }, + { + "i": 17, + "x": -2.34, + "y": -3.58, + "s": 0.3 + }, + { + "i": 18, + "x": -1.98, + "y": -3.58, + "s": 0.3 + }, + { + "i": 19, + "x": -1.62, + "y": -3.58, + "s": 0.3 + }, + { + "i": 20, + "x": -1.26, + "y": -3.58, + "s": 0.3 + }, + { + "i": 21, + "x": -0.9, + "y": -3.58, + "s": 0.3 + }, + { + "i": 22, + "x": -0.54, + "y": -3.58, + "s": 0.3 + }, + { + "i": 23, + "x": -0.18, + "y": -3.58, + "s": 0.3 + }, + { + "i": 24, + "x": 0.18, + "y": -3.58, + "s": 0.3 + }, + { + "i": 25, + "x": 0.54, + "y": -3.58, + "s": 0.3 + }, + { + "i": 26, + "x": 0.9, + "y": -3.58, + "s": 0.3 + }, + { + "i": 27, + "x": 1.26, + "y": -3.58, + "s": 0.3 + }, + { + "i": 28, + "x": 1.62, + "y": -3.58, + "s": 0.3 + }, + { + "i": 29, + "x": 1.98, + "y": -3.58, + "s": 0.3 + }, + { + "i": 30, + "x": 2.34, + "y": -3.58, + "s": 0.3 + }, + { + "i": 31, + "x": 2.7, + "y": -3.58, + "s": 0.3 + } + ], + "idx": [] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "relocate", + "src": "row:row", + "dst": "_grow16:row", + "count": 16, + "t": 3.1, + "dur": 1.0 + }, + { + "type": "row_destroy", + "target": "row:row", + "write": "_raii_row_16", + "t": 4.1, + "dur": 2.4 + }, + { + "type": "fadeout", + "target": "_cap_row_16", + "t": 9.7, + "dur": 0.3 + }, + { + "type": "fadeout", + "target": "_raii_row_16", + "t": 10.0, + "dur": 0.3 + }, + { + "type": "row_swap", + "target": "row:row", + "tmp": "_grow16:row", + "to": [ + 0.0, + -1.0 + ], + "t": 10.3, + "dur": 0.5 + }, + { + "type": "counter", + "text": "size = 16 capacity = 32", + "t": 10.8, + "dur": 0.25 + } + ] + }, + { + "kind": "push", + "label": "push ×16 (fast)", + "note": "[16,32)", + "duration": 1.6, + "speed": 1.8, + "events": [ + { + "type": "fill", + "target": "row:row", + "i": 16, + "s": 17, + "cap": 32, + "counter": true, + "t": 0.0, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 17, + "s": 18, + "cap": 32, + "counter": true, + "t": 0.1, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 18, + "s": 19, + "cap": 32, + "counter": true, + "t": 0.2, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 19, + "s": 20, + "cap": 32, + "counter": true, + "t": 0.3, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 20, + "s": 21, + "cap": 32, + "counter": true, + "t": 0.4, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 21, + "s": 22, + "cap": 32, + "counter": true, + "t": 0.5, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 22, + "s": 23, + "cap": 32, + "counter": true, + "t": 0.6, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 23, + "s": 24, + "cap": 32, + "counter": true, + "t": 0.7, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 24, + "s": 25, + "cap": 32, + "counter": true, + "t": 0.8, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 25, + "s": 26, + "cap": 32, + "counter": true, + "t": 0.9, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 26, + "s": 27, + "cap": 32, + "counter": true, + "t": 1.0, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 27, + "s": 28, + "cap": 32, + "counter": true, + "t": 1.1, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 28, + "s": 29, + "cap": 32, + "counter": true, + "t": 1.2, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 29, + "s": 30, + "cap": 32, + "counter": true, + "t": 1.3, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 30, + "s": 31, + "cap": 32, + "counter": true, + "t": 1.4, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 31, + "s": 32, + "cap": 32, + "counter": true, + "t": 1.5, + "dur": 0.1 + } + ] + }, + { + "kind": "grow_to", + "label": "扩容 32→64", + "note": "capacity 32->64, 搬 32 格", + "duration": 11.05, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row_32", + "indicate": "row:row", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "_grow32:row", + "g": { + "kind": "cells", + "cap": 64, + "side": 0.22, + "cx": 0.0, + "cy": -3.53, + "w": 4.42, + "h": 1.06, + "cells": [ + { + "i": 0, + "x": -2.1, + "y": -3.11, + "s": 0.22 + }, + { + "i": 1, + "x": -1.82, + "y": -3.11, + "s": 0.22 + }, + { + "i": 2, + "x": -1.54, + "y": -3.11, + "s": 0.22 + }, + { + "i": 3, + "x": -1.26, + "y": -3.11, + "s": 0.22 + }, + { + "i": 4, + "x": -0.98, + "y": -3.11, + "s": 0.22 + }, + { + "i": 5, + "x": -0.7, + "y": -3.11, + "s": 0.22 + }, + { + "i": 6, + "x": -0.42, + "y": -3.11, + "s": 0.22 + }, + { + "i": 7, + "x": -0.14, + "y": -3.11, + "s": 0.22 + }, + { + "i": 8, + "x": 0.14, + "y": -3.11, + "s": 0.22 + }, + { + "i": 9, + "x": 0.42, + "y": -3.11, + "s": 0.22 + }, + { + "i": 10, + "x": 0.7, + "y": -3.11, + "s": 0.22 + }, + { + "i": 11, + "x": 0.98, + "y": -3.11, + "s": 0.22 + }, + { + "i": 12, + "x": 1.26, + "y": -3.11, + "s": 0.22 + }, + { + "i": 13, + "x": 1.54, + "y": -3.11, + "s": 0.22 + }, + { + "i": 14, + "x": 1.82, + "y": -3.11, + "s": 0.22 + }, + { + "i": 15, + "x": 2.1, + "y": -3.11, + "s": 0.22 + }, + { + "i": 16, + "x": -2.1, + "y": -3.39, + "s": 0.22 + }, + { + "i": 17, + "x": -1.82, + "y": -3.39, + "s": 0.22 + }, + { + "i": 18, + "x": -1.54, + "y": -3.39, + "s": 0.22 + }, + { + "i": 19, + "x": -1.26, + "y": -3.39, + "s": 0.22 + }, + { + "i": 20, + "x": -0.98, + "y": -3.39, + "s": 0.22 + }, + { + "i": 21, + "x": -0.7, + "y": -3.39, + "s": 0.22 + }, + { + "i": 22, + "x": -0.42, + "y": -3.39, + "s": 0.22 + }, + { + "i": 23, + "x": -0.14, + "y": -3.39, + "s": 0.22 + }, + { + "i": 24, + "x": 0.14, + "y": -3.39, + "s": 0.22 + }, + { + "i": 25, + "x": 0.42, + "y": -3.39, + "s": 0.22 + }, + { + "i": 26, + "x": 0.7, + "y": -3.39, + "s": 0.22 + }, + { + "i": 27, + "x": 0.98, + "y": -3.39, + "s": 0.22 + }, + { + "i": 28, + "x": 1.26, + "y": -3.39, + "s": 0.22 + }, + { + "i": 29, + "x": 1.54, + "y": -3.39, + "s": 0.22 + }, + { + "i": 30, + "x": 1.82, + "y": -3.39, + "s": 0.22 + }, + { + "i": 31, + "x": 2.1, + "y": -3.39, + "s": 0.22 + }, + { + "i": 32, + "x": -2.1, + "y": -3.67, + "s": 0.22 + }, + { + "i": 33, + "x": -1.82, + "y": -3.67, + "s": 0.22 + }, + { + "i": 34, + "x": -1.54, + "y": -3.67, + "s": 0.22 + }, + { + "i": 35, + "x": -1.26, + "y": -3.67, + "s": 0.22 + }, + { + "i": 36, + "x": -0.98, + "y": -3.67, + "s": 0.22 + }, + { + "i": 37, + "x": -0.7, + "y": -3.67, + "s": 0.22 + }, + { + "i": 38, + "x": -0.42, + "y": -3.67, + "s": 0.22 + }, + { + "i": 39, + "x": -0.14, + "y": -3.67, + "s": 0.22 + }, + { + "i": 40, + "x": 0.14, + "y": -3.67, + "s": 0.22 + }, + { + "i": 41, + "x": 0.42, + "y": -3.67, + "s": 0.22 + }, + { + "i": 42, + "x": 0.7, + "y": -3.67, + "s": 0.22 + }, + { + "i": 43, + "x": 0.98, + "y": -3.67, + "s": 0.22 + }, + { + "i": 44, + "x": 1.26, + "y": -3.67, + "s": 0.22 + }, + { + "i": 45, + "x": 1.54, + "y": -3.67, + "s": 0.22 + }, + { + "i": 46, + "x": 1.82, + "y": -3.67, + "s": 0.22 + }, + { + "i": 47, + "x": 2.1, + "y": -3.67, + "s": 0.22 + }, + { + "i": 48, + "x": -2.1, + "y": -3.95, + "s": 0.22 + }, + { + "i": 49, + "x": -1.82, + "y": -3.95, + "s": 0.22 + }, + { + "i": 50, + "x": -1.54, + "y": -3.95, + "s": 0.22 + }, + { + "i": 51, + "x": -1.26, + "y": -3.95, + "s": 0.22 + }, + { + "i": 52, + "x": -0.98, + "y": -3.95, + "s": 0.22 + }, + { + "i": 53, + "x": -0.7, + "y": -3.95, + "s": 0.22 + }, + { + "i": 54, + "x": -0.42, + "y": -3.95, + "s": 0.22 + }, + { + "i": 55, + "x": -0.14, + "y": -3.95, + "s": 0.22 + }, + { + "i": 56, + "x": 0.14, + "y": -3.95, + "s": 0.22 + }, + { + "i": 57, + "x": 0.42, + "y": -3.95, + "s": 0.22 + }, + { + "i": 58, + "x": 0.7, + "y": -3.95, + "s": 0.22 + }, + { + "i": 59, + "x": 0.98, + "y": -3.95, + "s": 0.22 + }, + { + "i": 60, + "x": 1.26, + "y": -3.95, + "s": 0.22 + }, + { + "i": 61, + "x": 1.54, + "y": -3.95, + "s": 0.22 + }, + { + "i": 62, + "x": 1.82, + "y": -3.95, + "s": 0.22 + }, + { + "i": 63, + "x": 2.1, + "y": -3.95, + "s": 0.22 + } + ], + "idx": [] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "relocate", + "src": "row:row", + "dst": "_grow32:row", + "count": 32, + "t": 3.1, + "dur": 1.0 + }, + { + "type": "row_destroy", + "target": "row:row", + "write": "_raii_row_32", + "t": 4.1, + "dur": 2.4 + }, + { + "type": "fadeout", + "target": "_cap_row_32", + "t": 9.7, + "dur": 0.3 + }, + { + "type": "fadeout", + "target": "_raii_row_32", + "t": 10.0, + "dur": 0.3 + }, + { + "type": "row_swap", + "target": "row:row", + "tmp": "_grow32:row", + "to": [ + 0.0, + -1.0 + ], + "t": 10.3, + "dur": 0.5 + }, + { + "type": "counter", + "text": "size = 32 capacity = 64", + "t": 10.8, + "dur": 0.25 + } + ] + }, + { + "kind": "push", + "label": "push ×8 (turbo)", + "note": "[32,40)", + "duration": 0.4, + "speed": 3.6, + "events": [ + { + "type": "fill", + "target": "row:row", + "i": 32, + "s": 33, + "cap": 64, + "counter": true, + "t": 0.0, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 33, + "s": 34, + "cap": 64, + "counter": true, + "t": 0.05, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 34, + "s": 35, + "cap": 64, + "counter": true, + "t": 0.1, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 35, + "s": 36, + "cap": 64, + "counter": true, + "t": 0.15, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 36, + "s": 37, + "cap": 64, + "counter": true, + "t": 0.2, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 37, + "s": 38, + "cap": 64, + "counter": true, + "t": 0.25, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 38, + "s": 39, + "cap": 64, + "counter": true, + "t": 0.3, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 39, + "s": 40, + "cap": 64, + "counter": true, + "t": 0.35, + "dur": 0.05 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "0.5s", + "duration": 0.5, + "speed": 1.0, + "events": [] + }, + { + "kind": "show", + "label": "show lb_note", + "note": "", + "duration": 1.67, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "show:lb_note", + "t": 0.0, + "dur": 1.67 + } + ] + }, + { + "kind": "show", + "label": "show bars", + "note": "", + "duration": 0.8, + "speed": 1.0, + "events": [ + { + "type": "bars_show", + "target": "show:bars", + "t": 0.0, + "dur": 0.8 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "1.2s", + "duration": 1.2, + "speed": 1.0, + "events": [] + }, + { + "kind": "conclude", + "label": "结论", + "note": "压轴结论墙", + "duration": 15.2, + "speed": 1.0, + "events": [ + { + "type": "fadeout", + "target": "show:bars", + "t": 0.0, + "dur": 0.3 + }, + { + "type": "fadeout", + "target": "show:lb_note", + "t": 0.3, + "dur": 0.3 + }, + { + "type": "write", + "target": "concl:0", + "t": 0.6, + "dur": 2.4 + }, + { + "type": "write", + "target": "concl:1", + "t": 3.35, + "dur": 2.4 + }, + { + "type": "write", + "target": "concl:2", + "t": 6.1, + "dur": 2.4 + }, + { + "type": "pulse", + "target": "counter", + "t": 12.2, + "dur": 1.0 + } + ] + } + ] +} diff --git a/site/.vitepress/theme/components/animations/data/vector_growth.json b/site/.vitepress/theme/components/animations/data/vector_growth.json new file mode 100644 index 000000000..af508e3d9 --- /dev/null +++ b/site/.vitepress/theme/components/animations/data/vector_growth.json @@ -0,0 +1,3016 @@ +{ + "version": 1, + "id": "vector_growth", + "title": "ministl::Vector 扩容轨迹", + "subtitle": "连塞 40 个数:40 次 push_back,只有 5 次扩容", + "source": "examples/vector_growth.yaml", + "backend": "web", + "frame": { + "w": 14.2222, + "h": 8.0 + }, + "palette": { + "bg": "#17171f", + "text": "#ECECE4", + "muted": "#9a9aad", + "fill": "#5EC8E0", + "fillEdge": "#2E86AB", + "emptyEdge": "#4a4a5e", + "grow": "#FFB454", + "numOnFill": "#0e2430", + "ok": "#7BC96A", + "bad": "#E06C75", + "cardBg": "#1e1e2a" + }, + "actors": { + "title": { + "kind": "text", + "text": "ministl::Vector 扩容轨迹", + "x": 0.0, + "y": 3.4324, + "fs": 0.32, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 4.864, + "h": 0.4352 + }, + "sub": { + "kind": "text", + "text": "连塞 40 个数:40 次 push_back,只有 5 次扩容", + "x": 0.0, + "y": 2.8988, + "fs": 0.2, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 5.648, + "h": 0.272 + }, + "counter": { + "kind": "text", + "text": "size = 0 capacity = 0", + "x": 0.0, + "y": 1.6, + "fs": 0.3, + "color": "#ECECE4", + "mono": true, + "anchor": "middle", + "w": 5.148, + "h": 0.3 + }, + "_empty": { + "kind": "text", + "text": "还没申请内存", + "x": 0.0, + "y": -1.0, + "fs": 0.2, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 1.584, + "h": 0.272 + }, + "_cap_row": { + "kind": "text", + "text": "申请内存: capacity 0 → 4", + "x": 0.0, + "y": 0.1632, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 3.816, + "h": 0.3264 + }, + "row:row": { + "kind": "cells", + "cap": 64, + "side": 0.22, + "cx": 0.0, + "cy": -1.0, + "w": 4.42, + "h": 1.06, + "cells": [ + { + "i": 0, + "x": -2.1, + "y": -0.58, + "s": 0.22 + }, + { + "i": 1, + "x": -1.82, + "y": -0.58, + "s": 0.22 + }, + { + "i": 2, + "x": -1.54, + "y": -0.58, + "s": 0.22 + }, + { + "i": 3, + "x": -1.26, + "y": -0.58, + "s": 0.22 + }, + { + "i": 4, + "x": -0.98, + "y": -0.58, + "s": 0.22 + }, + { + "i": 5, + "x": -0.7, + "y": -0.58, + "s": 0.22 + }, + { + "i": 6, + "x": -0.42, + "y": -0.58, + "s": 0.22 + }, + { + "i": 7, + "x": -0.14, + "y": -0.58, + "s": 0.22 + }, + { + "i": 8, + "x": 0.14, + "y": -0.58, + "s": 0.22 + }, + { + "i": 9, + "x": 0.42, + "y": -0.58, + "s": 0.22 + }, + { + "i": 10, + "x": 0.7, + "y": -0.58, + "s": 0.22 + }, + { + "i": 11, + "x": 0.98, + "y": -0.58, + "s": 0.22 + }, + { + "i": 12, + "x": 1.26, + "y": -0.58, + "s": 0.22 + }, + { + "i": 13, + "x": 1.54, + "y": -0.58, + "s": 0.22 + }, + { + "i": 14, + "x": 1.82, + "y": -0.58, + "s": 0.22 + }, + { + "i": 15, + "x": 2.1, + "y": -0.58, + "s": 0.22 + }, + { + "i": 16, + "x": -2.1, + "y": -0.86, + "s": 0.22 + }, + { + "i": 17, + "x": -1.82, + "y": -0.86, + "s": 0.22 + }, + { + "i": 18, + "x": -1.54, + "y": -0.86, + "s": 0.22 + }, + { + "i": 19, + "x": -1.26, + "y": -0.86, + "s": 0.22 + }, + { + "i": 20, + "x": -0.98, + "y": -0.86, + "s": 0.22 + }, + { + "i": 21, + "x": -0.7, + "y": -0.86, + "s": 0.22 + }, + { + "i": 22, + "x": -0.42, + "y": -0.86, + "s": 0.22 + }, + { + "i": 23, + "x": -0.14, + "y": -0.86, + "s": 0.22 + }, + { + "i": 24, + "x": 0.14, + "y": -0.86, + "s": 0.22 + }, + { + "i": 25, + "x": 0.42, + "y": -0.86, + "s": 0.22 + }, + { + "i": 26, + "x": 0.7, + "y": -0.86, + "s": 0.22 + }, + { + "i": 27, + "x": 0.98, + "y": -0.86, + "s": 0.22 + }, + { + "i": 28, + "x": 1.26, + "y": -0.86, + "s": 0.22 + }, + { + "i": 29, + "x": 1.54, + "y": -0.86, + "s": 0.22 + }, + { + "i": 30, + "x": 1.82, + "y": -0.86, + "s": 0.22 + }, + { + "i": 31, + "x": 2.1, + "y": -0.86, + "s": 0.22 + }, + { + "i": 32, + "x": -2.1, + "y": -1.14, + "s": 0.22 + }, + { + "i": 33, + "x": -1.82, + "y": -1.14, + "s": 0.22 + }, + { + "i": 34, + "x": -1.54, + "y": -1.14, + "s": 0.22 + }, + { + "i": 35, + "x": -1.26, + "y": -1.14, + "s": 0.22 + }, + { + "i": 36, + "x": -0.98, + "y": -1.14, + "s": 0.22 + }, + { + "i": 37, + "x": -0.7, + "y": -1.14, + "s": 0.22 + }, + { + "i": 38, + "x": -0.42, + "y": -1.14, + "s": 0.22 + }, + { + "i": 39, + "x": -0.14, + "y": -1.14, + "s": 0.22 + }, + { + "i": 40, + "x": 0.14, + "y": -1.14, + "s": 0.22 + }, + { + "i": 41, + "x": 0.42, + "y": -1.14, + "s": 0.22 + }, + { + "i": 42, + "x": 0.7, + "y": -1.14, + "s": 0.22 + }, + { + "i": 43, + "x": 0.98, + "y": -1.14, + "s": 0.22 + }, + { + "i": 44, + "x": 1.26, + "y": -1.14, + "s": 0.22 + }, + { + "i": 45, + "x": 1.54, + "y": -1.14, + "s": 0.22 + }, + { + "i": 46, + "x": 1.82, + "y": -1.14, + "s": 0.22 + }, + { + "i": 47, + "x": 2.1, + "y": -1.14, + "s": 0.22 + }, + { + "i": 48, + "x": -2.1, + "y": -1.42, + "s": 0.22 + }, + { + "i": 49, + "x": -1.82, + "y": -1.42, + "s": 0.22 + }, + { + "i": 50, + "x": -1.54, + "y": -1.42, + "s": 0.22 + }, + { + "i": 51, + "x": -1.26, + "y": -1.42, + "s": 0.22 + }, + { + "i": 52, + "x": -0.98, + "y": -1.42, + "s": 0.22 + }, + { + "i": 53, + "x": -0.7, + "y": -1.42, + "s": 0.22 + }, + { + "i": 54, + "x": -0.42, + "y": -1.42, + "s": 0.22 + }, + { + "i": 55, + "x": -0.14, + "y": -1.42, + "s": 0.22 + }, + { + "i": 56, + "x": 0.14, + "y": -1.42, + "s": 0.22 + }, + { + "i": 57, + "x": 0.42, + "y": -1.42, + "s": 0.22 + }, + { + "i": 58, + "x": 0.7, + "y": -1.42, + "s": 0.22 + }, + { + "i": 59, + "x": 0.98, + "y": -1.42, + "s": 0.22 + }, + { + "i": 60, + "x": 1.26, + "y": -1.42, + "s": 0.22 + }, + { + "i": 61, + "x": 1.54, + "y": -1.42, + "s": 0.22 + }, + { + "i": 62, + "x": 1.82, + "y": -1.42, + "s": 0.22 + }, + { + "i": 63, + "x": 2.1, + "y": -1.42, + "s": 0.22 + } + ], + "idx": [] + }, + "_cap_row_4": { + "kind": "text", + "text": "满了!capacity 4 → 8,grow_to!", + "x": 0.0, + "y": -2.1732, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 4.8768, + "h": 0.3264 + }, + "_grow4:row": { + "kind": "cells", + "cap": 8, + "side": 0.5, + "cx": 0.0, + "cy": -3.51, + "w": 4.42, + "h": 0.5, + "cells": [ + { + "i": 0, + "x": -1.96, + "y": -3.51, + "s": 0.5 + }, + { + "i": 1, + "x": -1.4, + "y": -3.51, + "s": 0.5 + }, + { + "i": 2, + "x": -0.84, + "y": -3.51, + "s": 0.5 + }, + { + "i": 3, + "x": -0.28, + "y": -3.51, + "s": 0.5 + }, + { + "i": 4, + "x": 0.28, + "y": -3.51, + "s": 0.5 + }, + { + "i": 5, + "x": 0.84, + "y": -3.51, + "s": 0.5 + }, + { + "i": 6, + "x": 1.4, + "y": -3.51, + "s": 0.5 + }, + { + "i": 7, + "x": 1.96, + "y": -3.51, + "s": 0.5 + } + ], + "idx": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ] + }, + "_raii_row_4": { + "kind": "text", + "text": "旧对象已逐个析构, 内存 RAII 归还", + "x": 0.0, + "y": -0.3176, + "fs": 0.18, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 3.744, + "h": 0.2448 + }, + "_cap_row_8": { + "kind": "text", + "text": "满了!capacity 8 → 16,grow_to!", + "x": 0.0, + "y": -2.1132, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 5.0256, + "h": 0.3264 + }, + "_grow8:row": { + "kind": "cells", + "cap": 16, + "side": 0.4, + "cx": 0.0, + "cy": -3.45, + "w": 7.3, + "h": 0.4, + "cells": [ + { + "i": 0, + "x": -3.45, + "y": -3.45, + "s": 0.4 + }, + { + "i": 1, + "x": -2.99, + "y": -3.45, + "s": 0.4 + }, + { + "i": 2, + "x": -2.53, + "y": -3.45, + "s": 0.4 + }, + { + "i": 3, + "x": -2.07, + "y": -3.45, + "s": 0.4 + }, + { + "i": 4, + "x": -1.61, + "y": -3.45, + "s": 0.4 + }, + { + "i": 5, + "x": -1.15, + "y": -3.45, + "s": 0.4 + }, + { + "i": 6, + "x": -0.69, + "y": -3.45, + "s": 0.4 + }, + { + "i": 7, + "x": -0.23, + "y": -3.45, + "s": 0.4 + }, + { + "i": 8, + "x": 0.23, + "y": -3.45, + "s": 0.4 + }, + { + "i": 9, + "x": 0.69, + "y": -3.45, + "s": 0.4 + }, + { + "i": 10, + "x": 1.15, + "y": -3.45, + "s": 0.4 + }, + { + "i": 11, + "x": 1.61, + "y": -3.45, + "s": 0.4 + }, + { + "i": 12, + "x": 2.07, + "y": -3.45, + "s": 0.4 + }, + { + "i": 13, + "x": 2.53, + "y": -3.45, + "s": 0.4 + }, + { + "i": 14, + "x": 2.99, + "y": -3.45, + "s": 0.4 + }, + { + "i": 15, + "x": 3.45, + "y": -3.45, + "s": 0.4 + } + ], + "idx": [] + }, + "_raii_row_8": { + "kind": "text", + "text": "旧对象已逐个析构, 内存 RAII 归还", + "x": 0.0, + "y": -0.3776, + "fs": 0.18, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 3.744, + "h": 0.2448 + }, + "_cap_row_16": { + "kind": "text", + "text": "满了!capacity 16 → 32,grow_to!", + "x": 0.0, + "y": -2.0632, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 5.1744, + "h": 0.3264 + }, + "_grow16:row": { + "kind": "cells", + "cap": 32, + "side": 0.3, + "cx": 0.0, + "cy": -3.4, + "w": 5.7, + "h": 0.66, + "cells": [ + { + "i": 0, + "x": -2.7, + "y": -3.22, + "s": 0.3 + }, + { + "i": 1, + "x": -2.34, + "y": -3.22, + "s": 0.3 + }, + { + "i": 2, + "x": -1.98, + "y": -3.22, + "s": 0.3 + }, + { + "i": 3, + "x": -1.62, + "y": -3.22, + "s": 0.3 + }, + { + "i": 4, + "x": -1.26, + "y": -3.22, + "s": 0.3 + }, + { + "i": 5, + "x": -0.9, + "y": -3.22, + "s": 0.3 + }, + { + "i": 6, + "x": -0.54, + "y": -3.22, + "s": 0.3 + }, + { + "i": 7, + "x": -0.18, + "y": -3.22, + "s": 0.3 + }, + { + "i": 8, + "x": 0.18, + "y": -3.22, + "s": 0.3 + }, + { + "i": 9, + "x": 0.54, + "y": -3.22, + "s": 0.3 + }, + { + "i": 10, + "x": 0.9, + "y": -3.22, + "s": 0.3 + }, + { + "i": 11, + "x": 1.26, + "y": -3.22, + "s": 0.3 + }, + { + "i": 12, + "x": 1.62, + "y": -3.22, + "s": 0.3 + }, + { + "i": 13, + "x": 1.98, + "y": -3.22, + "s": 0.3 + }, + { + "i": 14, + "x": 2.34, + "y": -3.22, + "s": 0.3 + }, + { + "i": 15, + "x": 2.7, + "y": -3.22, + "s": 0.3 + }, + { + "i": 16, + "x": -2.7, + "y": -3.58, + "s": 0.3 + }, + { + "i": 17, + "x": -2.34, + "y": -3.58, + "s": 0.3 + }, + { + "i": 18, + "x": -1.98, + "y": -3.58, + "s": 0.3 + }, + { + "i": 19, + "x": -1.62, + "y": -3.58, + "s": 0.3 + }, + { + "i": 20, + "x": -1.26, + "y": -3.58, + "s": 0.3 + }, + { + "i": 21, + "x": -0.9, + "y": -3.58, + "s": 0.3 + }, + { + "i": 22, + "x": -0.54, + "y": -3.58, + "s": 0.3 + }, + { + "i": 23, + "x": -0.18, + "y": -3.58, + "s": 0.3 + }, + { + "i": 24, + "x": 0.18, + "y": -3.58, + "s": 0.3 + }, + { + "i": 25, + "x": 0.54, + "y": -3.58, + "s": 0.3 + }, + { + "i": 26, + "x": 0.9, + "y": -3.58, + "s": 0.3 + }, + { + "i": 27, + "x": 1.26, + "y": -3.58, + "s": 0.3 + }, + { + "i": 28, + "x": 1.62, + "y": -3.58, + "s": 0.3 + }, + { + "i": 29, + "x": 1.98, + "y": -3.58, + "s": 0.3 + }, + { + "i": 30, + "x": 2.34, + "y": -3.58, + "s": 0.3 + }, + { + "i": 31, + "x": 2.7, + "y": -3.58, + "s": 0.3 + } + ], + "idx": [] + }, + "_raii_row_16": { + "kind": "text", + "text": "旧对象已逐个析构, 内存 RAII 归还", + "x": 0.0, + "y": -0.4276, + "fs": 0.18, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 3.744, + "h": 0.2448 + }, + "_cap_row_32": { + "kind": "text", + "text": "满了!capacity 32 → 64,grow_to!", + "x": 0.0, + "y": -2.1932, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 5.1744, + "h": 0.3264 + }, + "_grow32:row": { + "kind": "cells", + "cap": 64, + "side": 0.22, + "cx": 0.0, + "cy": -3.53, + "w": 4.42, + "h": 1.06, + "cells": [ + { + "i": 0, + "x": -2.1, + "y": -3.11, + "s": 0.22 + }, + { + "i": 1, + "x": -1.82, + "y": -3.11, + "s": 0.22 + }, + { + "i": 2, + "x": -1.54, + "y": -3.11, + "s": 0.22 + }, + { + "i": 3, + "x": -1.26, + "y": -3.11, + "s": 0.22 + }, + { + "i": 4, + "x": -0.98, + "y": -3.11, + "s": 0.22 + }, + { + "i": 5, + "x": -0.7, + "y": -3.11, + "s": 0.22 + }, + { + "i": 6, + "x": -0.42, + "y": -3.11, + "s": 0.22 + }, + { + "i": 7, + "x": -0.14, + "y": -3.11, + "s": 0.22 + }, + { + "i": 8, + "x": 0.14, + "y": -3.11, + "s": 0.22 + }, + { + "i": 9, + "x": 0.42, + "y": -3.11, + "s": 0.22 + }, + { + "i": 10, + "x": 0.7, + "y": -3.11, + "s": 0.22 + }, + { + "i": 11, + "x": 0.98, + "y": -3.11, + "s": 0.22 + }, + { + "i": 12, + "x": 1.26, + "y": -3.11, + "s": 0.22 + }, + { + "i": 13, + "x": 1.54, + "y": -3.11, + "s": 0.22 + }, + { + "i": 14, + "x": 1.82, + "y": -3.11, + "s": 0.22 + }, + { + "i": 15, + "x": 2.1, + "y": -3.11, + "s": 0.22 + }, + { + "i": 16, + "x": -2.1, + "y": -3.39, + "s": 0.22 + }, + { + "i": 17, + "x": -1.82, + "y": -3.39, + "s": 0.22 + }, + { + "i": 18, + "x": -1.54, + "y": -3.39, + "s": 0.22 + }, + { + "i": 19, + "x": -1.26, + "y": -3.39, + "s": 0.22 + }, + { + "i": 20, + "x": -0.98, + "y": -3.39, + "s": 0.22 + }, + { + "i": 21, + "x": -0.7, + "y": -3.39, + "s": 0.22 + }, + { + "i": 22, + "x": -0.42, + "y": -3.39, + "s": 0.22 + }, + { + "i": 23, + "x": -0.14, + "y": -3.39, + "s": 0.22 + }, + { + "i": 24, + "x": 0.14, + "y": -3.39, + "s": 0.22 + }, + { + "i": 25, + "x": 0.42, + "y": -3.39, + "s": 0.22 + }, + { + "i": 26, + "x": 0.7, + "y": -3.39, + "s": 0.22 + }, + { + "i": 27, + "x": 0.98, + "y": -3.39, + "s": 0.22 + }, + { + "i": 28, + "x": 1.26, + "y": -3.39, + "s": 0.22 + }, + { + "i": 29, + "x": 1.54, + "y": -3.39, + "s": 0.22 + }, + { + "i": 30, + "x": 1.82, + "y": -3.39, + "s": 0.22 + }, + { + "i": 31, + "x": 2.1, + "y": -3.39, + "s": 0.22 + }, + { + "i": 32, + "x": -2.1, + "y": -3.67, + "s": 0.22 + }, + { + "i": 33, + "x": -1.82, + "y": -3.67, + "s": 0.22 + }, + { + "i": 34, + "x": -1.54, + "y": -3.67, + "s": 0.22 + }, + { + "i": 35, + "x": -1.26, + "y": -3.67, + "s": 0.22 + }, + { + "i": 36, + "x": -0.98, + "y": -3.67, + "s": 0.22 + }, + { + "i": 37, + "x": -0.7, + "y": -3.67, + "s": 0.22 + }, + { + "i": 38, + "x": -0.42, + "y": -3.67, + "s": 0.22 + }, + { + "i": 39, + "x": -0.14, + "y": -3.67, + "s": 0.22 + }, + { + "i": 40, + "x": 0.14, + "y": -3.67, + "s": 0.22 + }, + { + "i": 41, + "x": 0.42, + "y": -3.67, + "s": 0.22 + }, + { + "i": 42, + "x": 0.7, + "y": -3.67, + "s": 0.22 + }, + { + "i": 43, + "x": 0.98, + "y": -3.67, + "s": 0.22 + }, + { + "i": 44, + "x": 1.26, + "y": -3.67, + "s": 0.22 + }, + { + "i": 45, + "x": 1.54, + "y": -3.67, + "s": 0.22 + }, + { + "i": 46, + "x": 1.82, + "y": -3.67, + "s": 0.22 + }, + { + "i": 47, + "x": 2.1, + "y": -3.67, + "s": 0.22 + }, + { + "i": 48, + "x": -2.1, + "y": -3.95, + "s": 0.22 + }, + { + "i": 49, + "x": -1.82, + "y": -3.95, + "s": 0.22 + }, + { + "i": 50, + "x": -1.54, + "y": -3.95, + "s": 0.22 + }, + { + "i": 51, + "x": -1.26, + "y": -3.95, + "s": 0.22 + }, + { + "i": 52, + "x": -0.98, + "y": -3.95, + "s": 0.22 + }, + { + "i": 53, + "x": -0.7, + "y": -3.95, + "s": 0.22 + }, + { + "i": 54, + "x": -0.42, + "y": -3.95, + "s": 0.22 + }, + { + "i": 55, + "x": -0.14, + "y": -3.95, + "s": 0.22 + }, + { + "i": 56, + "x": 0.14, + "y": -3.95, + "s": 0.22 + }, + { + "i": 57, + "x": 0.42, + "y": -3.95, + "s": 0.22 + }, + { + "i": 58, + "x": 0.7, + "y": -3.95, + "s": 0.22 + }, + { + "i": 59, + "x": 0.98, + "y": -3.95, + "s": 0.22 + }, + { + "i": 60, + "x": 1.26, + "y": -3.95, + "s": 0.22 + }, + { + "i": 61, + "x": 1.54, + "y": -3.95, + "s": 0.22 + }, + { + "i": 62, + "x": 1.82, + "y": -3.95, + "s": 0.22 + }, + { + "i": 63, + "x": 2.1, + "y": -3.95, + "s": 0.22 + } + ], + "idx": [] + }, + "_raii_row_32": { + "kind": "text", + "text": "旧对象已逐个析构, 内存 RAII 归还", + "x": 0.0, + "y": -0.2976, + "fs": 0.18, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 3.744, + "h": 0.2448 + }, + "concl:0": { + "kind": "text", + "text": "40 次 push_back,只有 5 次扩容", + "x": 0.0, + "y": -2.6604, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 4.5984, + "h": 0.3264 + }, + "concl:1": { + "kind": "text", + "text": "总搬迁 4+8+16+32 = 60 < 2×40 —— push_back 摊还 O(1)", + "x": 0.0, + "y": -3.2368, + "fs": 0.24, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 8.0208, + "h": 0.3264 + } + }, + "steps": [ + { + "kind": "intro", + "label": "开场", + "note": "", + "duration": 5.8, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "title", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "fadein", + "target": "sub", + "t": 2.4, + "dur": 0.5 + }, + { + "type": "fadein", + "target": "counter", + "t": 2.4, + "dur": 0.5 + }, + { + "type": "write", + "target": "_empty", + "t": 3.4, + "dur": 1.07 + }, + { + "type": "fadeout", + "target": "_empty", + "t": 5.5, + "dur": 0.3 + } + ] + }, + { + "kind": "grow_to", + "label": "申请 4", + "note": "capacity 0->4, 搬 0 格", + "duration": 6.15, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "row:row", + "g": { + "kind": "cells", + "cap": 4, + "side": 0.62, + "cx": 0.0, + "cy": -1.0, + "w": 2.66, + "h": 0.62, + "cells": [ + { + "i": 0, + "x": -1.02, + "y": -1.0, + "s": 0.62 + }, + { + "i": 1, + "x": -0.34, + "y": -1.0, + "s": 0.62 + }, + { + "i": 2, + "x": 0.34, + "y": -1.0, + "s": 0.62 + }, + { + "i": 3, + "x": 1.02, + "y": -1.0, + "s": 0.62 + } + ], + "idx": [ + 1, + 2, + 3, + 4 + ] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "fadeout", + "target": "_cap_row", + "t": 5.6, + "dur": 0.3 + }, + { + "type": "counter", + "text": "size = 0 capacity = 4", + "t": 5.9, + "dur": 0.25 + } + ] + }, + { + "kind": "push", + "label": "push ×4 (slow)", + "note": "[0,4)", + "duration": 1.2, + "speed": 0.6, + "events": [ + { + "type": "fill", + "target": "row:row", + "i": 0, + "s": 1, + "cap": 4, + "counter": true, + "t": 0.0, + "dur": 0.3 + }, + { + "type": "fill", + "target": "row:row", + "i": 1, + "s": 2, + "cap": 4, + "counter": true, + "t": 0.3, + "dur": 0.3 + }, + { + "type": "fill", + "target": "row:row", + "i": 2, + "s": 3, + "cap": 4, + "counter": true, + "t": 0.6, + "dur": 0.3 + }, + { + "type": "fill", + "target": "row:row", + "i": 3, + "s": 4, + "cap": 4, + "counter": true, + "t": 0.9, + "dur": 0.3 + } + ] + }, + { + "kind": "grow_to", + "label": "扩容 4→8", + "note": "capacity 4->8, 搬 4 格", + "duration": 11.05, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row_4", + "indicate": "row:row", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "_grow4:row", + "g": { + "kind": "cells", + "cap": 8, + "side": 0.5, + "cx": 0.0, + "cy": -3.51, + "w": 4.42, + "h": 0.5, + "cells": [ + { + "i": 0, + "x": -1.96, + "y": -3.51, + "s": 0.5 + }, + { + "i": 1, + "x": -1.4, + "y": -3.51, + "s": 0.5 + }, + { + "i": 2, + "x": -0.84, + "y": -3.51, + "s": 0.5 + }, + { + "i": 3, + "x": -0.28, + "y": -3.51, + "s": 0.5 + }, + { + "i": 4, + "x": 0.28, + "y": -3.51, + "s": 0.5 + }, + { + "i": 5, + "x": 0.84, + "y": -3.51, + "s": 0.5 + }, + { + "i": 6, + "x": 1.4, + "y": -3.51, + "s": 0.5 + }, + { + "i": 7, + "x": 1.96, + "y": -3.51, + "s": 0.5 + } + ], + "idx": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "relocate", + "src": "row:row", + "dst": "_grow4:row", + "count": 4, + "t": 3.1, + "dur": 1.0 + }, + { + "type": "row_destroy", + "target": "row:row", + "write": "_raii_row_4", + "t": 4.1, + "dur": 2.4 + }, + { + "type": "fadeout", + "target": "_cap_row_4", + "t": 9.7, + "dur": 0.3 + }, + { + "type": "fadeout", + "target": "_raii_row_4", + "t": 10.0, + "dur": 0.3 + }, + { + "type": "row_swap", + "target": "row:row", + "tmp": "_grow4:row", + "to": [ + 0.0, + -1.0 + ], + "t": 10.3, + "dur": 0.5 + }, + { + "type": "counter", + "text": "size = 4 capacity = 8", + "t": 10.8, + "dur": 0.25 + } + ] + }, + { + "kind": "push", + "label": "push ×4 (normal)", + "note": "[4,8)", + "duration": 0.72, + "speed": 1.0, + "events": [ + { + "type": "fill", + "target": "row:row", + "i": 4, + "s": 5, + "cap": 8, + "counter": true, + "t": 0.0, + "dur": 0.18 + }, + { + "type": "fill", + "target": "row:row", + "i": 5, + "s": 6, + "cap": 8, + "counter": true, + "t": 0.18, + "dur": 0.18 + }, + { + "type": "fill", + "target": "row:row", + "i": 6, + "s": 7, + "cap": 8, + "counter": true, + "t": 0.36, + "dur": 0.18 + }, + { + "type": "fill", + "target": "row:row", + "i": 7, + "s": 8, + "cap": 8, + "counter": true, + "t": 0.54, + "dur": 0.18 + } + ] + }, + { + "kind": "grow_to", + "label": "扩容 8→16", + "note": "capacity 8->16, 搬 8 格", + "duration": 11.05, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row_8", + "indicate": "row:row", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "_grow8:row", + "g": { + "kind": "cells", + "cap": 16, + "side": 0.4, + "cx": 0.0, + "cy": -3.45, + "w": 7.3, + "h": 0.4, + "cells": [ + { + "i": 0, + "x": -3.45, + "y": -3.45, + "s": 0.4 + }, + { + "i": 1, + "x": -2.99, + "y": -3.45, + "s": 0.4 + }, + { + "i": 2, + "x": -2.53, + "y": -3.45, + "s": 0.4 + }, + { + "i": 3, + "x": -2.07, + "y": -3.45, + "s": 0.4 + }, + { + "i": 4, + "x": -1.61, + "y": -3.45, + "s": 0.4 + }, + { + "i": 5, + "x": -1.15, + "y": -3.45, + "s": 0.4 + }, + { + "i": 6, + "x": -0.69, + "y": -3.45, + "s": 0.4 + }, + { + "i": 7, + "x": -0.23, + "y": -3.45, + "s": 0.4 + }, + { + "i": 8, + "x": 0.23, + "y": -3.45, + "s": 0.4 + }, + { + "i": 9, + "x": 0.69, + "y": -3.45, + "s": 0.4 + }, + { + "i": 10, + "x": 1.15, + "y": -3.45, + "s": 0.4 + }, + { + "i": 11, + "x": 1.61, + "y": -3.45, + "s": 0.4 + }, + { + "i": 12, + "x": 2.07, + "y": -3.45, + "s": 0.4 + }, + { + "i": 13, + "x": 2.53, + "y": -3.45, + "s": 0.4 + }, + { + "i": 14, + "x": 2.99, + "y": -3.45, + "s": 0.4 + }, + { + "i": 15, + "x": 3.45, + "y": -3.45, + "s": 0.4 + } + ], + "idx": [] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "relocate", + "src": "row:row", + "dst": "_grow8:row", + "count": 8, + "t": 3.1, + "dur": 1.0 + }, + { + "type": "row_destroy", + "target": "row:row", + "write": "_raii_row_8", + "t": 4.1, + "dur": 2.4 + }, + { + "type": "fadeout", + "target": "_cap_row_8", + "t": 9.7, + "dur": 0.3 + }, + { + "type": "fadeout", + "target": "_raii_row_8", + "t": 10.0, + "dur": 0.3 + }, + { + "type": "row_swap", + "target": "row:row", + "tmp": "_grow8:row", + "to": [ + 0.0, + -1.0 + ], + "t": 10.3, + "dur": 0.5 + }, + { + "type": "counter", + "text": "size = 8 capacity = 16", + "t": 10.8, + "dur": 0.25 + } + ] + }, + { + "kind": "push", + "label": "push ×8 (fast)", + "note": "[8,16)", + "duration": 0.8, + "speed": 1.8, + "events": [ + { + "type": "fill", + "target": "row:row", + "i": 8, + "s": 9, + "cap": 16, + "counter": true, + "t": 0.0, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 9, + "s": 10, + "cap": 16, + "counter": true, + "t": 0.1, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 10, + "s": 11, + "cap": 16, + "counter": true, + "t": 0.2, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 11, + "s": 12, + "cap": 16, + "counter": true, + "t": 0.3, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 12, + "s": 13, + "cap": 16, + "counter": true, + "t": 0.4, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 13, + "s": 14, + "cap": 16, + "counter": true, + "t": 0.5, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 14, + "s": 15, + "cap": 16, + "counter": true, + "t": 0.6, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 15, + "s": 16, + "cap": 16, + "counter": true, + "t": 0.7, + "dur": 0.1 + } + ] + }, + { + "kind": "grow_to", + "label": "扩容 16→32", + "note": "capacity 16->32, 搬 16 格", + "duration": 11.05, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row_16", + "indicate": "row:row", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "_grow16:row", + "g": { + "kind": "cells", + "cap": 32, + "side": 0.3, + "cx": 0.0, + "cy": -3.4, + "w": 5.7, + "h": 0.66, + "cells": [ + { + "i": 0, + "x": -2.7, + "y": -3.22, + "s": 0.3 + }, + { + "i": 1, + "x": -2.34, + "y": -3.22, + "s": 0.3 + }, + { + "i": 2, + "x": -1.98, + "y": -3.22, + "s": 0.3 + }, + { + "i": 3, + "x": -1.62, + "y": -3.22, + "s": 0.3 + }, + { + "i": 4, + "x": -1.26, + "y": -3.22, + "s": 0.3 + }, + { + "i": 5, + "x": -0.9, + "y": -3.22, + "s": 0.3 + }, + { + "i": 6, + "x": -0.54, + "y": -3.22, + "s": 0.3 + }, + { + "i": 7, + "x": -0.18, + "y": -3.22, + "s": 0.3 + }, + { + "i": 8, + "x": 0.18, + "y": -3.22, + "s": 0.3 + }, + { + "i": 9, + "x": 0.54, + "y": -3.22, + "s": 0.3 + }, + { + "i": 10, + "x": 0.9, + "y": -3.22, + "s": 0.3 + }, + { + "i": 11, + "x": 1.26, + "y": -3.22, + "s": 0.3 + }, + { + "i": 12, + "x": 1.62, + "y": -3.22, + "s": 0.3 + }, + { + "i": 13, + "x": 1.98, + "y": -3.22, + "s": 0.3 + }, + { + "i": 14, + "x": 2.34, + "y": -3.22, + "s": 0.3 + }, + { + "i": 15, + "x": 2.7, + "y": -3.22, + "s": 0.3 + }, + { + "i": 16, + "x": -2.7, + "y": -3.58, + "s": 0.3 + }, + { + "i": 17, + "x": -2.34, + "y": -3.58, + "s": 0.3 + }, + { + "i": 18, + "x": -1.98, + "y": -3.58, + "s": 0.3 + }, + { + "i": 19, + "x": -1.62, + "y": -3.58, + "s": 0.3 + }, + { + "i": 20, + "x": -1.26, + "y": -3.58, + "s": 0.3 + }, + { + "i": 21, + "x": -0.9, + "y": -3.58, + "s": 0.3 + }, + { + "i": 22, + "x": -0.54, + "y": -3.58, + "s": 0.3 + }, + { + "i": 23, + "x": -0.18, + "y": -3.58, + "s": 0.3 + }, + { + "i": 24, + "x": 0.18, + "y": -3.58, + "s": 0.3 + }, + { + "i": 25, + "x": 0.54, + "y": -3.58, + "s": 0.3 + }, + { + "i": 26, + "x": 0.9, + "y": -3.58, + "s": 0.3 + }, + { + "i": 27, + "x": 1.26, + "y": -3.58, + "s": 0.3 + }, + { + "i": 28, + "x": 1.62, + "y": -3.58, + "s": 0.3 + }, + { + "i": 29, + "x": 1.98, + "y": -3.58, + "s": 0.3 + }, + { + "i": 30, + "x": 2.34, + "y": -3.58, + "s": 0.3 + }, + { + "i": 31, + "x": 2.7, + "y": -3.58, + "s": 0.3 + } + ], + "idx": [] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "relocate", + "src": "row:row", + "dst": "_grow16:row", + "count": 16, + "t": 3.1, + "dur": 1.0 + }, + { + "type": "row_destroy", + "target": "row:row", + "write": "_raii_row_16", + "t": 4.1, + "dur": 2.4 + }, + { + "type": "fadeout", + "target": "_cap_row_16", + "t": 9.7, + "dur": 0.3 + }, + { + "type": "fadeout", + "target": "_raii_row_16", + "t": 10.0, + "dur": 0.3 + }, + { + "type": "row_swap", + "target": "row:row", + "tmp": "_grow16:row", + "to": [ + 0.0, + -1.0 + ], + "t": 10.3, + "dur": 0.5 + }, + { + "type": "counter", + "text": "size = 16 capacity = 32", + "t": 10.8, + "dur": 0.25 + } + ] + }, + { + "kind": "push", + "label": "push ×16 (fast)", + "note": "[16,32)", + "duration": 1.6, + "speed": 1.8, + "events": [ + { + "type": "fill", + "target": "row:row", + "i": 16, + "s": 17, + "cap": 32, + "counter": true, + "t": 0.0, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 17, + "s": 18, + "cap": 32, + "counter": true, + "t": 0.1, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 18, + "s": 19, + "cap": 32, + "counter": true, + "t": 0.2, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 19, + "s": 20, + "cap": 32, + "counter": true, + "t": 0.3, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 20, + "s": 21, + "cap": 32, + "counter": true, + "t": 0.4, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 21, + "s": 22, + "cap": 32, + "counter": true, + "t": 0.5, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 22, + "s": 23, + "cap": 32, + "counter": true, + "t": 0.6, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 23, + "s": 24, + "cap": 32, + "counter": true, + "t": 0.7, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 24, + "s": 25, + "cap": 32, + "counter": true, + "t": 0.8, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 25, + "s": 26, + "cap": 32, + "counter": true, + "t": 0.9, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 26, + "s": 27, + "cap": 32, + "counter": true, + "t": 1.0, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 27, + "s": 28, + "cap": 32, + "counter": true, + "t": 1.1, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 28, + "s": 29, + "cap": 32, + "counter": true, + "t": 1.2, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 29, + "s": 30, + "cap": 32, + "counter": true, + "t": 1.3, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 30, + "s": 31, + "cap": 32, + "counter": true, + "t": 1.4, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 31, + "s": 32, + "cap": 32, + "counter": true, + "t": 1.5, + "dur": 0.1 + } + ] + }, + { + "kind": "grow_to", + "label": "扩容 32→64", + "note": "capacity 32->64, 搬 32 格", + "duration": 11.05, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row_32", + "indicate": "row:row", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "_grow32:row", + "g": { + "kind": "cells", + "cap": 64, + "side": 0.22, + "cx": 0.0, + "cy": -3.53, + "w": 4.42, + "h": 1.06, + "cells": [ + { + "i": 0, + "x": -2.1, + "y": -3.11, + "s": 0.22 + }, + { + "i": 1, + "x": -1.82, + "y": -3.11, + "s": 0.22 + }, + { + "i": 2, + "x": -1.54, + "y": -3.11, + "s": 0.22 + }, + { + "i": 3, + "x": -1.26, + "y": -3.11, + "s": 0.22 + }, + { + "i": 4, + "x": -0.98, + "y": -3.11, + "s": 0.22 + }, + { + "i": 5, + "x": -0.7, + "y": -3.11, + "s": 0.22 + }, + { + "i": 6, + "x": -0.42, + "y": -3.11, + "s": 0.22 + }, + { + "i": 7, + "x": -0.14, + "y": -3.11, + "s": 0.22 + }, + { + "i": 8, + "x": 0.14, + "y": -3.11, + "s": 0.22 + }, + { + "i": 9, + "x": 0.42, + "y": -3.11, + "s": 0.22 + }, + { + "i": 10, + "x": 0.7, + "y": -3.11, + "s": 0.22 + }, + { + "i": 11, + "x": 0.98, + "y": -3.11, + "s": 0.22 + }, + { + "i": 12, + "x": 1.26, + "y": -3.11, + "s": 0.22 + }, + { + "i": 13, + "x": 1.54, + "y": -3.11, + "s": 0.22 + }, + { + "i": 14, + "x": 1.82, + "y": -3.11, + "s": 0.22 + }, + { + "i": 15, + "x": 2.1, + "y": -3.11, + "s": 0.22 + }, + { + "i": 16, + "x": -2.1, + "y": -3.39, + "s": 0.22 + }, + { + "i": 17, + "x": -1.82, + "y": -3.39, + "s": 0.22 + }, + { + "i": 18, + "x": -1.54, + "y": -3.39, + "s": 0.22 + }, + { + "i": 19, + "x": -1.26, + "y": -3.39, + "s": 0.22 + }, + { + "i": 20, + "x": -0.98, + "y": -3.39, + "s": 0.22 + }, + { + "i": 21, + "x": -0.7, + "y": -3.39, + "s": 0.22 + }, + { + "i": 22, + "x": -0.42, + "y": -3.39, + "s": 0.22 + }, + { + "i": 23, + "x": -0.14, + "y": -3.39, + "s": 0.22 + }, + { + "i": 24, + "x": 0.14, + "y": -3.39, + "s": 0.22 + }, + { + "i": 25, + "x": 0.42, + "y": -3.39, + "s": 0.22 + }, + { + "i": 26, + "x": 0.7, + "y": -3.39, + "s": 0.22 + }, + { + "i": 27, + "x": 0.98, + "y": -3.39, + "s": 0.22 + }, + { + "i": 28, + "x": 1.26, + "y": -3.39, + "s": 0.22 + }, + { + "i": 29, + "x": 1.54, + "y": -3.39, + "s": 0.22 + }, + { + "i": 30, + "x": 1.82, + "y": -3.39, + "s": 0.22 + }, + { + "i": 31, + "x": 2.1, + "y": -3.39, + "s": 0.22 + }, + { + "i": 32, + "x": -2.1, + "y": -3.67, + "s": 0.22 + }, + { + "i": 33, + "x": -1.82, + "y": -3.67, + "s": 0.22 + }, + { + "i": 34, + "x": -1.54, + "y": -3.67, + "s": 0.22 + }, + { + "i": 35, + "x": -1.26, + "y": -3.67, + "s": 0.22 + }, + { + "i": 36, + "x": -0.98, + "y": -3.67, + "s": 0.22 + }, + { + "i": 37, + "x": -0.7, + "y": -3.67, + "s": 0.22 + }, + { + "i": 38, + "x": -0.42, + "y": -3.67, + "s": 0.22 + }, + { + "i": 39, + "x": -0.14, + "y": -3.67, + "s": 0.22 + }, + { + "i": 40, + "x": 0.14, + "y": -3.67, + "s": 0.22 + }, + { + "i": 41, + "x": 0.42, + "y": -3.67, + "s": 0.22 + }, + { + "i": 42, + "x": 0.7, + "y": -3.67, + "s": 0.22 + }, + { + "i": 43, + "x": 0.98, + "y": -3.67, + "s": 0.22 + }, + { + "i": 44, + "x": 1.26, + "y": -3.67, + "s": 0.22 + }, + { + "i": 45, + "x": 1.54, + "y": -3.67, + "s": 0.22 + }, + { + "i": 46, + "x": 1.82, + "y": -3.67, + "s": 0.22 + }, + { + "i": 47, + "x": 2.1, + "y": -3.67, + "s": 0.22 + }, + { + "i": 48, + "x": -2.1, + "y": -3.95, + "s": 0.22 + }, + { + "i": 49, + "x": -1.82, + "y": -3.95, + "s": 0.22 + }, + { + "i": 50, + "x": -1.54, + "y": -3.95, + "s": 0.22 + }, + { + "i": 51, + "x": -1.26, + "y": -3.95, + "s": 0.22 + }, + { + "i": 52, + "x": -0.98, + "y": -3.95, + "s": 0.22 + }, + { + "i": 53, + "x": -0.7, + "y": -3.95, + "s": 0.22 + }, + { + "i": 54, + "x": -0.42, + "y": -3.95, + "s": 0.22 + }, + { + "i": 55, + "x": -0.14, + "y": -3.95, + "s": 0.22 + }, + { + "i": 56, + "x": 0.14, + "y": -3.95, + "s": 0.22 + }, + { + "i": 57, + "x": 0.42, + "y": -3.95, + "s": 0.22 + }, + { + "i": 58, + "x": 0.7, + "y": -3.95, + "s": 0.22 + }, + { + "i": 59, + "x": 0.98, + "y": -3.95, + "s": 0.22 + }, + { + "i": 60, + "x": 1.26, + "y": -3.95, + "s": 0.22 + }, + { + "i": 61, + "x": 1.54, + "y": -3.95, + "s": 0.22 + }, + { + "i": 62, + "x": 1.82, + "y": -3.95, + "s": 0.22 + }, + { + "i": 63, + "x": 2.1, + "y": -3.95, + "s": 0.22 + } + ], + "idx": [] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "relocate", + "src": "row:row", + "dst": "_grow32:row", + "count": 32, + "t": 3.1, + "dur": 1.0 + }, + { + "type": "row_destroy", + "target": "row:row", + "write": "_raii_row_32", + "t": 4.1, + "dur": 2.4 + }, + { + "type": "fadeout", + "target": "_cap_row_32", + "t": 9.7, + "dur": 0.3 + }, + { + "type": "fadeout", + "target": "_raii_row_32", + "t": 10.0, + "dur": 0.3 + }, + { + "type": "row_swap", + "target": "row:row", + "tmp": "_grow32:row", + "to": [ + 0.0, + -1.0 + ], + "t": 10.3, + "dur": 0.5 + }, + { + "type": "counter", + "text": "size = 32 capacity = 64", + "t": 10.8, + "dur": 0.25 + } + ] + }, + { + "kind": "push", + "label": "push ×8 (turbo)", + "note": "[32,40)", + "duration": 0.4, + "speed": 3.6, + "events": [ + { + "type": "fill", + "target": "row:row", + "i": 32, + "s": 33, + "cap": 64, + "counter": true, + "t": 0.0, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 33, + "s": 34, + "cap": 64, + "counter": true, + "t": 0.05, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 34, + "s": 35, + "cap": 64, + "counter": true, + "t": 0.1, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 35, + "s": 36, + "cap": 64, + "counter": true, + "t": 0.15, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 36, + "s": 37, + "cap": 64, + "counter": true, + "t": 0.2, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 37, + "s": 38, + "cap": 64, + "counter": true, + "t": 0.25, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 38, + "s": 39, + "cap": 64, + "counter": true, + "t": 0.3, + "dur": 0.05 + }, + { + "type": "fill", + "target": "row:row", + "i": 39, + "s": 40, + "cap": 64, + "counter": true, + "t": 0.35, + "dur": 0.05 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "0.5s", + "duration": 0.5, + "speed": 1.0, + "events": [] + }, + { + "kind": "conclude", + "label": "结论", + "note": "压轴结论墙", + "duration": 18.35, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "concl:0", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "write", + "target": "concl:1", + "t": 2.75, + "dur": 2.4 + }, + { + "type": "pulse", + "target": "counter", + "t": 15.35, + "dur": 1.0 + } + ] + } + ] +} diff --git a/site/.vitepress/theme/components/animations/data/vocab_amortized.json b/site/.vitepress/theme/components/animations/data/vocab_amortized.json new file mode 100644 index 000000000..94faba2e3 --- /dev/null +++ b/site/.vitepress/theme/components/animations/data/vocab_amortized.json @@ -0,0 +1,761 @@ +{ + "version": 1, + "id": "vocab_amortized", + "title": "搬迁的账本:为什么 push_back 摊还 O(1)", + "subtitle": "8 次 push,只搬了 4 格", + "source": "examples/vocab_amortized.yaml", + "backend": "web", + "frame": { + "w": 14.2222, + "h": 8.0 + }, + "palette": { + "bg": "#17171f", + "text": "#ECECE4", + "muted": "#9a9aad", + "fill": "#5EC8E0", + "fillEdge": "#2E86AB", + "emptyEdge": "#4a4a5e", + "grow": "#FFB454", + "numOnFill": "#0e2430", + "ok": "#7BC96A", + "bad": "#E06C75", + "cardBg": "#1e1e2a" + }, + "actors": { + "title": { + "kind": "text", + "text": "搬迁的账本:为什么 push_back 摊还 O(1)", + "x": 0.0, + "y": 3.4324, + "fs": 0.32, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 7.8208, + "h": 0.4352 + }, + "sub": { + "kind": "text", + "text": "8 次 push,只搬了 4 格", + "x": 0.0, + "y": 2.8988, + "fs": 0.2, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 2.824, + "h": 0.272 + }, + "counter": { + "kind": "text", + "text": "size = 0 capacity = 0", + "x": 0.0, + "y": 1.6, + "fs": 0.3, + "color": "#ECECE4", + "mono": true, + "anchor": "middle", + "w": 4.752, + "h": 0.3 + }, + "_empty": { + "kind": "text", + "text": "还没申请内存", + "x": 0.0, + "y": -1.0, + "fs": 0.2, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 1.584, + "h": 0.272 + }, + "_cap_row": { + "kind": "text", + "text": "申请内存: capacity 0 → 4", + "x": 0.0, + "y": 0.1632, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 3.816, + "h": 0.3264 + }, + "row:row": { + "kind": "cells", + "cap": 8, + "side": 0.5, + "cx": 0.0, + "cy": -1.0, + "w": 4.42, + "h": 0.5, + "cells": [ + { + "i": 0, + "x": -1.96, + "y": -1.0, + "s": 0.5 + }, + { + "i": 1, + "x": -1.4, + "y": -1.0, + "s": 0.5 + }, + { + "i": 2, + "x": -0.84, + "y": -1.0, + "s": 0.5 + }, + { + "i": 3, + "x": -0.28, + "y": -1.0, + "s": 0.5 + }, + { + "i": 4, + "x": 0.28, + "y": -1.0, + "s": 0.5 + }, + { + "i": 5, + "x": 0.84, + "y": -1.0, + "s": 0.5 + }, + { + "i": 6, + "x": 1.4, + "y": -1.0, + "s": 0.5 + }, + { + "i": 7, + "x": 1.96, + "y": -1.0, + "s": 0.5 + } + ], + "idx": [] + }, + "_cap_row_4": { + "kind": "text", + "text": "满了!capacity 4 → 8,grow_to!", + "x": 0.0, + "y": -2.1732, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 4.8768, + "h": 0.3264 + }, + "_grow4:row": { + "kind": "cells", + "cap": 8, + "side": 0.5, + "cx": 0.0, + "cy": -3.51, + "w": 4.42, + "h": 0.5, + "cells": [ + { + "i": 0, + "x": -1.96, + "y": -3.51, + "s": 0.5 + }, + { + "i": 1, + "x": -1.4, + "y": -3.51, + "s": 0.5 + }, + { + "i": 2, + "x": -0.84, + "y": -3.51, + "s": 0.5 + }, + { + "i": 3, + "x": -0.28, + "y": -3.51, + "s": 0.5 + }, + { + "i": 4, + "x": 0.28, + "y": -3.51, + "s": 0.5 + }, + { + "i": 5, + "x": 0.84, + "y": -3.51, + "s": 0.5 + }, + { + "i": 6, + "x": 1.4, + "y": -3.51, + "s": 0.5 + }, + { + "i": 7, + "x": 1.96, + "y": -3.51, + "s": 0.5 + } + ], + "idx": [] + }, + "_raii_row_4": { + "kind": "text", + "text": "旧对象已逐个析构, 内存 RAII 归还", + "x": 0.0, + "y": -0.3176, + "fs": 0.18, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 3.744, + "h": 0.2448 + }, + "show:lb_note": { + "kind": "text", + "text": "翻倍扩容 → 账本对比", + "x": 4.3, + "y": 1.8, + "fs": 0.2, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 2.624, + "h": 0.272, + "id": "lb_note" + }, + "show:bars": { + "kind": "bars", + "w": 2.5, + "h": 2.4944, + "cols": [ + { + "label": "push 次数", + "value": 8, + "h": 1.6 + }, + { + "label": "搬迁格数", + "value": 4, + "h": 0.8 + } + ], + "colW": 0.9, + "pitch": 1.6, + "cx": 0.0, + "cy": -2.75 + }, + "concl:0": { + "kind": "text", + "text": "8 次 push,只搬了 4 格", + "x": 0.0, + "y": -2.084, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 3.3888, + "h": 0.3264 + }, + "concl:1": { + "kind": "text", + "text": "容量一路翻倍 → 搬迁总和 < 2 × push 次数", + "x": 0.0, + "y": -2.6604, + "fs": 0.24, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 6.2016, + "h": 0.3264 + }, + "concl:2": { + "kind": "text", + "text": "所以 push_back 摊还 O(1)", + "x": 0.0, + "y": -3.2368, + "fs": 0.24, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 3.648, + "h": 0.3264 + } + }, + "steps": [ + { + "kind": "intro", + "label": "开场", + "note": "", + "duration": 5.8, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "title", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "fadein", + "target": "sub", + "t": 2.4, + "dur": 0.5 + }, + { + "type": "fadein", + "target": "counter", + "t": 2.4, + "dur": 0.5 + }, + { + "type": "write", + "target": "_empty", + "t": 3.4, + "dur": 1.07 + }, + { + "type": "fadeout", + "target": "_empty", + "t": 5.5, + "dur": 0.3 + } + ] + }, + { + "kind": "grow_to", + "label": "申请 4", + "note": "capacity 0->4, 搬 0 格", + "duration": 6.15, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "row:row", + "g": { + "kind": "cells", + "cap": 4, + "side": 0.62, + "cx": 0.0, + "cy": -1.0, + "w": 2.66, + "h": 0.62, + "cells": [ + { + "i": 0, + "x": -1.02, + "y": -1.0, + "s": 0.62 + }, + { + "i": 1, + "x": -0.34, + "y": -1.0, + "s": 0.62 + }, + { + "i": 2, + "x": 0.34, + "y": -1.0, + "s": 0.62 + }, + { + "i": 3, + "x": 1.02, + "y": -1.0, + "s": 0.62 + } + ], + "idx": [] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "fadeout", + "target": "_cap_row", + "t": 5.6, + "dur": 0.3 + }, + { + "type": "counter", + "text": "size = 0 capacity = 4", + "t": 5.9, + "dur": 0.25 + } + ] + }, + { + "kind": "push", + "label": "push ×4 (slow)", + "note": "[0,4)", + "duration": 1.2, + "speed": 0.6, + "events": [ + { + "type": "fill", + "target": "row:row", + "i": 0, + "s": 1, + "cap": 4, + "counter": true, + "t": 0.0, + "dur": 0.3 + }, + { + "type": "fill", + "target": "row:row", + "i": 1, + "s": 2, + "cap": 4, + "counter": true, + "t": 0.3, + "dur": 0.3 + }, + { + "type": "fill", + "target": "row:row", + "i": 2, + "s": 3, + "cap": 4, + "counter": true, + "t": 0.6, + "dur": 0.3 + }, + { + "type": "fill", + "target": "row:row", + "i": 3, + "s": 4, + "cap": 4, + "counter": true, + "t": 0.9, + "dur": 0.3 + } + ] + }, + { + "kind": "grow_to", + "label": "扩容 4→8", + "note": "capacity 4->8, 搬 4 格", + "duration": 11.05, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row_4", + "indicate": "row:row", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "_grow4:row", + "g": { + "kind": "cells", + "cap": 8, + "side": 0.5, + "cx": 0.0, + "cy": -3.51, + "w": 4.42, + "h": 0.5, + "cells": [ + { + "i": 0, + "x": -1.96, + "y": -3.51, + "s": 0.5 + }, + { + "i": 1, + "x": -1.4, + "y": -3.51, + "s": 0.5 + }, + { + "i": 2, + "x": -0.84, + "y": -3.51, + "s": 0.5 + }, + { + "i": 3, + "x": -0.28, + "y": -3.51, + "s": 0.5 + }, + { + "i": 4, + "x": 0.28, + "y": -3.51, + "s": 0.5 + }, + { + "i": 5, + "x": 0.84, + "y": -3.51, + "s": 0.5 + }, + { + "i": 6, + "x": 1.4, + "y": -3.51, + "s": 0.5 + }, + { + "i": 7, + "x": 1.96, + "y": -3.51, + "s": 0.5 + } + ], + "idx": [] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "relocate", + "src": "row:row", + "dst": "_grow4:row", + "count": 4, + "t": 3.1, + "dur": 1.0 + }, + { + "type": "row_destroy", + "target": "row:row", + "write": "_raii_row_4", + "t": 4.1, + "dur": 2.4 + }, + { + "type": "fadeout", + "target": "_cap_row_4", + "t": 9.7, + "dur": 0.3 + }, + { + "type": "fadeout", + "target": "_raii_row_4", + "t": 10.0, + "dur": 0.3 + }, + { + "type": "row_swap", + "target": "row:row", + "tmp": "_grow4:row", + "to": [ + 0.0, + -1.0 + ], + "t": 10.3, + "dur": 0.5 + }, + { + "type": "counter", + "text": "size = 4 capacity = 8", + "t": 10.8, + "dur": 0.25 + } + ] + }, + { + "kind": "push", + "label": "push ×4 (fast)", + "note": "[4,8)", + "duration": 0.4, + "speed": 1.8, + "events": [ + { + "type": "fill", + "target": "row:row", + "i": 4, + "s": 5, + "cap": 8, + "counter": true, + "t": 0.0, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 5, + "s": 6, + "cap": 8, + "counter": true, + "t": 0.1, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 6, + "s": 7, + "cap": 8, + "counter": true, + "t": 0.2, + "dur": 0.1 + }, + { + "type": "fill", + "target": "row:row", + "i": 7, + "s": 8, + "cap": 8, + "counter": true, + "t": 0.3, + "dur": 0.1 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "0.4s", + "duration": 0.4, + "speed": 1.0, + "events": [] + }, + { + "kind": "highlight", + "label": "高亮 [0,8) green", + "note": "", + "duration": 1.6, + "speed": 1.0, + "events": [ + { + "type": "hl_show", + "frame": { + "kind": "frame", + "color": "#7BC96A", + "cx": 0.0, + "cy": -1.0, + "w": 4.52, + "h": 0.6 + }, + "t": 0.0, + "dur": 0.4 + }, + { + "type": "hl_hide", + "frame": { + "kind": "frame", + "color": "#7BC96A", + "cx": 0.0, + "cy": -1.0, + "w": 4.52, + "h": 0.6 + }, + "t": 1.3, + "dur": 0.3 + } + ] + }, + { + "kind": "show", + "label": "show lb_note", + "note": "", + "duration": 1.67, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "show:lb_note", + "t": 0.0, + "dur": 1.67 + } + ] + }, + { + "kind": "show", + "label": "show bars", + "note": "", + "duration": 0.8, + "speed": 1.0, + "events": [ + { + "type": "bars_show", + "target": "show:bars", + "t": 0.0, + "dur": 0.8 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "1.2s", + "duration": 1.2, + "speed": 1.0, + "events": [] + }, + { + "kind": "conclude", + "label": "结论", + "note": "压轴结论墙", + "duration": 15.07, + "speed": 1.0, + "events": [ + { + "type": "fadeout", + "target": "show:bars", + "t": 0.0, + "dur": 0.3 + }, + { + "type": "fadeout", + "target": "show:lb_note", + "t": 0.3, + "dur": 0.3 + }, + { + "type": "write", + "target": "concl:0", + "t": 0.6, + "dur": 2.27 + }, + { + "type": "write", + "target": "concl:1", + "t": 3.22, + "dur": 2.4 + }, + { + "type": "write", + "target": "concl:2", + "t": 5.97, + "dur": 2.4 + }, + { + "type": "pulse", + "target": "counter", + "t": 12.07, + "dur": 1.0 + } + ] + } + ] +} diff --git a/site/.vitepress/theme/components/animations/data/vocab_boundary.json b/site/.vitepress/theme/components/animations/data/vocab_boundary.json new file mode 100644 index 000000000..1124cb0c4 --- /dev/null +++ b/site/.vitepress/theme/components/animations/data/vocab_boundary.json @@ -0,0 +1,689 @@ +{ + "version": 1, + "id": "vocab_boundary", + "title": "析构边界:多杀一格是 UB,少杀一格是泄漏", + "subtitle": "为什么笔者每次都掰手指数格子", + "source": "examples/vocab_boundary.yaml", + "backend": "web", + "frame": { + "w": 14.2222, + "h": 8.0 + }, + "palette": { + "bg": "#17171f", + "text": "#ECECE4", + "muted": "#9a9aad", + "fill": "#5EC8E0", + "fillEdge": "#2E86AB", + "emptyEdge": "#4a4a5e", + "grow": "#FFB454", + "numOnFill": "#0e2430", + "ok": "#7BC96A", + "bad": "#E06C75", + "cardBg": "#1e1e2a" + }, + "actors": { + "title": { + "kind": "text", + "text": "析构边界:多杀一格是 UB,少杀一格是泄漏", + "x": 0.0, + "y": 3.4324, + "fs": 0.32, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 8.1984, + "h": 0.4352 + }, + "sub": { + "kind": "text", + "text": "为什么笔者每次都掰手指数格子", + "x": 0.0, + "y": 2.8988, + "fs": 0.2, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 3.696, + "h": 0.272 + }, + "counter": { + "kind": "text", + "text": "size = 0 capacity = 0", + "x": 0.0, + "y": 1.6, + "fs": 0.3, + "color": "#ECECE4", + "mono": true, + "anchor": "middle", + "w": 4.752, + "h": 0.3 + }, + "_empty": { + "kind": "text", + "text": "还没申请内存", + "x": 0.0, + "y": -1.0, + "fs": 0.2, + "color": "#9a9aad", + "mono": false, + "anchor": "middle", + "w": 1.584, + "h": 0.272 + }, + "_cap_row": { + "kind": "text", + "text": "申请内存: capacity 0 → 4", + "x": 0.0, + "y": 0.1632, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 3.816, + "h": 0.3264 + }, + "row:row": { + "kind": "cells", + "cap": 4, + "side": 0.62, + "cx": 0.0, + "cy": -1.0, + "w": 2.66, + "h": 0.62, + "cells": [ + { + "i": 0, + "x": -1.02, + "y": -1.0, + "s": 0.62 + }, + { + "i": 1, + "x": -0.34, + "y": -1.0, + "s": 0.62 + }, + { + "i": 2, + "x": 0.34, + "y": -1.0, + "s": 0.62 + }, + { + "i": 3, + "x": 1.02, + "y": -1.0, + "s": 0.62 + } + ], + "idx": [ + 1, + 2, + 3, + 4 + ] + }, + "ptr:p_begin": { + "kind": "ptr", + "id": "p_begin", + "name": "begin", + "above": true, + "x": -1.02, + "tipY": -0.45, + "baseY": -0.06, + "txt": { + "text": "begin", + "x": -1.02, + "y": 0.1, + "fs": 0.22, + "color": "#ECECE4", + "mono": true, + "anchor": "middle", + "w": 0.726, + "h": 0.22 + }, + "cx": -1.02, + "cy": -0.12, + "w": 0.726, + "h": 0.66 + }, + "ptr:p_end": { + "kind": "ptr", + "id": "p_end", + "name": "end", + "above": true, + "x": 1.02, + "tipY": -0.45, + "baseY": -0.06, + "txt": { + "text": "end", + "x": 1.02, + "y": 0.1, + "fs": 0.22, + "color": "#ECECE4", + "mono": true, + "anchor": "middle", + "w": 0.4356, + "h": 0.22 + }, + "cx": 1.02, + "cy": -0.12, + "w": 0.4356, + "h": 0.66 + }, + "show:lb_ok": { + "kind": "text", + "text": "该析构的:恰好这三格", + "x": -0.34, + "y": -1.796, + "fs": 0.2, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 2.64, + "h": 0.272, + "id": "lb_ok" + }, + "show:lb_bad": { + "kind": "text", + "text": "多杀一格 = 对未构造内存调析构(UB)", + "x": 1.02, + "y": -1.796, + "fs": 0.2, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 4.58, + "h": 0.272, + "id": "lb_bad" + }, + "show:code": { + "kind": "code", + "fs": 0.2, + "lh": 0.258, + "pitch": 0.478, + "gutW": 0.1056, + "bodyW": 4.62, + "w": 5.5456, + "h": 2.69, + "rows": [ + { + "text": "~Vector() {", + "w": 1.452 + }, + { + "text": " helper::DestroySources(", + "w": 3.3 + }, + { + "text": " buffer_.data(),", + "w": 2.508 + }, + { + "text": " buffer_.data() + current_cnt_);", + "w": 4.62 + }, + { + "text": "}", + "w": 0.132 + } + ], + "cx": 4.2683, + "cy": -0.68 + }, + "concl:0": { + "kind": "text", + "text": "析构区间 = [data, data + current_cnt_)", + "x": 0.0, + "y": -2.084, + "fs": 0.24, + "color": "#FFB454", + "mono": false, + "anchor": "middle", + "w": 5.7312, + "h": 0.3264 + }, + "concl:1": { + "kind": "text", + "text": "多杀一格 UB,少杀一格泄漏", + "x": 0.0, + "y": -2.6604, + "fs": 0.24, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 3.9312, + "h": 0.3264 + }, + "concl:2": { + "kind": "text", + "text": "内存归还交给 RawBuffer 的 RAII", + "x": 0.0, + "y": -3.2368, + "fs": 0.24, + "color": "#ECECE4", + "mono": false, + "anchor": "middle", + "w": 4.5984, + "h": 0.3264 + } + }, + "steps": [ + { + "kind": "intro", + "label": "开场", + "note": "", + "duration": 5.8, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "title", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "fadein", + "target": "sub", + "t": 2.4, + "dur": 0.5 + }, + { + "type": "fadein", + "target": "counter", + "t": 2.4, + "dur": 0.5 + }, + { + "type": "write", + "target": "_empty", + "t": 3.4, + "dur": 1.07 + }, + { + "type": "fadeout", + "target": "_empty", + "t": 5.5, + "dur": 0.3 + } + ] + }, + { + "kind": "grow_to", + "label": "申请 4", + "note": "capacity 0->4, 搬 0 格", + "duration": 6.15, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "_cap_row", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "row_create", + "target": "row:row", + "g": { + "kind": "cells", + "cap": 4, + "side": 0.62, + "cx": 0.0, + "cy": -1.0, + "w": 2.66, + "h": 0.62, + "cells": [ + { + "i": 0, + "x": -1.02, + "y": -1.0, + "s": 0.62 + }, + { + "i": 1, + "x": -0.34, + "y": -1.0, + "s": 0.62 + }, + { + "i": 2, + "x": 0.34, + "y": -1.0, + "s": 0.62 + }, + { + "i": 3, + "x": 1.02, + "y": -1.0, + "s": 0.62 + } + ], + "idx": [ + 1, + 2, + 3, + 4 + ] + }, + "t": 2.4, + "dur": 0.7 + }, + { + "type": "fadeout", + "target": "_cap_row", + "t": 5.6, + "dur": 0.3 + }, + { + "type": "counter", + "text": "size = 0 capacity = 4", + "t": 5.9, + "dur": 0.25 + } + ] + }, + { + "kind": "push", + "label": "push ×3 (slow)", + "note": "[0,3)", + "duration": 0.9, + "speed": 0.6, + "events": [ + { + "type": "fill", + "target": "row:row", + "i": 0, + "s": 1, + "cap": 4, + "counter": true, + "t": 0.0, + "dur": 0.3 + }, + { + "type": "fill", + "target": "row:row", + "i": 1, + "s": 2, + "cap": 4, + "counter": true, + "t": 0.3, + "dur": 0.3 + }, + { + "type": "fill", + "target": "row:row", + "i": 2, + "s": 3, + "cap": 4, + "counter": true, + "t": 0.6, + "dur": 0.3 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "0.3s", + "duration": 0.3, + "speed": 1.0, + "events": [] + }, + { + "kind": "point_to", + "label": "指针 begin 出场", + "note": "index 0", + "duration": 0.4, + "speed": 1.0, + "events": [ + { + "type": "ptr_show", + "target": "p_begin", + "t": 0.0, + "dur": 0.4 + } + ] + }, + { + "kind": "point_to", + "label": "指针 end 出场", + "note": "index 3", + "duration": 0.4, + "speed": 1.0, + "events": [ + { + "type": "ptr_show", + "target": "p_end", + "t": 0.0, + "dur": 0.4 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "0.4s", + "duration": 0.4, + "speed": 1.0, + "events": [] + }, + { + "kind": "highlight", + "label": "高亮 [0,3) green", + "note": "", + "duration": 1.6, + "speed": 1.0, + "events": [ + { + "type": "hl_show", + "frame": { + "kind": "frame", + "color": "#7BC96A", + "cx": -0.34, + "cy": -1.0, + "w": 2.08, + "h": 0.72 + }, + "t": 0.0, + "dur": 0.4 + }, + { + "type": "hl_hide", + "frame": { + "kind": "frame", + "color": "#7BC96A", + "cx": -0.34, + "cy": -1.0, + "w": 2.08, + "h": 0.72 + }, + "t": 1.3, + "dur": 0.3 + } + ] + }, + { + "kind": "show", + "label": "show lb_ok", + "note": "", + "duration": 1.55, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "show:lb_ok", + "t": 0.0, + "dur": 1.55 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "1.0s", + "duration": 1.0, + "speed": 1.0, + "events": [] + }, + { + "kind": "hide", + "label": "hide lb_ok", + "note": "", + "duration": 0.95, + "speed": 1.0, + "events": [ + { + "type": "fadeout", + "target": "show:lb_ok", + "t": 0.55, + "dur": 0.4 + } + ] + }, + { + "kind": "highlight", + "label": "高亮 [3,4) red", + "note": "", + "duration": 1.6, + "speed": 1.0, + "events": [ + { + "type": "hl_show", + "frame": { + "kind": "frame", + "color": "#E06C75", + "cx": 1.02, + "cy": -1.0, + "w": 0.72, + "h": 0.72 + }, + "t": 0.0, + "dur": 0.4 + }, + { + "type": "hl_hide", + "frame": { + "kind": "frame", + "color": "#E06C75", + "cx": 1.02, + "cy": -1.0, + "w": 0.72, + "h": 0.72 + }, + "t": 1.3, + "dur": 0.3 + } + ] + }, + { + "kind": "show", + "label": "show lb_bad", + "note": "", + "duration": 2.4, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "show:lb_bad", + "t": 0.0, + "dur": 2.4 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "1.0s", + "duration": 1.0, + "speed": 1.0, + "events": [] + }, + { + "kind": "hide", + "label": "hide lb_bad", + "note": "", + "duration": 2.6, + "speed": 1.0, + "events": [ + { + "type": "fadeout", + "target": "show:lb_bad", + "t": 2.2, + "dur": 0.4 + } + ] + }, + { + "kind": "show", + "label": "show code", + "note": "", + "duration": 2.8, + "speed": 1.0, + "events": [ + { + "type": "code_show", + "target": "show:code", + "t": 0.0, + "dur": 2.8 + } + ] + }, + { + "kind": "wait", + "label": "停顿", + "note": "1.2s", + "duration": 1.2, + "speed": 1.0, + "events": [] + }, + { + "kind": "hide", + "label": "hide code", + "note": "", + "duration": 0.75, + "speed": 1.0, + "events": [ + { + "type": "fadeout", + "target": "show:code", + "t": 0.35, + "dur": 0.4 + } + ] + }, + { + "kind": "conclude", + "label": "结论", + "note": "压轴结论墙", + "duration": 14.98, + "speed": 1.0, + "events": [ + { + "type": "write", + "target": "concl:0", + "t": 0.0, + "dur": 2.4 + }, + { + "type": "write", + "target": "concl:1", + "t": 2.75, + "dur": 2.03 + }, + { + "type": "write", + "target": "concl:2", + "t": 5.13, + "dur": 2.4 + }, + { + "type": "pulse", + "target": "counter", + "t": 11.98, + "dur": 1.0 + } + ] + } + ] +} diff --git a/site/.vitepress/theme/custom.css b/site/.vitepress/theme/custom.css index 05fe389fd..bdc3921bf 100644 --- a/site/.vitepress/theme/custom.css +++ b/site/.vitepress/theme/custom.css @@ -2052,3 +2052,12 @@ body.rs-resizing { .dark .vp-doc img { box-shadow: 0 2px 12px rgba(0, 0, 0, 0.25); } + +/* ── drawio viewer ──────────────────────────────────────────────── */ + +/* 工具条(缩放/全屏)是绝对定位, 容器必须建立定位上下文; 否则锚到页面级 + 定位祖先, 悬浮到图外压住正文(@dhlx/vitepress-plugin-drawio 容器默认无 + position, 全站 26 张 drawio 共用此修复) */ +.mxgraph { + position: relative; +} diff --git a/site/.vitepress/theme/index.ts b/site/.vitepress/theme/index.ts index 119aa90f4..3c8f5306a 100644 --- a/site/.vitepress/theme/index.ts +++ b/site/.vitepress/theme/index.ts @@ -20,6 +20,7 @@ import { setupMermaid } from './mermaid-client' import MermaidLightbox from './components/MermaidLightbox.vue' import NavSpinner from './components/NavSpinner.vue' import QQGroupCard from './components/QQGroupCard.vue' +import Anim from './components/Anim.vue' import { setupDevFakeLag } from './dev-fake-lag' import './custom.css' @@ -51,5 +52,6 @@ export default { app.component('ReferenceItem', ReferenceItem) app.component('OnlineCompilerDemo', OnlineCompilerDemo) app.component('QQGroupCard', QQGroupCard) + app.component('Anim', Anim) } } satisfies Theme