diff --git a/Readme(Chinese_Version).md b/Readme(Chinese_Version).md new file mode 100644 index 0000000..58b501e --- /dev/null +++ b/Readme(Chinese_Version).md @@ -0,0 +1,445 @@ +# ticketmap + +## 1. 简介 + +**一个具有强大功能的容器** + +它是作者开发出来的一个扩展库 + +[^陈佳宇]: 拿到这个项目刚开始以为是邮票地图?再参阅了文档、调试环境去运行后,发现它其实是一个非常酷的容器,类似map, unordered_map,一个全新的map + + + +## 2. 功能特点 + +1. 自动键功能管理:自动为每个新插入的元素分配唯一的键(票号)。 +2. 键溢出处理:当键类型达到最大值时,能够检测溢出并抛出异常。 +3. 迭代器支持:提供迭代器以遍历容器中的所有元素。 +4. 容量管理:可以预留足够的空间以存储指定数量的元素。 +5. 异常处理:在遇到错误情况(如键溢出)时抛出异常。 + + + +## 3. ticketmap的定义及方法 + +**ticketmap的定义同map, unordered_map一样** + +~~~cpp +// 声明 +ticket_map 变量名; +~~~ + +**方法:** +~~~cpp +// insert("值") -- 给键插入值 +auto 键 = 变量名.insert(值); +// 例 +auto ticket = map.insert("Hello World!"); +cout << ticket << endl; +// 这里输出0 因为ticket从0自增 +cout << map[ticket] ; +// 这里会输出答案值:Hello World! +~~~ + +~~~cpp +// map.begin() - 返回迭代器的第一个参数 + +auto one = map.insert("one"); +auto two = map.insert("two"); +auto three = map.insert("three"); + +cout << map.begin().ticket << ' ' << map.begin().value << endl; +// 答案输出为 0 one. 因为是添加的第一个键和它的值 +~~~ + + + +## 4. 使用示例 + + + +```markdown +#include "ticket_map.hpp" +#include + +// 个人习惯:使用命名空间简写代码 +using namespace jss; // jss::ticket_map 变为 ticket_map +using namespace std; // std::cout 变为 cout + +int main() { + // 创建一个 ticket_map 实例,键类型为 int,值类型为 string + ticket_map map; + + // 插入元素并获取分配的票号 + auto ticket = map.insert("Hello, World!"); + cout << "Inserted with ticket: " << ticket << endl; + + // 通过票号访问元素 + cout << "Value: " << map[ticket] << endl; + + // 遍历容器中的所有元素 + for (const auto& entry : map) { + cout << "Ticket: " << entry.ticket << ", Value: " << entry.value << endl; + } + + return 0; +} +``` + +**运行结果:** + +![1745249897527](/imges/run_problem1.png) + + + +## 5. 运行时候出现的小问题 + +**第一次在运行的时候出现一个小问题(图1)** + +![1745248916445](/imges/run_problem1.png) + +**利用Kimi找到了解决这个问题的办法** + +![1745249350575](/imges/run_solution.png) + + + +## 6. 环境配置 + +- 该项目作为c++的一个拓展项目并不需要配置什么环境,只需要提供能编译G++17的编译器 + +- 只要把项目拉取下来,然后在编译的c++文件中去导入这个库,即可使用 + +- 如果直接拉取不可以的话或许是没有配置MinGW,这边我使用的是Clion,下载Clion会自带默认MinGW,如果还出现报错的话,那就把进入到MinGW的bin目录当中把地址复制到环境变量->系统变量->path中去配置 + + + +## 7.翻译 + +### 1~80行(管理单调递增的 ID 与对应值之间的映射关系) + +```cpp +// This code is released under the Boost Software License +// https://www.boost.org/LICENSE_1_0.txt +// (C) Copyright 2021 Anthony Williams + +// 此代码根据 Boost 软件许可证发布 +// https://www.boost.org/LICENSE_1_0.txt +// (C) 版权所有 2021 Anthony Williams +``` + +```cpp +/// A map between from Ticket values to Value values. +/// +/// Ticket must be default-constructible, incrementable, less-than +/// comparable and equality-comparable. Value must be move-constructible +/// +/// When new values are inserted they are assigned new Ticket values +/// automatically. If the Ticket value overflows then no more values can be +/// inserted. + +/// 一个从票证值到值之间的映射。 + +/// +/// 票证类型(Ticket)必须是可默认构造的、可递增的、可进行小于比较的以及可进行相等比较的。值类型(Value)必须是可移动构造的。 +/// +/// 当插入新值时,它们会自动被分配新的票证值。如果票证值溢出,那么就不能再插入更多的值。 +``` + +template class ticket_map { + static_assert( + std::is_default_constructible(), + "票证类型(Ticket)必须是可默认构造的"); + static_assert ( + std::is_same_v()++), Ticket>, + "票证类型(Ticket)必须是可后置递增的"); + static_assert ( + std::is_same_v< + decltype (std::declval() < std::declval()), + bool>, + "票证类型(Ticket)必须是可进行小于比较的"); + static_assert ( + std::is_same_v< + decltype (std::declval() == std::declval()), + bool>, + "票证类型(Ticket)必须是可进行相等比较的"); + static_assert ( + std::is_same_v< + decltype (std::declval() != std::declval()), + bool>, + "票证类型(Ticket)必须是可进行不等比较的"); + + + +```cpp +/// The type of the actual storage +/// 实际存储的类型 +``` + + + + using collection_type= + std::vector>>; + +```cpp +/// The iterator for our map +/// 我们映射的迭代器 +``` + + + + template class iterator_impl { + using dereference_type= + std::conditional_t; + + +```cpp +public: + /// The value_type of our iterator is a ticket/value pair. We use + /// references, since the underlying storage doesn't hold the same + /// member types + struct value_type { + /// A reference to the ticket value for this element + Ticket const &ticket; + /// A reference to the data value for this element + dereference_type value; + }; +public: + /// 我们迭代器的 value_type 是一个票证 / 值对。我们使用引用,因为底层存储并不持有相同的成员类型 + struct value_type { + /// 对此元素的票证值的引用 + Ticket const &ticket; + /// 对此元素的数据值的引用 + dereference_type value; + }; +``` + +```cpp +private: + /// It's an input iterator, so we need a proxy for -> + struct arrow_proxy { + /// Our proxy operator-> + value_type *operator->() noexcept { + return &value; + } + /// The pointed-to value + value_type value; + }; +private: + /// 它是一个输入迭代器,所以我们需要一个用于 -> 的代理 + struct arrow_proxy { + /// 我们的代理操作符 -> + value_type *operator->() noexcept { + return &value; + } + /// 被指向的值 + value_type value; + }; +``` + + + + + +### 80~125行(类型定义注释) +- `Required iterator typedefs` + `所需的迭代器类型定义` +- `Compare iterators for inequality.` + `比较迭代器是否不相等` +- `Equality in terms of iterator_impls: if it's not not-equal then it must be equal` + `就迭代器实现而言的相等性:如果不是不相等,那么它必须相等` +- `Dereference the iterator` + `取消引用迭代器` +- `Dereference for iter->m` + `对 iter->m 进行解引用(即通过指针/迭代器访问成员 m)` +- `Pre-increment` + `前置递增` +- `Post-increment` + `后增量` + +--- + +### 127~138行(构造方法注释) +- `Allow constructing a const_iterator from a non-const iterator, but not vice-versa` + `允许从非const迭代器构造const迭代器,但反之不可。` +- `A default-constructed iterator is a sentinel value` + `默认构造的迭代器是一个哨兵值` + +--- + +### 140~160行(实现细节注释) +- `Construct from an iterator into a map` + `通过迭代器构造映射` +- `The stored iterator` + `存储的迭代器` +- `The map` + `映射` + +--- + +### 80~160行中代码特殊实现说明 +- `arrow_proxy operator->()` + `通过指针代理访问元素成员(实现 iter->m 语法)` +- `underlying_iterator` 类型说明 + `底层容器迭代器(根据 is_const 选择 const/non-const 版本)` +- `map_ptr` 类型说明 + `指向所属容器的指针` + + + +### 240-320行代码翻译 +### 插入操作注释 +- `Insert a new value into the map, directly constructing in place. It is assigned a new ticket value. Returns the ticket for the new entry. Invalidates any existing iterators into the map. Throws overflow_error if the Ticket values have overflowed.` + `插入一个新值到映射中,在原地直接构造。它会被分配一个新的票据值。返回新条目的票据。会使映射中现有的任何迭代器失效。如果票据值已溢出,则抛出溢出异常。` + +### 查找操作注释 +- `Find a value in the map by its ticket. Returns an iterator referring to the found element, or end() if no element could be found` + `通过票证在映射中查找值。返回指向找到元素的迭代器,如果未找到元素则返回 end()` + +- `Find a value in the map by its ticket. Returns a reference to the found element. Throws std:out_of_range if the value was not present.` + `通过票证在映射中查找值。返回指向找到元素的引用。如果值不存在,则抛出 std::out_of_range 异常。` + +### 迭代器操作注释 +- `Returns an iterator to the first element, or end() if the container is empty` + `返回指向第一个元素的迭代器,如果容器为空则返回 end()` + +- `Returns an iterator one-past-the-end of the container` + `返回指向容器末尾后一个元素的 const_iterator` + +- `Returns a const_iterator to the first element, or end() if the container is empty` + `返回指向第一个元素的 const_iterator。如果容器为空则返回 cend()` + +- `Returns a const_iterator one-past-the-end of the container` + `返回指向容器末尾后一个元素的 const_iterator` +### 删除操作注释 +- `Remove an element with the specified ticket. Returns an iterator to the next element if there is one, or end() otherwise. Returns end() if there was no element with the specified ticket. Invalidates any existing iterators into the map. Compacts the data if there are too many empty slots.` + `删除具有指定票证的元素。如果存在下一个元素,则返回指向下一个元素的迭代器,否则返回 end()。如果未找到具有指定票证的元素,则返回 end()。删除元素会使得所有现有的映射迭代器失效。如果存在过多的空闲槽位,则压缩数据。` + +### 特殊机制注释 +- `Invalidates any existing iterators` + `会使现有迭代器失效` +- `Throws overflow_error` + `抛出溢出异常` +- `Compacts the data` + `压缩数据` + + + +### 400-480行翻译 +1. Return the maximum number of items that can be inserted without + reallocating +**返回在不需要重新分配内存的情况下可以插入的最大项目数。** +2. Return the number of entries for a ticket in the container. Thereturn value is 1 if the ticket is in the container, 0 otherwise. +**返回容器中票证的条目数量。如果票证在容器中,则返回值为1,否则为0。** +3. Erase an entry referenced by an iterator into the internal vector +**删除内部向量中由迭代器引用的条目** +4. Returns true if the container has too many empty slot, falseotherwise +**如果容器中有太多空槽,则返回true,否则返回false。** +5. Compact the container to remove all empty slots. +**压缩容器以移除所有空槽** +6. Increment a ticket and check for overflow (generic) +**增加票证并检查溢出(通用)** +
+ + +# 原Readme翻译 + +## 票证映射 + +我遇到了一个越来越常见的场景:你有一些单调递增的 ID,比如订阅号、连接索引或用户 ID,并且你的 C++ 程序需要保存与该 ID 值相关联的一些数据。然后,程序可以传递这个 ID,并在稍后使用该 ID 来访问相关数据。 + +随着时间的推移,ID 可能会失效,因此与该值相关联的数据会被移除,最终你会得到一组稀疏的当前活动 ID。因此,你自然会倾向于使用一个映射(无论是`std::map`、`std::unordered_map`还是其他自定义映射)来将数据与 ID 关联起来。 + +通常,这样的映射是作为基于节点的容器实现的,这意味着节点可能会被分配到不同的内存地址,这对缓存性能不利。添加和删除节点也总是需要进行内存分配 / 释放操作。 + +在他的["更好的代码:关系"](https://sean-parent.stlab.cc/papers-and-presentations/#better-code-relationships)演讲中,Sean Parent 描述了一种替代实现,他称之为 "俄罗斯大衣寄存算法"。在这个算法中,映射被实现为一个键 / 可选数据对的向量。因为键来自单调递增的索引,所以向量*始终是有序的*,并且插入总是在末尾进行。条目可以通过清除数据来删除,如果有太多空条目,则可以压缩向量。查找总是很快,因为向量始终是有序的,所以简单的二分查找就能找到正确的元素。 + +这个库是该算法的一个实现,我称之为*票证映射*:它将一个*票证*映射到一个*值*。当你插入一个值时,它会被分配下一个可用的票证值。你可以稍后使用该票证来访问或删除该值。 + + + +## 许可证 + +本代码根据[Boost 软件许可证](https://www.boost.org/LICENSE_1_0.txt)发布: + +> Boost 软件许可证 - 版本 1.0 - 2003 年 8 月 17 日 +> +> 特此免费授予任何获得本许可证所涵盖的软件及随附文档("软件")的个人或组织使用、复制、展示、分发、执行和传输该软件的权利,并允许其准备该软件的衍生作品,并允许向其提供软件的第三方也这样做,但需遵守以下规定: +> +> 软件中的版权声明和本完整声明(包括上述许可证授予、本限制和以下免责声明)必须包含在软件的所有副本(全部或部分)以及软件的所有衍生作品中,除非此类副本或衍生作品仅以由源语言处理器生成的机器可执行目标代码的形式存在。 +> +> 软件按 "原样" 提供,不提供任何形式的保证,无论是明示的还是暗示的,包括但不限于适销性、特定用途适用性、标题和不侵权的保证。在任何情况下,版权持有人或任何分发软件的人对于任何损害或其他责任(无论是合同责任、侵权责任还是其他责任)概不负责,无论该责任是因软件或其使用或其他交易而产生、源于或与之相关。 + + + + + +### 标准迭代器类型定义 +- ` Standard iterator typedef` + `标准迭代器类型定义` +- ` Standard const_iterator typedef ` +` 标准常量迭代器类型定义` + +### 空映射构造 +- ` Construct an empty map ` +`构造一个空映射` + +### 范围构造 +- ` Construct a map from a range of elements ` +`从元素范围构造映射` + +### 移动构造 +- `Move-construct from other. The elements of other are transferred to this; other is left empty 到 **this**` +`从其他对象移动构造。将其他对象的元素转移到新对象,原对象变为空` + +### 拷贝构造 +- `Copy-construct from other. this will have the same elements and next ticket value as other. ` +`从另一个对象复制构造。新对象包含与原对象相同的元素和下一个票证值` + +### 拷贝赋值 +- `Copy-assign from other ` +`拷贝赋值操作` + +### 移动赋值 +- `Move-assign from other ` +`移动赋值操作` + +### 成员函数 empty() +- `Returns true if there are no elements currently in the map, false otherwise` + `返回当前映射是否为空` + +### size() +- `Returns the number of elements currently in the map ` + `返回当前映射的元素数量` + +### insert(value) +- `Insert a new value into the map. It is assigned a new ticket value.` +`插入新值到映射。分配新票证值` +- ` Returns the ticket for the new entry. ` +`返回新条目的票证` +- `Invalidates any existing iterators into the map. ` +`使所有现有迭代器失效` +- `Throws overflow_error if the Ticket values have overflowed. ` +`票证溢出时抛出 overflow_error 异常` + +### insert(range) +- ` Insert a set of new values into the map. Each is assigned a new ticket value. ` +`批量插入新值。每个元素分配新票证值。` +- `Returns an iterator that references the first new or end() if no values were inserted. ` +`返回指向第一个新插入元素的迭代器(若无插入则返回 end())` +- `Invalidates any existing iterators into the map. ` +`使所有现有迭代器失效` +- `Throws overflow_error if the Ticket values have overflowed. ` +`票证溢出时抛出 overflow_error 异常` + +### emplace(args...) +- `Insert a new value into the map, directly constructing in place.` +`将一个新值插入映射中,并直接在原地构造。` +- `It is assigned a new ticket value. Returns the ticket for the new entry.` + `它被分配了一个新的票证值。返回新条目的票证。` +- ` Invalidates any existing iterators into the map. ` +`使所有现有迭代器失效` +- `Throws overflow_error if the Ticket values have overflowed. ` +`票证溢出时抛出 overflow_error 异常` + + \ No newline at end of file diff --git a/imges/2205308010325-1.png b/imges/2205308010325-1.png new file mode 100644 index 0000000..fb74d70 Binary files /dev/null and b/imges/2205308010325-1.png differ diff --git a/imges/2205308010325-2.png b/imges/2205308010325-2.png new file mode 100644 index 0000000..bc9bb7b Binary files /dev/null and b/imges/2205308010325-2.png differ diff --git a/imges/2205308010325-3.png b/imges/2205308010325-3.png new file mode 100644 index 0000000..57eb60e Binary files /dev/null and b/imges/2205308010325-3.png differ diff --git a/imges/2205308010345-1.png b/imges/2205308010345-1.png new file mode 100644 index 0000000..8fe4452 Binary files /dev/null and b/imges/2205308010345-1.png differ diff --git a/imges/2205308010345-2.png b/imges/2205308010345-2.png new file mode 100644 index 0000000..54fdb62 Binary files /dev/null and b/imges/2205308010345-2.png differ diff --git a/imges/2205308010345-3.png b/imges/2205308010345-3.png new file mode 100644 index 0000000..9774642 Binary files /dev/null and b/imges/2205308010345-3.png differ diff --git a/imges/2205308010358_3.png b/imges/2205308010358_3.png new file mode 100644 index 0000000..2aa4d87 Binary files /dev/null and b/imges/2205308010358_3.png differ diff --git a/imges/2205308010358__1.png b/imges/2205308010358__1.png new file mode 100644 index 0000000..988171f Binary files /dev/null and b/imges/2205308010358__1.png differ diff --git a/imges/2205308010358__2.png b/imges/2205308010358__2.png new file mode 100644 index 0000000..00fe8df Binary files /dev/null and b/imges/2205308010358__2.png differ diff --git a/imges/2208305020346-1.png b/imges/2208305020346-1.png new file mode 100644 index 0000000..3d494e4 Binary files /dev/null and b/imges/2208305020346-1.png differ diff --git a/imges/2208305020346-2.png b/imges/2208305020346-2.png new file mode 100644 index 0000000..352e8b4 Binary files /dev/null and b/imges/2208305020346-2.png differ diff --git a/imges/2208305020346-3.png b/imges/2208305020346-3.png new file mode 100644 index 0000000..66ec8f4 Binary files /dev/null and b/imges/2208305020346-3.png differ diff --git a/imges/2208305020346_1.png b/imges/2208305020346_1.png new file mode 100644 index 0000000..3d494e4 Binary files /dev/null and b/imges/2208305020346_1.png differ diff --git a/imges/2208305020346_2.png b/imges/2208305020346_2.png new file mode 100644 index 0000000..352e8b4 Binary files /dev/null and b/imges/2208305020346_2.png differ diff --git a/imges/2208305020346_3.png b/imges/2208305020346_3.png new file mode 100644 index 0000000..66ec8f4 Binary files /dev/null and b/imges/2208305020346_3.png differ diff --git "a/imges/limits\345\244\264\346\226\207\344\273\266\350\241\245\345\205\205.png" "b/imges/limits\345\244\264\346\226\207\344\273\266\350\241\245\345\205\205.png" new file mode 100644 index 0000000..415c62e Binary files /dev/null and "b/imges/limits\345\244\264\346\226\207\344\273\266\350\241\245\345\205\205.png" differ diff --git a/imges/run_problem1.png b/imges/run_problem1.png new file mode 100644 index 0000000..b2b975e Binary files /dev/null and b/imges/run_problem1.png differ diff --git a/imges/run_solution.png b/imges/run_solution.png new file mode 100644 index 0000000..afb79a2 Binary files /dev/null and b/imges/run_solution.png differ diff --git a/imges/solution.png b/imges/solution.png new file mode 100644 index 0000000..3766e2c Binary files /dev/null and b/imges/solution.png differ diff --git a/modification_log.md b/modification_log.md new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/modification_log.md @@ -0,0 +1 @@ + diff --git a/test.cpp b/test.cpp new file mode 100644 index 0000000..6f3c8cb --- /dev/null +++ b/test.cpp @@ -0,0 +1,24 @@ +// +// Created by JYC on 2025/4/22. +// +#include "/ticket_map.hpp" +#include + +int main() { + jss::ticket_map map; // 明确使用 jss:: 前缀 + + // 插入元素并获取分配的票号 + auto ticket = map.insert("Hello, World!"); + std::cout << "Inserted with ticket: " << ticket << std::endl; + + // 通过票号访问元素 + std::cout << "Value: " << map[ticket] << std::endl; + + // 遍历容器中的所有元素 + for (const auto& entry : map) { + std::cout << "Ticket: " << entry.ticket << ", Value: " << entry.value << std::endl; + } + + return 0; +} +// 陈佳宇 diff --git a/ticket_map.hpp b/ticket_map.hpp index 3cee92b..661698f 100644 --- a/ticket_map.hpp +++ b/ticket_map.hpp @@ -4,6 +4,7 @@ #pragma once +#include #include #include #include @@ -77,7 +78,7 @@ namespace jss { value_type value; }; - public: + public: /// Required iterator typedefs using reference= value_type; /// Required iterator typedefs @@ -158,15 +159,19 @@ namespace jss { }; public: - /// Standard iterator typedef + /// Standard iterator typedef、 + using iterator= iterator_impl; /// Standard const_iterator typedef + using const_iterator= iterator_impl; /// Construct an empty map + constexpr ticket_map() noexcept : nextId(), filledItems(0) {} /// Construct a map from a range of elements + template constexpr ticket_map(Iter first, Iter last) : ticket_map() { insert(first, last); @@ -174,21 +179,24 @@ namespace jss { /// Move-construct from other. The elements of other are transferred to /// *this; other is left empty + constexpr ticket_map(ticket_map &&other) noexcept : nextId(std::move(other.nextId)), data(std::move(other.data)), filledItems(std::move(other.filledItems)) { other.filledItems= 0; } /// Copy-construct from other. *this will have the same elements and - /// next ticket value as other. + constexpr ticket_map(ticket_map const &other)= default; /// Copy-assign from other + constexpr ticket_map &operator=(ticket_map const &other) { ticket_map temp(other); swap(temp); return *this; } /// Move-assign from other + constexpr ticket_map &operator=(ticket_map &&other) noexcept { ticket_map temp(std::move(other)); swap(temp); @@ -197,11 +205,13 @@ namespace jss { /// Returns true if there are no elements currently in the map, false /// otherwise + constexpr bool empty() const noexcept { return size() == 0; } /// Returns the number of elements currently in the map + constexpr std::size_t size() const noexcept { return filledItems; } @@ -210,6 +220,7 @@ namespace jss { /// Returns the ticket for the new entry. /// Invalidates any existing iterators into the map. /// Throws overflow_error if the Ticket values have overflowed. + constexpr Ticket insert(Value v) { return emplace(std::move(v)); } @@ -219,6 +230,7 @@ namespace jss { /// entry, or end() if no values were inserted. /// Invalidates any existing iterators into the map. /// Throws overflow_error if the Ticket values have overflowed. + template constexpr iterator insert(Iter first, Iter last) { auto const index= data.size(); @@ -232,6 +244,7 @@ namespace jss { /// is assigned a new ticket value. Returns the ticket for the new /// entry. Invalidates any existing iterators into the map. /// Throws overflow_error if the Ticket values have overflowed. + template constexpr Ticket emplace(Args &&... args) { if(overflow) throw std::overflow_error( @@ -249,57 +262,70 @@ namespace jss { /// Find a value in the map by its ticket. Returns an iterator referring /// to the found element, or end() if no element could be found + /// 通过票证在映射中查找值。返回指向找到元素的迭代器,如果未找到元素则返回 end() constexpr const_iterator find(const Ticket &ticket) const noexcept { return {lookup(data, ticket), this}; } /// Find a value in the map by its ticket. Returns an iterator referring /// to the found element, or end() if no element could be found + /// 通过票证在映射中查找值。返回指向找到元素的迭代器,如果未找到元素则返回 end() constexpr iterator find(const Ticket &ticket) noexcept { return {lookup(data, ticket), this}; } /// Find a value in the map by its ticket. Returns a reference to the /// found element. Throws std:out_of_range if the value was not present. + /// 通过票证在映射中查找值。返回指向找到元素的引用。 + ///如果值不存在,则抛出 std::out_of_range 异常。 constexpr Value &operator[](const Ticket &ticket) { return index(data, ticket); } /// Find a value in the map by its ticket. Returns a reference to the /// found element. Throws std:out_of_range if the value was not present. + /// 通过票证在映射中查找值。返回指向找到元素的引用。如果值不存在,则抛出 std::out_of_range 异常。 constexpr const Value &operator[](const Ticket &ticket) const { return index(data, ticket); } /// Returns an iterator to the first element, or end() if the container /// is empty + /// 返回指向第一个元素的迭代器,如果容器为空则返回 end() constexpr iterator begin() noexcept { return {next_valid(data.begin()), this}; } /// Returns an iterator one-past-the-end of the container + /// 返回指向容器末尾后一个元素的 const_iterator constexpr iterator end() noexcept { return {data.end(), this}; } /// Returns a const_iterator to the first element, or end() if the /// container is empty + /// 返回指向第一个元素的 const_iterator + ///如果容器为空则返回 cend() constexpr const_iterator begin() const noexcept { return {next_valid(data.begin()), this}; } /// Returns a const_iterator one-past-the-end of the container + /// 返回指向容器末尾后一个元素的 const_iterator constexpr const_iterator end() const noexcept { return {data.end(), this}; } /// Returns a const_iterator to the first element, or cend() if the /// container is empty + /// 返回指向第一个元素的 const_iterator + ///如果容器为空则返回 cend() constexpr const_iterator cbegin() const noexcept { return {next_valid(data.begin()), this}; } /// Returns a const_iterator one-past-the-end of the container + /// 返回指向容器末尾后一个元素的 const_iterator constexpr const_iterator cend() const noexcept { return {data.end(), this}; } @@ -309,6 +335,10 @@ namespace jss { /// if there was no element with the specified ticket. /// Invalidates any existing iterators into the map. /// Compacts the data if there are too many empty slots. + /// 删除具有指定票证的元素。如果存在下一个元素,则返回指向下一个元素的迭代器,否则返回 end()。 + ///如果未找到具有指定票证的元素,则返回 end()。 + ///删除元素会使得所有现有的映射迭代器失效。 + ///如果存在过多的空闲槽位,则压缩数据。 constexpr iterator erase(const Ticket &ticket) noexcept { return {erase_entry(lookup(data, ticket)), this}; } @@ -476,4 +506,4 @@ namespace std { jss::ticket_map &rhs) noexcept { lhs.swap(rhs); } -} // namespace std +} // namespace std \ No newline at end of file