diff --git a/.clang-format b/.clang-format index 4702c3b..f8089cf 100644 --- a/.clang-format +++ b/.clang-format @@ -1,19 +1,151 @@ ---- -Language: Cpp -Standard: Latest +# ----------------------------------------------------------------------------- +# mcpp-community C++ Style Configuration +# +# This configuration follows the style specification defined in: +# https://github.com/mcpp-community/mcpp-style-ref +# +# Maintained by: mcpp-community +# ----------------------------------------------------------------------------- -IndentWidth: 4 # 缩进宽度:4空格 -TabWidth: 4 # Tab宽度:4空格 -UseTab: Never # 不使用Tab,只用空格 -AccessModifierOffset: -4 # 访问修饰符(public/private)向左缩进4空格 +Language: Cpp # Apply configuration to C++ -BreakBeforeBraces: Attach # 大括号附加在声明同行(如 if (x) {) -PointerAlignment: Left # 指针/引用符号紧贴类型(int* p) +# ----------------------------------------------------------------------------- +# Language Standard +# ----------------------------------------------------------------------------- +Standard: Latest # Always use the latest supported C++ standard -SpaceBeforeCpp11BracedList: true # 在 ) 和 { 之间加空格:func( {1, 2} ) -Cpp11BracedListStyle: false # 保留 {} 内部空格:{ 1, 2, 3 } -AlwaysBreakTemplateDeclarations: Yes # 模板声明总是换行:template\nclass X +# ----------------------------------------------------------------------------- +# Indentation +# ----------------------------------------------------------------------------- +IndentWidth: 4 # Use 4 spaces for indentation +TabWidth: 4 # Visual width of tab +UseTab: Never # Never use tabs -AllowShortFunctionsOnASingleLine: Empty # 只有空函数可以单行 \ No newline at end of file + +# ----------------------------------------------------------------------------- +# Line Width +# ----------------------------------------------------------------------------- +ColumnLimit: 120 # Maximum line width + + +# ----------------------------------------------------------------------------- +# Spaces +# ----------------------------------------------------------------------------- +SpaceBeforeParens: ControlStatements # Space before parentheses for control statements (if/for/while); function calls remain tight +SpacesInContainerLiterals: true # Enforce spaces in container literals +SpaceBeforeAssignmentOperators: true # Add space before assignment operators +SpacesInParentheses: false # No extra spaces inside parentheses +PointerAlignment: Left # Pointer/reference attaches to type +QualifierAlignment: Left # Place qualifiers like const to the left + + +# ----------------------------------------------------------------------------- +# Braces +# ----------------------------------------------------------------------------- +BreakBeforeBraces: Attach # Opening brace stays on same line +AllowShortFunctionsOnASingleLine: Empty # Allow empty functions like `void f() {}` +AllowShortIfStatementsOnASingleLine: Never # Disallow single-line if statements +AllowShortBlocksOnASingleLine: Empty # Allow empty blocks on one line +AllowShortLoopsOnASingleLine: false # Disallow one-line loops + + +# ----------------------------------------------------------------------------- +# Constructor Initializer List +# ----------------------------------------------------------------------------- +BreakConstructorInitializers: BeforeColon # Keep initializer list compact when short +ConstructorInitializerAllOnOneLineOrOnePerLine: true # Allow compact initializer lists +BreakConstructorInitializersBeforeComma: false # Do not break before commas + + +# ----------------------------------------------------------------------------- +# Access Modifiers +# ----------------------------------------------------------------------------- +AccessModifierOffset: -4 # Align access modifiers with class indentation +EmptyLineBeforeAccessModifier: Never # Do not insert empty line before access specifiers +EmptyLineAfterAccessModifier: Never # Do not insert empty line after access specifiers + + +# ----------------------------------------------------------------------------- +# Namespace Formatting +# ----------------------------------------------------------------------------- +NamespaceIndentation: None # Do not indent contents inside namespace +FixNamespaceComments: true # Enforce closing namespace comments +CompactNamespaces: true # Prefer namespace a::b instead of nested namespaces + + +# ----------------------------------------------------------------------------- +# Switch / Case Formatting +# ----------------------------------------------------------------------------- +IndentCaseLabels: true # Indent case/default labels +IndentCaseBlocks: true # Indent statements inside case blocks + + +# ----------------------------------------------------------------------------- +# Includes +# ----------------------------------------------------------------------------- +SortIncludes: true # Automatically sort includes +IncludeBlocks: Regroup # Regroup include blocks +IncludeCategories: + - Regex: '^<.*>' # Standard / third-party headers + Priority: 1 + - Regex: '^".*"' # Project headers + Priority: 2 + + +# ----------------------------------------------------------------------------- +# Comment Alignment +# ----------------------------------------------------------------------------- +AlignTrailingComments: true # Align trailing comments +SpacesBeforeTrailingComments: 2 # Two spaces before trailing comments + + +# ----------------------------------------------------------------------------- +# Parameter Formatting +# ----------------------------------------------------------------------------- +BinPackParameters: true # Allow parameters on same line +BinPackArguments: true # Allow arguments on same line + + +# ----------------------------------------------------------------------------- +# Template Formatting +# ----------------------------------------------------------------------------- +AlwaysBreakTemplateDeclarations: Yes # Always place template declarations on their own line + + +# ----------------------------------------------------------------------------- +# Operator Line Breaking +# ----------------------------------------------------------------------------- +BreakBeforeBinaryOperators: None # Break after operators + + +# ----------------------------------------------------------------------------- +# Method Chain Formatting +# ----------------------------------------------------------------------------- +PenaltyBreakBeforeFirstCallParameter: 10000 # Avoid breaking chained calls unless necessary + + +# ----------------------------------------------------------------------------- +# Lambda Formatting +# ----------------------------------------------------------------------------- +AllowShortLambdasOnASingleLine: All # Allow short lambdas on one line + + +# ----------------------------------------------------------------------------- +# Using Declarations +# ----------------------------------------------------------------------------- +SortUsingDeclarations: true # Automatically sort using declarations + + +# ----------------------------------------------------------------------------- +# Return Type Formatting +# ----------------------------------------------------------------------------- +AlwaysBreakAfterReturnType: None # Break return type only when exceeding ColumnLimit + + +# ----------------------------------------------------------------------------- +# Concepts / Requires +# ----------------------------------------------------------------------------- +RequiresClausePosition: OwnLine # Force requires clause to a new line +IndentRequiresClause: false # Do not indent requires clause diff --git a/.d2x.json b/.d2x.json index 72117ab..1091201 100644 --- a/.d2x.json +++ b/.d2x.json @@ -1,6 +1,6 @@ { "buildtools": "xmake d2x-buildtools", - "lang": "en", + "lang": "zh", "llm": { "api_key": "", "api_url": "https://api.deepseek.com/v1", diff --git a/.xlings.json b/.xlings.json new file mode 100644 index 0000000..8854e19 --- /dev/null +++ b/.xlings.json @@ -0,0 +1,9 @@ +{ + "workspace": { + "d2x": "0.1.4", + "xmake": "3.0.7", + "mdbook": "0.4.43", + "code": "", + "gcc": { "linux": "15.1.0" } + } +} \ No newline at end of file diff --git a/mystl/chapter3/global.cppm b/mystl/chapter3/global.cppm index e69de29..ec29ad0 100644 --- a/mystl/chapter3/global.cppm +++ b/mystl/chapter3/global.cppm @@ -0,0 +1,5 @@ +export module mySTL; + +export import mySTL.metaInfo; +export import mySTL.range; +export import mySTL.list; diff --git a/mystl/chapter3/list/list.cppm b/mystl/chapter3/list/list.cppm new file mode 100644 index 0000000..0f81f72 --- /dev/null +++ b/mystl/chapter3/list/list.cppm @@ -0,0 +1,334 @@ +export module mySTL.list; +import std; + +import mySTL.iterator; +import mySTL.range; + +namespace mySTL::impl { + +template +struct ListNode { + T value {}; + ListNode* prev { nullptr }; + ListNode* next { nullptr }; +}; + +} // namespace mySTL::impl + +export namespace mySTL { + +template +class List { +public: + using ValueType = T; + using Reference = T&; + using ConstReference = const T&; + using Pointer = T*; + using ConstPointer = const T*; + using SizeType = std::size_t; + + class Iterator { + public: + using value_type = T; + using difference_type = std::ptrdiff_t; + using reference = T&; + using pointer = T*; + using iterator_category = std::bidirectional_iterator_tag; + + constexpr Iterator() noexcept = default; + constexpr explicit Iterator(impl::ListNode* node) noexcept + : node_ { node } {} + + constexpr T& operator*() const noexcept { + return node_->value; + } + + constexpr T* operator->() const noexcept { + return std::addressof(node_->value); + } + + constexpr Iterator& operator++() noexcept { + node_ = node_->next; + return *this; + } + + constexpr Iterator operator++(int) noexcept { + Iterator tmp { *this }; + ++(*this); + return tmp; + } + + constexpr Iterator& operator--() noexcept { + node_ = node_->prev; + return *this; + } + + constexpr Iterator operator--(int) noexcept { + Iterator tmp { *this }; + --(*this); + return tmp; + } + + friend constexpr bool operator==(const Iterator& lhs, const Iterator& rhs) noexcept { + return lhs.node_ == rhs.node_; + } + + friend constexpr bool operator==(const Iterator& lhs, const typename List::ConstIterator& rhs) noexcept { + return lhs.node_ == rhs.node_; + } + + private: + impl::ListNode* node_ { nullptr }; + }; + + class ConstIterator { + public: + using value_type = T; + using difference_type = std::ptrdiff_t; + using reference = const T&; + using pointer = const T*; + using iterator_category = std::bidirectional_iterator_tag; + + constexpr ConstIterator() noexcept = default; + constexpr explicit ConstIterator(const impl::ListNode* node) noexcept + : node_ { node } {} + + constexpr explicit ConstIterator(const Iterator& it) noexcept + : node_ { it.node_ } {} + + constexpr const T& operator*() const noexcept { + return node_->value; + } + + constexpr const T* operator->() const noexcept { + return std::addressof(node_->value); + } + + constexpr ConstIterator& operator++() noexcept { + node_ = node_->next; + return *this; + } + + constexpr ConstIterator operator++(int) noexcept { + ConstIterator tmp { *this }; + ++(*this); + return tmp; + } + + constexpr ConstIterator& operator--() noexcept { + node_ = node_->prev; + return *this; + } + + constexpr ConstIterator operator--(int) noexcept { + ConstIterator tmp { *this }; + --(*this); + return tmp; + } + + friend constexpr bool operator==(const ConstIterator& lhs, const ConstIterator& rhs) noexcept { + return lhs.node_ == rhs.node_; + } + + friend constexpr bool operator==(const ConstIterator& lhs, const Iterator& rhs) noexcept { + return lhs.node_ == rhs.node_; + } + + private: + const impl::ListNode* node_ { nullptr }; + }; + + List() { + sentinel_.prev = &sentinel_; + sentinel_.next = &sentinel_; + } + + List(const List& other) : List() { + for (const auto& v : other) { + push_back(v); + } + } + + List(List&& other) noexcept : List() { + swap(other); + } + + List& operator=(const List& other) { + if (this == &other) { + return *this; + } + clear(); + for (const auto& v : other) { + push_back(v); + } + return *this; + } + + List& operator=(List&& other) noexcept { + if (this == &other) { + return *this; + } + clear(); + swap(other); + return *this; + } + + ~List() { + clear(); + } + + constexpr SizeType size() const noexcept { + return size_; + } + + constexpr bool empty() const noexcept { + return size_ == 0; + } + + void push_back(const T& value) { + insert_before(&sentinel_, value); + } + + void push_back(T&& value) { + insert_before(&sentinel_, std::move(value)); + } + + void push_front(const T& value) { + insert_before(sentinel_.next, value); + } + + void push_front(T&& value) { + insert_before(sentinel_.next, std::move(value)); + } + + void insert_front(const T& value) { + insert_before(sentinel_.next, value); + } + + void insert_front(T&& value) { + insert_before(sentinel_.next, std::move(value)); + } + + void insert_back(const T& value) { + insert_before(&sentinel_, value); + } + + void insert_back(T&& value) { + insert_before(&sentinel_, std::move(value)); + } + + void pop_back() { + erase_node(sentinel_.prev); + } + + void pop_front() { + erase_node(sentinel_.next); + } + + Reference front() { + return sentinel_.next->value; + } + + ConstReference front() const { + return sentinel_.next->value; + } + + Reference back() { + return sentinel_.prev->value; + } + + ConstReference back() const { + return sentinel_.prev->value; + } + + void clear() noexcept { + auto* node = sentinel_.next; + while (node != &sentinel_) { + auto* next = node->next; + delete node; + node = next; + } + sentinel_.prev = &sentinel_; + sentinel_.next = &sentinel_; + size_ = 0; + } + + void swap(List& other) noexcept { + std::swap(sentinel_.prev, other.sentinel_.prev); + std::swap(sentinel_.next, other.sentinel_.next); + if (sentinel_.next == &other.sentinel_) { + sentinel_.next = &sentinel_; + sentinel_.prev = &sentinel_; + other.sentinel_.next = &other.sentinel_; + other.sentinel_.prev = &other.sentinel_; + } + else if (other.sentinel_.next == &sentinel_) { + other.sentinel_.next = &other.sentinel_; + other.sentinel_.prev = &other.sentinel_; + sentinel_.next = &sentinel_; + sentinel_.prev = &sentinel_; + } + std::swap(size_, other.size_); + } + + Iterator begin() noexcept { + return Iterator { sentinel_.next }; + } + + ConstIterator begin() const noexcept { + return ConstIterator { sentinel_.next }; + } + + ConstIterator cbegin() const noexcept { + return begin(); + } + + Iterator end() noexcept { + return Iterator { const_cast*>(&sentinel_) }; + } + + ConstIterator end() const noexcept { + return ConstIterator { &sentinel_ }; + } + + ConstIterator cend() const noexcept { + return end(); + } + +private: + template + void insert_before(impl::ListNode* pos, U&& value) { + auto* node = new impl::ListNode { + std::forward(value), + pos->prev, + pos + }; + pos->prev->next = node; + pos->prev = node; + ++size_; + } + + template + void insert_after(impl::ListNode* pos, U&& value) { + auto* node = new impl::ListNode { + std::forward(value), + pos, + pos->next + }; + pos->next->prev = node; + pos->next = node; + ++size_; + } + + void erase_node(impl::ListNode* node) { + node->prev->next = node->next; + node->next->prev = node->prev; + delete node; + --size_; + } + + mutable impl::ListNode sentinel_ {}; + SizeType size_ { 0 }; +}; + +} // namespace mySTL diff --git a/mystl/chapter3/xmake.lua b/mystl/chapter3/xmake.lua index adcc1d3..e5f027d 100644 --- a/mystl/chapter3/xmake.lua +++ b/mystl/chapter3/xmake.lua @@ -5,4 +5,5 @@ target("chapter3_modules") add_files("metaInfo/metaInfo.cppm") add_files("array/array.cppm") add_files("iterator/iterator.cppm") - add_files("range/range.cppm") \ No newline at end of file + add_files("range/range.cppm") + add_files("list/list.cppm") diff --git a/src/chapter3/global.cppm b/src/chapter3/global.cppm index aa9d0a5..112c51e 100644 --- a/src/chapter3/global.cppm +++ b/src/chapter3/global.cppm @@ -1,4 +1,5 @@ export module mySTL; export import mySTL.metaInfo; -export import mySTL.range; \ No newline at end of file +export import mySTL.range; +export import mySTL.list; \ No newline at end of file diff --git a/src/chapter3/list/list.cppm b/src/chapter3/list/list.cppm new file mode 100644 index 0000000..30d4987 --- /dev/null +++ b/src/chapter3/list/list.cppm @@ -0,0 +1,521 @@ +export module mySTL.list; +import std; + +import mySTL.iterator; +import mySTL.range; + +namespace mySTL::impl { + +template +struct ListNode { + T value{}; + ListNode* prev{nullptr}; + ListNode* next{nullptr}; +}; + +} // namespace mySTL::impl + +export namespace mySTL { + +template +class List { +public: + using ValueType = T; + using Reference = T&; + using ConstReference = const T&; + using Pointer = T*; + using ConstPointer = const T*; + using SizeType = std::size_t; +public: + class Iterator { + public: + using value_type = T; + using difference_type = std::ptrdiff_t; + using reference = T&; + using pointer = T*; + using iterator_category = std::bidirectional_iterator_tag; + + constexpr Iterator() noexcept = default; + constexpr explicit Iterator(impl::ListNode* node) noexcept : node_{node} {} + + constexpr T& operator*() const noexcept { + return node_->value; + } + + constexpr T* operator->() const noexcept { + return std::addressof(node_->value); + } + + constexpr Iterator& operator++() noexcept { + node_ = node_->next; + return *this; + } + + constexpr Iterator operator++(int) noexcept { + Iterator tmp{*this}; + ++(*this); + return tmp; + } + + constexpr Iterator& operator--() noexcept { + node_ = node_->prev; + return *this; + } + + constexpr Iterator operator--(int) noexcept { + Iterator tmp{*this}; + --(*this); + return tmp; + } + + friend constexpr bool operator==(const Iterator& left, const Iterator& right) noexcept { + return left.node_ == right.node_; + } + + friend constexpr bool operator==(const Iterator& left, const typename List::ConstIterator& right) noexcept { + return left.node_ == right.node_; + } + + friend constexpr bool operator!=(const Iterator& left, const Iterator& right) noexcept { + return !(left == right); + } + + friend constexpr bool operator!=(const Iterator& left, const typename List::ConstIterator& right) noexcept { + return !(left == right); + } + private: + impl::ListNode* node_{nullptr}; + }; +public: + class ConstIterator { + public: + using value_type = T; + using difference_type = std::ptrdiff_t; + using reference = const T&; + using pointer = const T*; + using iterator_category = std::bidirectional_iterator_tag; + + constexpr ConstIterator() noexcept = default; + constexpr explicit ConstIterator(const impl::ListNode* node) noexcept : node_{node} {} + + constexpr explicit ConstIterator(const Iterator& it) noexcept : node_{it.node_} {} + + constexpr const T& operator*() const noexcept { + return node_->value; + } + + constexpr const T* operator->() const noexcept { + return std::addressof(node_->value); + } + + constexpr ConstIterator& operator++() noexcept { + node_ = node_->next; + return *this; + } + + constexpr ConstIterator operator++(int) noexcept { + ConstIterator tmp{*this}; + ++(*this); + return tmp; + } + + constexpr ConstIterator& operator--() noexcept { + node_ = node_->prev; + return *this; + } + + constexpr ConstIterator operator--(int) noexcept { + ConstIterator tmp{*this}; + --(*this); + return tmp; + } + + friend constexpr bool operator==(const ConstIterator& left, const ConstIterator& right) noexcept { + return left.node_ == right.node_; + } + + friend constexpr bool operator==(const ConstIterator& left, const Iterator& right) noexcept { + return left.node_ == right.node_; + } + + friend constexpr bool operator!=(const ConstIterator& left, const ConstIterator& right) noexcept { + return !(left == right); + } + + friend constexpr bool operator!=(const ConstIterator& left, const Iterator& right) noexcept { + return !(left == right); + } + private: + const impl::ListNode* node_{nullptr}; + }; +public: + List() { + sentinel_.prev = &sentinel_; + sentinel_.next = &sentinel_; + } + + List(const List& other) : List() { + for (const auto& v : other) { + push_back(v); + } + } + + List(List&& other) noexcept : List() { + swap(other); + } + + List& operator=(const List& other) { + if (this == &other) { + return *this; + } + clear(); + for (const auto& v : other) { + push_back(v); + } + return *this; + } + + List& operator=(List&& other) noexcept { + if (this == &other) { + return *this; + } + clear(); + swap(other); + return *this; + } + + ~List() { + clear(); + } +public: + constexpr SizeType size() const noexcept { + return size_; + } + + constexpr bool empty() const noexcept { + return size_ == 0; + } + + void push_back(const T& value) { + insert_after_(sentinel_.prev, value); + } + + void push_back(T&& value) { + insert_after_(sentinel_.prev, std::move(value)); + } + + void push_front(const T& value) { + insert_before_(sentinel_.next, value); + } + + void push_front(T&& value) { + insert_before_(sentinel_.next, std::move(value)); + } + + void pop_back() { + delete_node_(sentinel_.prev); + } + + void pop_front() { + delete_node_(sentinel_.next); + } + + Reference front() { + return sentinel_.next->value; + } + + ConstReference front() const { + return sentinel_.next->value; + } + + Reference back() { + return sentinel_.prev->value; + } + + ConstReference back() const { + return sentinel_.prev->value; + } + + void clear() noexcept { + auto* node = sentinel_.next; + while (node != &sentinel_) { + auto* next = node->next; + delete node; + node = next; + } + sentinel_.prev = &sentinel_; + sentinel_.next = &sentinel_; + size_ = 0; + } + + void swap(List& other) noexcept { + std::swap(sentinel_.prev, other.sentinel_.prev); + std::swap(sentinel_.next, other.sentinel_.next); + if (sentinel_.next == &other.sentinel_) { + sentinel_.next = &sentinel_; + sentinel_.prev = &sentinel_; + other.sentinel_.next = &other.sentinel_; + other.sentinel_.prev = &other.sentinel_; + } else if (other.sentinel_.next == &sentinel_) { + other.sentinel_.next = &other.sentinel_; + other.sentinel_.prev = &other.sentinel_; + sentinel_.next = &sentinel_; + sentinel_.prev = &sentinel_; + } + std::swap(size_, other.size_); + } + + Iterator begin() noexcept { + return Iterator{sentinel_.next}; + } + + ConstIterator begin() const noexcept { + return ConstIterator{sentinel_.next}; + } + + ConstIterator cbegin() const noexcept { + return begin(); + } + + Iterator end() noexcept { + return Iterator{const_cast*>(&sentinel_)}; + } + + ConstIterator end() const noexcept { + return ConstIterator{&sentinel_}; + } + + ConstIterator cend() const noexcept { + return end(); + } + + Iterator insert(ConstIterator pos, const T& value) { + auto* node = pos.node_; + insert_before_(node, value); + return Iterator{node->prev}; + } + + Iterator insert(ConstIterator pos, T&& value) { + auto* node = pos.node_; + insert_before_(node, std::move(value)); + return Iterator{node->prev}; + } + + Iterator erase(ConstIterator pos) { + auto* node = pos.node_; + auto* next = node->next; + delete_node_(node); + return Iterator{next}; + } + + Iterator erase(ConstIterator first, ConstIterator last) { + while (first != last) { + first = erase(first); + } + return Iterator{first.node_}; + } + + template + Reference emplace_back(Args&&... args) { + auto* node = new impl::ListNode{T{std::forward(args)...}, sentinel_.prev, &sentinel_}; + sentinel_.prev->next = node; + sentinel_.prev = node; + ++size_; + return node->value; + } + + template + Reference emplace_front(Args&&... args) { + auto* node = new impl::ListNode{T{std::forward(args)...}, &sentinel_, sentinel_.next}; + sentinel_.next->prev = node; + sentinel_.next = node; + ++size_; + return node->value; + } + + void resize(SizeType count) { + if (count < size_) { + while (size_ > count) { + pop_back(); + } + } else if (count > size_) { + while (size_ < count) { + push_back(T{}); + } + } + } + + void resize(SizeType count, const T& value) { + if (count < size_) { + while (size_ > count) { + pop_back(); + } + } else if (count > size_) { + while (size_ < count) { + push_back(value); + } + } + } + + void assign(SizeType count, const T& value) { + clear(); + for (SizeType i{0}; i < count; ++i) { + push_back(value); + } + } + + void remove(const T& value) { + auto it = begin(); + while (it != end()) { + if (*it == value) { + it = erase(it); + } else { + ++it; + } + } + } + + void sort() { + merge_sort_(std::less<>{}); + } + + template + void sort(Compare comp) { + merge_sort_(comp); + } +private: + template + void merge_sort_(Compare comp) { + if (size_ < 2) { + return; + } + + SizeType n{size_}; + for (SizeType step{1}; step < n; step *= 2) { + impl::ListNode* prev{&sentinel_}; + impl::ListNode* current{sentinel_.next}; + + while (current != &sentinel_) { + impl::ListNode* first{current}; + impl::ListNode* first_end{advance_(first, step)}; + impl::ListNode* second{first_end}; + impl::ListNode* second_end{advance_(second, step)}; + + if (first_end == &sentinel_) { + second = &sentinel_; + second_end = &sentinel_; + } else if (second_end == &sentinel_) { + second_end = &sentinel_; + } + + if (first_end != &sentinel_) { + first_end->prev = nullptr; + } + if (second_end != &sentinel_) { + second_end->prev = nullptr; + } + + if (first == &sentinel_) { + prev->next = second; + second->prev = prev; + while (second != second_end && second->next != nullptr) { + second = second->next; + } + second->next = &sentinel_; + sentinel_.prev = second; + break; + } + + impl::ListNode* merged{merge_(first, first_end, second, second_end, comp)}; + impl::ListNode* tail{tail_(merged)}; + + prev->next = merged; + merged->prev = prev; + tail->next = &sentinel_; + sentinel_.prev = tail; + prev = tail; + + current = second_end; + } + } + } + + static impl::ListNode* advance_(impl::ListNode* node, SizeType k) { + for (SizeType i{0}; i < k && node != nullptr && node->next != nullptr; ++i) { + node = node->next; + } + if (node != nullptr && node->next == nullptr) { + return nullptr; + } + return node; + } + + template + static impl::ListNode* merge_(impl::ListNode* a, impl::ListNode* a_end, impl::ListNode* b, + impl::ListNode* b_end, Compare comp) { + impl::ListNode dummy{}; + impl::ListNode* tail{&dummy}; + + while (a != a_end && b != b_end) { + if (comp(a->value, b->value)) { + tail->next = a; + a->prev = tail; + a = a->next; + } else { + tail->next = b; + b->prev = tail; + b = b->next; + } + tail = tail->next; + } + + impl::ListNode* rest{(a != a_end) ? a : b}; + impl::ListNode* rest_end{(a != a_end) ? a_end : b_end}; + while (rest != rest_end) { + tail->next = rest; + rest->prev = tail; + tail = rest; + rest = rest->next; + } + tail->next = nullptr; + if (dummy.next != nullptr) { + dummy.next->prev = nullptr; + } + return dummy.next; + } + + static impl::ListNode* tail_(impl::ListNode* node) { + while (node->next != nullptr) { + node = node->next; + } + return node; + } +private: + template + void insert_before_(impl::ListNode* pos, U&& value) { + auto* node = new impl::ListNode{std::forward(value), pos->prev, pos}; + pos->prev->next = node; + pos->prev = node; + ++size_; + } + + template + void insert_after_(impl::ListNode* pos, U&& value) { + auto* node = new impl::ListNode{std::forward(value), pos, pos->next}; + pos->next->prev = node; + pos->next = node; + ++size_; + } + + void delete_node_(impl::ListNode* node) { + node->prev->next = node->next; + node->next->prev = node->prev; + delete node; + --size_; + } + + mutable impl::ListNode sentinel_{}; + SizeType size_{0}; +}; + +} // namespace mySTL diff --git a/src/chapter3/xmake.lua b/src/chapter3/xmake.lua index adcc1d3..6327290 100644 --- a/src/chapter3/xmake.lua +++ b/src/chapter3/xmake.lua @@ -5,4 +5,5 @@ target("chapter3_modules") add_files("metaInfo/metaInfo.cppm") add_files("array/array.cppm") add_files("iterator/iterator.cppm") - add_files("range/range.cppm") \ No newline at end of file + add_files("range/range.cppm") + add_files("list/list.cppm") \ No newline at end of file diff --git a/tests/chapter3/xmake.lua b/tests/chapter3/xmake.lua index 1e1521f..2881d70 100644 --- a/tests/chapter3/xmake.lua +++ b/tests/chapter3/xmake.lua @@ -4,7 +4,8 @@ target("chapter3_tests") "../test_metaInfo.cpp", "../test_array.cpp", "../test_iterator.cpp", - "../test_range.cpp" + "../test_range.cpp", + "../test_list.cpp" ) if is_mode("debug") then add_files("../../src/chapter3/**.cppm") diff --git a/tests/test_list.cpp b/tests/test_list.cpp new file mode 100644 index 0000000..a5ad1a1 --- /dev/null +++ b/tests/test_list.cpp @@ -0,0 +1,184 @@ +#include + +import mySTL.list; +import mySTL.iterator; +import mySTL.range; + +TEST(ListTest, DefaultConstruct) +{ + mySTL::List lst; + EXPECT_EQ(lst.size(), 0u); + EXPECT_TRUE(lst.empty()); + EXPECT_EQ(lst.begin(), lst.end()); +} + +TEST(ListTest, PushBack) +{ + mySTL::List lst; + lst.push_back(1); + lst.push_back(2); + lst.push_back(3); + + EXPECT_EQ(lst.size(), 3u); + EXPECT_FALSE(lst.empty()); + + int expected = 1; + for (auto it = lst.begin(); it != lst.end(); ++it) { + EXPECT_EQ(*it, expected); + ++expected; + } +} + +TEST(ListTest, PushFront) +{ + mySTL::List lst; + lst.push_front(1); + lst.push_front(2); + lst.push_front(3); + + EXPECT_EQ(lst.size(), 3u); + + mySTL::List::Iterator it = lst.begin(); + EXPECT_EQ(*it, 3); + ++it; + EXPECT_EQ(*it, 2); + ++it; + EXPECT_EQ(*it, 1); +} + +TEST(ListTest, FrontBack) +{ + mySTL::List lst; + lst.push_back(10); + lst.push_back(20); + lst.push_back(30); + + EXPECT_EQ(lst.front(), 10); + EXPECT_EQ(lst.back(), 30); + + const auto& c = lst; + EXPECT_EQ(c.front(), 10); + EXPECT_EQ(c.back(), 30); +} + +TEST(ListTest, PopBackPopFront) +{ + mySTL::List lst; + lst.push_back(1); + lst.push_back(2); + lst.push_back(3); + + lst.pop_front(); + EXPECT_EQ(lst.size(), 2u); + EXPECT_EQ(lst.front(), 2); + + lst.pop_back(); + EXPECT_EQ(lst.size(), 1u); + EXPECT_EQ(lst.front(), 2); + EXPECT_EQ(lst.back(), 2); +} + +TEST(ListTest, BidirectionalIteration) +{ + mySTL::List lst; + for (int i { 0 }; i < 5; ++i) { + lst.push_back(i); + } + + int expected { 4 }; + for (auto it = lst.end(); it != lst.begin();) { + --it; + EXPECT_EQ(*it, expected); + --expected; + } + + int sum { 0 }; + for (const int& v : lst) { + sum += v; + } + EXPECT_EQ(sum, 0 + 1 + 2 + 3 + 4); +} + +TEST(ListTest, RangeConcept) +{ + mySTL::List lst; + EXPECT_TRUE(mySTL::range::Range>); + EXPECT_TRUE(mySTL::range::Range>); + EXPECT_TRUE(mySTL::range::IterRange>); +} + +TEST(ListTest, BidirectionalIteratorConcept) +{ + EXPECT_TRUE(mySTL::iterator::BidirectionalIterator::Iterator>); + EXPECT_TRUE(mySTL::iterator::BidirectionalIterator::ConstIterator>); +} + +TEST(ListTest, CopyAndMove) +{ + mySTL::List original; + original.push_back(1); + original.push_back(2); + original.push_back(3); + + mySTL::List copy { original }; + EXPECT_EQ(copy.size(), 3u); + EXPECT_EQ(original.size(), 3u); + + int expected { 1 }; + for (int v : copy) { + EXPECT_EQ(v, expected); + ++expected; + } + + mySTL::List moved; + moved = std::move(copy); + EXPECT_EQ(moved.size(), 3u); + EXPECT_EQ(copy.size(), 0u); + EXPECT_TRUE(copy.empty()); +} + +TEST(ListTest, Clear) +{ + mySTL::List lst; + for (int i { 0 }; i < 10; ++i) { + lst.push_back(i); + } + EXPECT_EQ(lst.size(), 10u); + + lst.clear(); + EXPECT_EQ(lst.size(), 0u); + EXPECT_TRUE(lst.empty()); + + lst.push_back(42); + EXPECT_EQ(lst.size(), 1u); + EXPECT_EQ(lst.front(), 42); +} + +TEST(ListTest, Swap) +{ + mySTL::List a; + a.push_back(1); + a.push_back(2); + + mySTL::List b; + b.push_back(100); + + a.swap(b); + + EXPECT_EQ(a.size(), 1u); + EXPECT_EQ(a.front(), 100); + EXPECT_EQ(b.size(), 2u); + EXPECT_EQ(b.front(), 1); + EXPECT_EQ(b.back(), 2); +} + +TEST(ListTest, GenericType) +{ + mySTL::List> nested; + mySTL::List inner; + inner.push_back(1); + inner.push_back(2); + nested.push_back(inner); + EXPECT_EQ(nested.size(), 1u); + EXPECT_EQ(nested.front().size(), 2u); +}