Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <iostream>
- template <typename T>
- class ListIterator;
- template <typename T, typename Allocator = std::allocator<T>>
- class List {
- friend class ListIterator<T>;
- public:
- using value_type = T;
- using allocator_type = Allocator;
- using iterator = ListIterator<T>;
- using const_iterator = ListIterator<const T>;
- List();
- explicit List(size_t count, const T& value,
- const Allocator& alloc = Allocator());
- explicit List(size_t count, const Allocator& alloc = Allocator());
- List(const List& other);
- List(List&& other) noexcept;
- List(std::initializer_list<value_type> init,
- const Allocator& alloc = Allocator());
- ~List();
- List& operator=(const List& other);
- List& operator=(List&& other) noexcept;
- [[nodiscard]] size_t size() const {
- return size_;
- };
- [[nodiscard]] bool empty() const {
- return size_ == 0;
- }
- [[nodiscard]] iterator begin() const;
- [[nodiscard]] const_iterator cbegin() const;
- [[nodiscard]] iterator end() const;
- [[nodiscard]] const_iterator cend() const;
- value_type& front();
- [[nodiscard]] const value_type& front() const;
- value_type& back();
- [[nodiscard]] const value_type& back() const;
- template<typename... Args>
- void emplace_back(Args&&... args);
- template<typename... Args>
- void emplace_front(Args&&... args);
- private:
- struct Node;
- Node* head_;
- Node* tail_;
- Node* x_;
- size_t size_ = 0;
- using alloc_traits = typename std::allocator_traits<
- allocator_type>::template rebind_traits<Node>;
- using alloc_type = typename std::allocator_traits<
- allocator_type>::template rebind_alloc<Node>;
- alloc_type alloc_;
- void set_ends();
- Node* make_node();
- Node* make_node(value_type value);
- Node* make_node(const Node& other);
- template <typename ...Args>
- Node* make_node(Args&&... args);
- void fill_list(size_t count);
- void fill_list(size_t count, T value);
- void fill_list(const List<T, Allocator>& other);
- void fill_list(std::initializer_list<T> init_list);
- void clean_list(Node* current, Node* next_node, bool dealloc = true);
- };
- template<typename T>
- class ListIterator : public std::iterator<std::bidirectional_iterator_tag, T> {
- using node = typename List<T>::Node;
- public:
- explicit ListIterator(node* node_p_) : node_p_(node_p_) {};
- ListIterator(const ListIterator<T>& it) : node_p_(it.node_p_) {}
- T operator*() const;
- T* operator->() const;
- ListIterator& operator++();
- ListIterator& operator--();
- bool operator==(const ListIterator& other);
- bool operator!=(const ListIterator& other);
- private:
- node* node_p_;
- };
- ////////////////////////////////////////////////////////////////////////////////
- template <typename T, typename Allocator>
- struct List<T, Allocator>::Node {
- Node() = default;
- explicit Node(T value) : value(value){};
- Node(const Node& other)
- : next(other.next), prev(other.prev), value(other.value) {
- }
- explicit Node(T&& value) : value(std::move(value)) {
- }
- Node(Node&& other) noexcept
- : next(other.next), prev(other.prev), value(std::move(other.value)) {
- next = nullptr;
- prev = nullptr;
- }
- template <typename... Args>
- Node(Args&&... args)
- : value(std::forward<Args>(args)...) {
- }
- ~Node() = default;
- Node* next = nullptr;
- Node* prev = nullptr;
- T value {};
- };
- template <typename T, typename Allocator>
- void List<T, Allocator>::set_ends() {
- head_->prev = x_;
- tail_->next = x_;
- x_->next = head_;
- x_->prev = tail_;
- }
- template <typename T, typename Allocator>
- typename List<T, Allocator>::Node* List<T, Allocator>::make_node(
- const List::Node& other) {
- Node* new_node = alloc_traits::allocate(alloc_, 1);
- try {
- alloc_traits::construct(alloc_, new_node, other);
- } catch (...) {
- alloc_traits::deallocate(alloc_, new_node, 1);
- throw;
- }
- return new_node;
- }
- template <typename T, typename Allocator>
- typename List<T, Allocator>::Node* List<T, Allocator>::make_node(
- value_type value) {
- Node* new_node = alloc_traits::allocate(alloc_, 1);
- try {
- alloc_traits::construct(alloc_, new_node, value);
- } catch (...) {
- alloc_traits::deallocate(alloc_, new_node, 1);
- throw;
- }
- return new_node;
- }
- template <typename T, typename Allocator>
- typename List<T, Allocator>::Node* List<T, Allocator>::make_node() {
- Node* new_node = alloc_traits::allocate(alloc_, 1);
- try {
- alloc_traits::construct(alloc_, new_node);
- } catch (...) {
- alloc_traits::deallocate(alloc_, new_node, 1);
- throw;
- }
- return new_node;
- }
- template <typename T, typename Allocator>
- template <typename... Args>
- typename List<T, Allocator>::Node* List<T, Allocator>::make_node(Args&&... args) {
- Node* new_node = alloc_traits::allocate(alloc_, 1);
- try {
- alloc_traits::construct(alloc_, new_node, std::forward<Args>(args)...);
- } catch (...) {
- alloc_traits::deallocate(alloc_, new_node, 1);
- throw;
- }
- return new_node;
- }
- template <typename T, typename Allocator>
- void List<T, Allocator>::clean_list(List::Node* current,
- List::Node* next_node, bool dealloc) {
- if (empty()) {
- return;
- }
- while (next_node != x_) {
- alloc_traits::destroy(alloc_, next_node);
- if (dealloc) {
- alloc_traits::deallocate(alloc_, next_node, 1);
- }
- next_node = current;
- current = current->prev;
- }
- }
- template <typename T, typename Allocator>
- void List<T, Allocator>::fill_list(size_t count, value_type value) {
- Node* current = x_;
- Node* next_node;
- try {
- for (size_t i = 0; i < count; ++i) {
- next_node = make_node(value);
- current->next = next_node;
- next_node->prev = current;
- current = next_node;
- }
- } catch (...) {
- clean_list(current, next_node);
- alloc_traits::deallocate(alloc_, x_, 1);
- throw;
- }
- head_ = x_->next;
- tail_ = next_node;
- set_ends();
- }
- template <typename T, typename Allocator>
- void List<T, Allocator>::fill_list(size_t count) {
- Node* current = x_;
- Node* next_node;
- try {
- for (size_t i = 0; i < count; ++i) {
- next_node = make_node();
- current->next = next_node;
- next_node->prev = current;
- current = next_node;
- }
- } catch (...) {
- clean_list(current, next_node);
- alloc_traits::deallocate(alloc_, x_, 1);
- throw;
- }
- head_ = x_->next;
- tail_ = next_node;
- set_ends();
- }
- template <typename T, typename Allocator>
- void List<T, Allocator>::fill_list(const List<T, Allocator>& other) {
- Node* current = x_;
- Node* next_node;
- Node* other_current = other.x_;
- try {
- while (other_current != other.tail_) {
- other_current = other_current->next;
- next_node = make_node(*other_current);
- current->next = next_node;
- next_node->prev = current;
- current = next_node;
- }
- } catch (...) {
- clean_list(current, next_node);
- alloc_traits::deallocate(alloc_, x_, 1);
- throw;
- }
- head_ = x_->next;
- tail_ = next_node;
- set_ends();
- }
- template <typename T, typename Allocator>
- void List<T, Allocator>::fill_list(std::initializer_list<T> init_list) {
- Node* current = x_;
- Node* next_node;
- try {
- for (auto iter = init_list.cbegin(); iter != init_list.cend(); ++iter) {
- next_node = make_node(iter);
- current->next = next_node;
- next_node->prev = current;
- current = next_node;
- }
- } catch (...) {
- clean_list(current, next_node);
- alloc_traits::deallocate(alloc_, x_, 1);
- throw;
- }
- head_ = x_->next;
- tail_ = next_node;
- set_ends();
- }
- /// -------------------------------Constructors---------------------------------
- template <typename T, typename Allocator>
- List<T, Allocator>::List() {
- x_ = alloc_traits::allocate(alloc_, 1);
- x_->next = head_;
- x_->prev = tail_;
- }
- template <typename T, typename Allocator>
- List<T, Allocator>::List(size_t count, const T& value, const Allocator& alloc) {
- size_ = count;
- alloc_ = alloc;
- x_ = alloc_traits::allocate(alloc_, 1);
- x_->next = head_;
- x_->prev = tail_;
- fill_list(count, value);
- }
- template <typename T, typename Allocator>
- List<T, Allocator>::List(size_t count, const Allocator& alloc) {
- size_ = count;
- alloc_ = alloc;
- x_ = alloc_traits::allocate(alloc_, 1);
- x_->next = head_;
- x_->prev = tail_;
- fill_list(count);
- }
- template <typename T, typename Allocator>
- List<T, Allocator>::List(const List& other) {
- size_ = other.size_;
- alloc_ = alloc_traits::select_on_container_copy_construction(other.alloc_);
- x_ = alloc_traits::allocate(alloc_, 1);
- x_->next = head_;
- x_->prev = tail_;
- fill_list(other);
- }
- template <typename T, typename Allocator>
- List<T, Allocator>::List(List&& other) noexcept
- : head_(std::move(other.head_))
- , tail_(std::move(other.tail_))
- , x_(std::move(other.x_))
- , size_(other.size_)
- , alloc_(std::move(other.alloc_)) {
- x_->next = head_;
- x_->prev = tail_;
- other.head_ = nullptr;
- other.tail_ = nullptr;
- other.size_ = 0;
- }
- template <typename T, typename Allocator>
- List<T, Allocator>::List(std::initializer_list<value_type> init,
- const Allocator& alloc) {
- size_ = init.size();
- alloc_ = alloc;
- x_ = alloc_traits::allocate(alloc_, 1);
- x_->next = head_;
- x_->prev = tail_;
- fill_list(init);
- }
- template <typename T, typename Allocator>
- List<T, Allocator>::~List() {
- if (empty()) {
- return;
- }
- clean_list(tail_->prev, tail_);
- size_ = 0;
- head_ = nullptr;
- tail_ = nullptr;
- x_->next = nullptr;
- x_->prev = nullptr;
- alloc_traits::deallocate(alloc_, x_, 1);
- }
- /// -------------------------------Operators------------------------------------
- template <typename T, typename Allocator>
- List<T, Allocator>& List<T, Allocator>::operator=(const List<T, Allocator>& other) {
- if (this == &other) {
- return *this;
- }
- clean_list(tail_->prev, tail_);
- alloc_traits::destroy(alloc_, x_);
- x_ = other.x_;
- size_ = other.size_;
- if (alloc_traits::propagate_on_container_copy_assignment::value && alloc_ != other.alloc_) {
- alloc_ = other.alloc_;
- }
- fill_list(other);
- return *this;
- }
- template <typename T, typename Allocator>
- List<T, Allocator>& List<T, Allocator>::operator=(List<T, Allocator>&& other) noexcept {
- List<T, Allocator> tmp = std::move(other);
- std::swap(size_, tmp.size_);
- std::swap(head_, tmp.head_);
- std::swap(tail_, tmp.tail_);
- std::swap(x_ , tmp.x_);
- if (alloc_traits::propagate_on_container_move_assignment::value && alloc_ != tmp.alloc_) {
- std::swap(alloc_, tmp.alloc_);
- }
- return *this;
- }
- /// -------------------------------Iterators------------------------------------
- template <typename T>
- T ListIterator<T>::operator*() const {
- return node_p_->value;
- }
- template <typename T>
- T* ListIterator<T>::operator->() const {
- return &(node_p_->value);
- }
- template <typename T>
- ListIterator<T>& ListIterator<T>::operator++() {
- node_p_ = node_p_->next;
- return *this;
- }
- template <typename T>
- ListIterator<T>& ListIterator<T>::operator--() {
- node_p_ = node_p_->prev;
- return *this;
- }
- template <typename T>
- bool ListIterator<T>::operator==(const ListIterator& other) {
- return node_p_ == other.node_p_;
- }
- template <typename T>
- bool ListIterator<T>::operator!=(const ListIterator& other) {
- return node_p_ != other.node_p_;
- }
- template <typename T, typename Allocator>
- typename List<T, Allocator>::iterator List<T, Allocator>::begin() const {
- if (head_ == nullptr) {
- return List::iterator(x_);
- }
- return List::iterator(head_);
- }
- template <typename T, typename Allocator>
- typename List<T, Allocator>::const_iterator List<T, Allocator>::cbegin() const {
- if (head_ == nullptr) {
- return List::const_iterator(x_);
- }
- return List::const_iterator(head_);
- }
- template <typename T, typename Allocator>
- typename List<T, Allocator>::iterator List<T, Allocator>::end() const{
- return List::iterator(x_);
- }
- template <typename T, typename Allocator>
- typename List<T, Allocator>::const_iterator List<T, Allocator>::cend() const{
- return List::const_iterator(x_);
- }
- /// -----------------------Element access methods-------------------------------
- template <typename T, typename Allocator>
- T& List<T, Allocator>::front() {
- return head_->value;
- }
- template <typename T, typename Allocator>
- const T& List<T, Allocator>::front() const{
- return head_->value;
- }
- template <typename T, typename Allocator>
- T& List<T, Allocator>::back() {
- return tail_->value;
- }
- template <typename T, typename Allocator>
- const T& List<T, Allocator>::back() const{
- return tail_->value;
- }
- /// ------------------------------Modifiers-------------------------------------
- template <typename T, typename Allocator>
- template <typename... Args>
- void List<T, Allocator>::emplace_back(Args&& ...args) {
- Node* next_node = nullptr;
- try {
- next_node = make_node(alloc_, std::forward<Args>(args)...);
- } catch (...) {
- alloc_traits::destroy(alloc_, next_node);
- alloc_traits::deallocate(alloc_, next_node, 1);
- alloc_traits::deallocate(alloc_, x_, 1);
- throw;
- }
- if (empty()) {
- head_ = next_node;
- tail_ = next_node;
- set_ends();
- return;
- }
- Node* x_prev = x_->prev;
- x_prev->next = next_node;
- tail_ = next_node;
- x_->prev = next_node;
- next_node->prev = x_prev;
- next_node->next = x_;
- }
- template <typename T, typename Allocator>
- template <typename ...Args>
- void List<T, Allocator>::emplace_front(Args&& ...args) {
- Node* next_node;
- try {
- next_node = make_node(alloc_, std::forward(args)...);
- } catch (...) {
- alloc_traits::destroy(alloc_, next_node);
- alloc_traits::deallocate(alloc_, next_node, 1);
- alloc_traits::deallocate(alloc_, x_, 1);
- throw;
- }
- if (empty()) {
- head_ = next_node;
- tail_ = next_node;
- set_ends();
- return;
- }
- Node* head_prev = head_;
- x_->next = next_node;
- head_ = next_node;
- head_prev->prev = next_node;
- next_node->prev = x_;
- next_node->next = head_prev;
- }
- int main() {
- List<int> list1(5, 1);
- List<int> list2(3);
- list1.emplace_back(5);
- for (auto i : list1) {
- std::cout << i << ' ';
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement