diff --git a/Readme(Chinese_Version).md b/Readme(Chinese_Version).md new file mode 100644 index 0000000..f8bfa80 --- /dev/null +++ b/Readme(Chinese_Version).md @@ -0,0 +1,115 @@ +# 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中去配置 + + 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/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..825158d 100644 --- a/ticket_map.hpp +++ b/ticket_map.hpp @@ -4,6 +4,7 @@ #pragma once +#include #include #include #include @@ -76,18 +77,23 @@ namespace jss { /// The pointed-to value value_type value; }; - + public: /// Required iterator typedefs + // 所需的迭代器类型定义 using reference= value_type; /// Required iterator typedefs + ///所需的迭代器类型定义 using iterator_category= std::input_iterator_tag; /// Required iterator typedefs + ///所需的迭代器类型定义 using pointer= value_type *; /// Required iterator typedefs + ///所需的迭代器类型定义 using difference_type= void; /// Compare iterators for inequality. + ///比较迭代器是否不相等 friend bool operator!=( iterator_impl const &lhs, iterator_impl const &rhs) noexcept { return lhs.iter != rhs.iter; @@ -95,28 +101,34 @@ namespace jss { /// Equality in terms of iterator_impls: if it's not not-equal then /// it must be equal + /*就迭代器实现而言的相等性:如果不是不相等,那么 + 它必须相等*/ friend bool operator==( iterator_impl const &lhs, iterator_impl const &rhs) noexcept { return !(lhs != rhs); } /// Dereference the iterator + ///取消引用迭代器 const value_type operator*() const noexcept { return value_type{iter->first, *iter->second}; } /// Dereference for iter->m + ///对 iter->m 进行解引用(即通过指针/迭代器访问成员 m) arrow_proxy operator->() const noexcept { return arrow_proxy{value_type{iter->first, *iter->second}}; } /// Pre-increment + ///前置递增 iterator_impl &operator++() noexcept { iter= map->next_valid(++iter); return *this; } /// Post-increment + ///后增量 iterator_impl operator++(int) noexcept { iterator_impl temp{*this}; ++*this; @@ -125,6 +137,8 @@ namespace jss { /// Allow constructing a const_iterator from a non-const iterator, /// but not vice-versa + /*允许从非const迭代器构造const迭代器, + 但反之不可。*/ template < typename Other, typename= std::enable_if_t< @@ -134,6 +148,7 @@ namespace jss { iter(other.iter), map(other.map) {} /// A default-constructed iterator is a sentinel value + ///默认构造的迭代器是一个哨兵值 constexpr iterator_impl() noexcept= default; private: @@ -148,25 +163,32 @@ namespace jss { std::conditional_t; /// Construct from an iterator into a map + ///通过迭代器构造映射 constexpr iterator_impl(underlying_iterator iter_, map_ptr map_) : iter(std::move(iter_)), map(map_) {} /// The stored iterator + ///存储的迭代器​ underlying_iterator iter; /// The map + ///​​映射 map_ptr map; }; 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 +196,26 @@ 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. + /// next ticket value as other. +        /// 从另一个对象复制构造。`*this` 将具有相同的元素并且下一个票证值与另一个对象相同。 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 +224,14 @@ namespace jss { /// Returns true if there are no elements currently in the map, false /// otherwise + /// 如果当前映射中没有元素,则返回 `true`,否则返回 `false`。 +        /// 否则 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 +240,10 @@ 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. + /// 将一个新值插入映射中。它被分配了一个新的票证值。 +        /// 返回新条目的票证。 +        /// 使任何现有的映射迭代器失效 +        /// 如果票证值溢出,则抛出 `overflow_error`。 constexpr Ticket insert(Value v) { return emplace(std::move(v)); } @@ -219,6 +253,11 @@ 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. + /// 将一组新值插入映射中。每个值都被分配一个新票证值。 +        /// 返回一个迭代器,它引用第一个新条目, +        /// 或者如果没有任何值被插入,则返回 `end()`。 +        /// 使任何现有的映射迭代器失效。 +        /// 如果票证值溢出,则抛出 `overflow_error`。 template constexpr iterator insert(Iter first, Iter last) { auto const index= data.size(); @@ -232,6 +271,10 @@ 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. + /// 将一个新值插入映射中,并直接在原地构造。 +        /// 它被分配了一个新的票证值。返回新条目的票证。 +        /// 使任何现有的映射迭代器失效。 +        /// 如果票证值溢出,则抛出 `overflow_error`。 template constexpr Ticket emplace(Args &&... args) { if(overflow) throw std::overflow_error( @@ -249,57 +292,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 +365,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}; }