17#include <initializer_list>
124 : m_value{ std::move(
value) }
142 [[nodiscard]]
auto value() const -> T
166 template<
bool IF_CONST>
231 : m_current_node{ node }
242 this->m_current_node = node;
255 m_current_node = m_current_node->m_next;
283 return m_current_node == other.m_current_node;
306 if (
Node* node =
dynamic_cast<Node*
>(m_current_node))
308 return node->value();
310 throw std::runtime_error(
"Invalid iterator dereference");
320 if (
Node* node =
dynamic_cast<Node*
>(m_current_node))
322 return &node->value();
324 throw std::runtime_error(
"Invalid iterator pointer");
438 template<
typename InputIt>
439 requires std::input_iterator<InputIt>
447 ForwardList(
const std::initializer_list<T>& init_list);
501 template<
typename InputIt>
502 requires std::input_iterator<InputIt>
503 void assign(InputIt first, InputIt last);
510 void assign(
const std::initializer_list<T>& init_list);
602 [[nodiscard]] auto
empty() const ->
bool;
660 template<typename InputIt>
661 requires std::input_iterator<InputIt>
687 template<typename... Args>
744 template<typename... Args>
772 void swap(
ForwardList<T>& other) noexcept(std::is_nothrow_swappable_v<T>);
809 template<typename Compare>
823 template<typename Compare>
932 template<typename UnaryPred>
956 template<typename BinaryPred>
980 template<typename Compare>
981 void sort(Compare comp);
1006 [[nodiscard]]
auto find_iter_before_last() ->
iterator;
1024 template<
typename... Args>
1025 auto construct_node(NodeBase* next_ptr, Args&&... args) -> Node*;
1032 void destroy_node(NodeBase* node_to_destroy);
1042 [[nodiscard]]
auto if_valid_iterator(
const const_iterator& pos) -> bool;
1089 template<
typename Compare>
1090 auto merge_sort(NodeBase* source, Compare comp) -> NodeBase*;
1101 template<
typename Compare>
1102 auto merge(NodeBase* left, NodeBase* right, Compare comp) -> NodeBase*;
1115 using node_allocator =
typename std::allocator_traits<std::allocator<T>>::template rebind_alloc<Node>;
1120 using node_alloc_traits = std::allocator_traits<node_allocator>;
1125 node_allocator node_alloc{};
1128 template<
typename T>
1134 template<
typename T>
1139 template<
typename T>
1150 template<
typename T>
1151 template<
typename InputIt>
1152 requires std::input_iterator<InputIt>
1160 template<
typename T>
1166 for (
const auto& item : init_list)
1172 template<
typename T>
1178 for (
const auto& item : other)
1184 template<
typename T>
1191 while (m_head->m_next)
1197 for (
const auto& item : other)
1206 template<
typename T>
1212 template<
typename T>
1220 m_head->m_next = other.m_head->m_next;
1221 m_size = other.m_size;
1223 other.m_head->m_next =
nullptr;
1230 template<
typename T>
1237 template<
typename T>
1240 while (m_head->m_next)
1252 template<
typename T>
1253 template<
typename InputIt>
1254 requires std::input_iterator<InputIt>
1260 while (first != last)
1267 template<
typename T>
1270 while (m_head->m_next)
1276 for (
const auto& item : init_list)
1282 template<
typename T>
1288 template<
typename T>
1294 template<
typename T>
1300 template<
typename T>
1306 template<
typename T>
1312 template<
typename T>
1318 template<
typename T>
1324 template<
typename T>
1330 template<
typename T>
1336 template<
typename T>
1342 template<
typename T>
1348 template<
typename T>
1355 template<
typename T>
1361 template<
typename T>
1364 return std::numeric_limits<size_type>::max();
1367 template<
typename T>
1375 m_head->m_next = temp->m_next;
1377 temp = m_head->m_next;
1381 m_head->m_next =
nullptr;
1385 template<
typename T>
1392 template<
typename T>
1396 if (!if_valid_iterator(pos))
1401 iterator iter{ pos.m_current_node };
1407 template<
typename T>
1411 if (!if_valid_iterator(pos))
1416 iterator iter{ pos.m_current_node };
1425 template<
typename T>
1426 template<
typename InputIt>
1427 requires std::input_iterator<InputIt>
1431 if (!if_valid_iterator(pos))
1436 iterator iter{ pos.m_current_node };
1437 while (first != last)
1446 template<
typename T>
1450 if (!if_valid_iterator(pos))
1455 iterator iter{ pos.m_current_node };
1456 for (
const auto val : init_list)
1464 template<
typename T>
1465 template<
typename... Args>
1468 const iterator current{ pos.m_current_node };
1470 Node* newNode{ construct_node(current.m_current_node->m_next, std::forward<Args>(args)...) };
1471 current.m_current_node->m_next = newNode;
1477 template<
typename T>
1480 if (!if_valid_iterator(pos))
1485 iterator iter{ pos.m_current_node };
1486 iter = erase_element_after(iter);
1491 template<
typename T>
1495 if (!if_valid_iterator(first) || !if_valid_iterator(last))
1500 const iterator iter(first.m_current_node);
1501 const size_type dist = distance(first, last);
1502 for (
size_type i = 0; i < dist - 1; i++)
1504 erase_element_after(iter);
1507 return first.m_current_node->m_next;
1510 template<
typename T>
1516 template<
typename T>
1522 template<
typename T>
1523 template<
typename... Args>
1530 template<
typename T>
1533 if (!m_head->m_next)
1541 m_head->m_next =
nullptr;
1545 m_head->m_next = temp->m_next;
1552 template<
typename T>
1558 template<
typename T>
1563 if (count == m_size)
1570 auto iter =
begin();
1571 for (
size_type i = 0; i < count - 1; i++)
1576 while (m_size > count)
1584 auto iter = find_iter_before_last();
1590 while (m_size < count)
1597 template<
typename T>
1600 std::swap(m_head->m_next, other.m_head->m_next);
1601 std::swap(m_size, other.m_size);
1604 template<
typename T>
1607 merge(std::move(other));
1610 template<
typename T>
1613 merge(std::move(other), std::less<>());
1616 template<
typename T>
1617 template<
typename Compare>
1620 merge(std::move(other), comp);
1623 template<
typename T>
1624 template<
typename Compare>
1636 Node* temp_head{ construct_node(
nullptr, T{}) };
1642 while (m_head->m_next && other.m_head->m_next)
1644 Node* node_this =
dynamic_cast<Node*
>(m_head->m_next);
1645 Node* node_other =
dynamic_cast<Node*
>(other.m_head->m_next);
1647 if (node_this && node_other)
1649 if (comp(node_this->
value(), node_other->
value()))
1651 to_move = m_head->m_next;
1652 to_return = to_move->m_next;
1653 temp_tail->m_next = to_move;
1654 m_head->m_next = to_return;
1658 to_move = other.m_head->m_next;
1659 to_return = to_move->m_next;
1660 temp_tail->m_next = to_move;
1661 other.m_head->m_next = to_return;
1664 temp_tail = temp_tail->m_next;
1668 if (m_head->m_next ==
nullptr)
1670 temp_tail->m_next = other.m_head->m_next;
1671 other.m_head->m_next =
nullptr;
1675 temp_tail->m_next = m_head->m_next;
1676 m_head->m_next =
nullptr;
1679 m_head->m_next = temp_head->m_next;
1680 destroy_node(temp_head);
1682 m_size += other.m_size;
1691 template<
typename T>
1697 template<
typename T>
1700 transfer(pos, std::move(other), other.before_begin(), other.end());
1703 template<
typename T>
1706 transfer(pos, std::move(other), iter);
1709 template<
typename T>
1712 transfer(pos, std::move(other), iter);
1715 template<
typename T>
1719 transfer(pos, std::move(other), first, last);
1722 template<
typename T>
1725 transfer(pos, std::move(other), first, last);
1728 template<
typename T>
1731 return remove_if([value](T node_val) {
return node_val == value; });
1734 template<
typename T>
1735 template<
typename UnaryPred>
1745 next = temp->m_next;
1747 if (
Node* node =
dynamic_cast<Node*
>(next))
1749 if (predicate(node->value()))
1751 NodeBase* to_remove = temp->m_next;
1752 temp->m_next = to_remove->m_next;
1753 destroy_node(to_remove);
1761 temp = temp->m_next;
1764 return removed_count;
1767 template<
typename T>
1772 auto iter = find_iter_before_last();
1773 NodeBase* last{ iter.m_current_node->m_next };
1775 m_head->m_next = last;
1783 next = temp->m_next;
1784 temp->m_next = prev;
1790 m_head->m_next = std::move(prev);
1793 template<
typename T>
1796 return unique(std::equal_to<>());
1799 template<
typename T>
1800 template<
typename BinaryPred>
1815 next = prev->m_next;
1817 Node* node_next =
dynamic_cast<Node*
>(next);
1818 Node* node_temp =
dynamic_cast<Node*
>(temp);
1819 if (node_next && node_temp)
1821 if (predicate(node_next->
value(), node_temp->
value()))
1824 prev->m_next = to_remove->m_next;
1825 destroy_node(to_remove);
1833 prev = prev->m_next;
1834 temp = temp->m_next;
1838 return removed_count;
1841 template<
typename T>
1844 m_head->m_next = merge_sort(m_head->m_next, std::less<>());
1847 template<
typename T>
1848 template<
typename Compare>
1851 m_head->m_next = merge_sort(m_head->m_next, comp);
1862 template<
typename T>
1870 for (
auto it = list.cbegin(); it != list.cend(); ++it)
1873 out << value <<
' ';
1888 template<
typename T>
1890 noexcept(
noexcept(*lhs.begin() == *rhs.begin())) ->
bool
1892 if (lhs.size() != rhs.size())
1897 auto lhs_iter = lhs.cbegin();
1898 auto rhs_iter = rhs.cbegin();
1900 while (lhs_iter != lhs.cend())
1902 if (*lhs_iter != *rhs_iter)
1927 template<
typename T>
1929 noexcept(
noexcept(*lhs.begin() == *rhs.begin())) -> std::compare_three_way_result_t<T>
1931 auto lhs_iter = lhs.cbegin();
1932 auto rhs_iter = rhs.cbegin();
1934 while (lhs_iter != lhs.cend() && rhs_iter != rhs.cend())
1936 auto cmp = *lhs_iter <=> *rhs_iter;
1948 return lhs.size() <=> rhs.size();
1958 template<
typename T>
1973 template<
typename T,
typename U>
1976 return erase_if(container, [&value](U node_val) {
return node_val == value; });
1988 template<
typename T,
typename Pred>
1991 return container.remove_if(pred);
1996 template<
typename T>
1997 void ForwardList<T>::init_node()
1999 if (m_head ==
nullptr)
2002 m_head =
new NodeBase;
2006 template<
typename T>
2007 auto ForwardList<T>::find_iter_before_last() -> iterator
2009 NodeBase* temp{ m_head->m_next };
2010 while (temp && temp->m_next && temp->m_next->m_next)
2012 temp = temp->m_next;
2015 auto iter = iterator(temp);
2016 if (!iter.m_current_node)
2018 iter = before_begin();
2024 template<
typename T>
2025 auto ForwardList<T>::erase_element_after(iterator pos) -> iterator
2027 NodeBase* temp{ pos.m_current_node };
2028 NodeBase* to_remove{ temp->m_next };
2030 temp->m_next = to_remove->m_next;
2031 destroy_node(to_remove);
2034 return iterator(temp->m_next);
2037 template<
typename T>
2038 template<
typename... Args>
2039 auto ForwardList<T>::construct_node(NodeBase* next_ptr, Args&&... args) -> Node*
2044 newNode = node_alloc_traits::allocate(node_alloc, 1);
2045 node_alloc_traits::construct(node_alloc, newNode, std::forward<Args>(args)...);
2046 newNode->m_next = next_ptr;
2050 node_alloc_traits::deallocate(node_alloc, newNode, 1);
2057 template<
typename T>
2058 void ForwardList<T>::destroy_node(NodeBase* node_to_destroy)
2060 if (Node* node_dyn =
dynamic_cast<Node*
>(node_to_destroy))
2062 node_alloc_traits::destroy(node_alloc, node_dyn);
2063 node_alloc_traits::deallocate(node_alloc, node_dyn, 1);
2067 template<
typename T>
2068 auto ForwardList<T>::if_valid_iterator(
const const_iterator& pos) ->
bool
2070 bool valid_iterator{};
2071 for (
auto it = cbefore_begin(); it != cend(); ++it)
2075 valid_iterator =
true;
2079 return valid_iterator;
2082 template<
typename T>
2083 auto ForwardList<T>::distance(const_iterator first,
const const_iterator& last) -> size_type
2086 while (first != last)
2095 template<
typename T>
2098 void ForwardList<T>::transfer(
const const_iterator& pos,
ForwardList<T>&& other,
const const_iterator& iter)
2100 if (&other !=
this && other.m_size > 0)
2102 NodeBase* temp_prev{ pos.m_current_node };
2103 NodeBase* temp_next{ iter.m_current_node };
2105 NodeBase* to_move{ temp_next->m_next };
2107 temp_next->m_next = to_move->m_next;
2108 to_move->m_next = temp_prev->m_next;
2109 temp_prev->m_next = to_move;
2116 template<
typename T>
2119 void ForwardList<T>::transfer(
const const_iterator& pos,
ForwardList<T>&& other,
2120 const const_iterator& first,
const const_iterator& last)
2122 if (&other !=
this && other.m_size > 0)
2124 const size_type dist = distance(first, last) - 1;
2126 if (first == last || dist == 0)
2131 NodeBase* temp_prev{ pos.m_current_node };
2132 NodeBase* temp_next{ first.m_current_node };
2134 NodeBase* first_to_move{ temp_next->m_next };
2135 NodeBase* last_to_move{ temp_next };
2136 for (size_type i = 0; i < dist; i++)
2138 last_to_move = last_to_move->m_next;
2141 temp_next->m_next = last_to_move->m_next;
2142 last_to_move->m_next = temp_prev->m_next;
2143 temp_prev->m_next = first_to_move;
2146 other.m_size -= dist;
2150 template<
typename T>
2151 template<
typename Compare>
2154 auto ForwardList<T>::merge_sort(NodeBase* source, Compare comp) -> NodeBase*
2157 if (source ==
nullptr || source->m_next ==
nullptr)
2163 NodeBase* left{ source };
2167 NodeBase* slow{ source };
2168 NodeBase* fast{ source->m_next };
2169 while (fast && fast->m_next)
2171 slow = slow->m_next;
2172 fast = fast->m_next->m_next;
2176 right = slow->m_next;
2177 slow->m_next =
nullptr;
2180 left = merge_sort(left, comp);
2181 right = merge_sort(right, comp);
2184 NodeBase* result{ merge(left, right, comp) };
2188 template<
typename T>
2189 template<
typename Compare>
2195 if (left ==
nullptr)
2199 if (right ==
nullptr)
2205 Node* node_left =
dynamic_cast<Node*
>(left);
2206 Node* node_right =
dynamic_cast<Node*
>(right);
2207 if (node_left && node_right)
2210 if (comp(node_left->m_value, node_right->m_value))
2213 result->m_next = merge(left->m_next, right, comp);
2218 result->m_next = merge(left, right->m_next, comp);
constexpr auto operator==(const Array< T, N > &lhs, const Array< T, N > &rhs) noexcept(noexcept(*lhs.begin()== *rhs.begin())) -> bool
The relational operator compares two Array objects.
constexpr auto operator<=>(const Array< T, N > &lhs, const Array< T, N > &rhs) noexcept(noexcept(*lhs.begin()== *rhs.begin())) -> std::compare_three_way_result_t< T >
The relational operator compares two Array objects.
void swap(Array< T, N > &lhs, Array< T, N > &rhs) noexcept(noexcept(lhs.swap(rhs)))
Exchanges content of two Array containers.
auto operator<<(std::ostream &out, const Array< T, N > &array) -> std::ostream &
Overloads operator to print all elements of Array.
Implements ForwardListIterator.
auto operator!=(const ForwardListIterator< IF_CONST > &other) const -> bool
Overload operator!= for ForwardListIterator objects comparison.
auto operator++(int) -> ForwardListIterator
Overload post-increment operator++ to point ForwardListIterator at next Node.
std::ptrdiff_t difference_type
Alias for pointer difference type.
auto operator->() -> pointer
Overload operator-> to get pointer to Node value / data.
T value_type
Alias for data type used by iterator.
auto operator*() const -> reference
Overload operator* to dereference Node value / data.
iterator_type * pointer
Alias for pointer to data type used by iterator.
auto operator==(const ForwardListIterator< IF_CONST > &other) const -> bool
Overload operator!= for ForwardListIterator objects comparison.
ForwardListIterator() noexcept=default
Construct a new ForwardListIterator object.
std::conditional_t< IF_CONST, const T, T > iterator_type
Alias for iterator type.
iterator_type & reference
Alias for reference to type used by iterator.
auto operator++() -> ForwardListIterator &
Overload pre-increment operator++ to point ForwardListIterator at next Node.
std::forward_iterator_tag iterator_category
Alias for forward iterator tag, define iterator direction.
std::size_t size_type
Alias for size type used in class.
auto operator=(NodeBase *node) -> ForwardListIterator &
Overload operator= to assign node to currently pointed ForwardListIterator.
Struct implements base pointer used by ForwardList.
auto operator=(NodeBase &&other) -> NodeBase &=default
Construct NodeBase object using move assignment.
NodeBase()=default
Construct a new NodeBase object.
NodeBase(NodeBase &&other)=default
Construct NodeBase object using move constructor.
auto operator=(const NodeBase &other) -> NodeBase &=default
Construct a new NodeBase object using copy assignment.
virtual ~NodeBase()=default
Destroy the Node Base object.
NodeBase(const NodeBase &other)=default
Construct a new NodeBase object using copy constructor.
Implements Node class with user data.
auto value() const -> T
Function returns value stored in Node object.
auto value() -> T &
Function returns value stored in Node object.
Node(T &&value)
Construct a new Node object with initial value using move semantics.
Node(const T &value)
Construct a new Node object with initial value.
friend class ForwardList
Forward friend declaration of ForwardList.
Implements ForwardList using Node with pointer to next element as internal base.
void clear()
Function removes all elements of ForwardList.
T value_type
Alias for data type used in class.
value_type & reference
Alias for reference to data type used in class.
auto emplace_front(Args &&... args) -> reference
Inserts a new element to the beginning of the container.
auto max_size() const noexcept -> size_type
Function returns maximum number of elements container can hold.
~ForwardList()
Destroy the ForwardList object.
auto emplace_after(const_iterator pos, Args &&... args) -> iterator
Insert new element into the container after pos.
auto operator=(const ForwardList< T > &other) -> ForwardList &
Constructs ForwardList using copy assignment.
std::allocator< value_type > allocator_type
Alias for memory allocator.
void splice_after(const const_iterator &pos, ForwardList< T > &other)
Function moves elements from other ForwardList object.
auto cend() const noexcept -> const_iterator
Function returns pointer to ForwardList last Node.
const value_type * const_pointer
Alias for const pointer to data type used in class.
ForwardListIterator< true > const_iterator
Alias for const iterator to data type used in class.
auto begin() noexcept -> iterator
Function returns pointer to ForwardList first Node.
void reverse()
Function reverts in place Nodes of ForwardList.
void assign(size_type count, const_reference value)
Function assign values to the ForwardList.
auto before_begin() noexcept -> iterator
Function returns iterator just before ForwardList first Node.
ForwardList()
Construct a new ForwardList object.
void swap(ForwardList< T > &other) noexcept(std::is_nothrow_swappable_v< T >)
Function swaps content of two ForwardList objects.
auto front() -> reference
Function returns reference to value stored in ForwardList first Node.
void pop_front()
Function removes first Node of ForwardList.
const value_type & const_reference
Alias for const reference to data type used in class.
auto cbegin() const noexcept -> const_iterator
Function returns const pointer to ForwardList first Node.
std::ptrdiff_t difference_type
Alias for pointer difference type used in class.
std::size_t size_type
Alias for size type used in class.
void resize(size_type count)
Function resize ForwardList to specified number of elements.
ForwardListIterator< false > iterator
Alias for iterator to data type used in class.
auto empty() const -> bool
Function checks if container has no elements.
auto remove_if(UnaryPred predicate) -> size_type
Function removes all elements for which predicate returns true.
void push_front(const_reference value)
Function adds new Node at the beginning of ForwardList.
auto erase_after(const const_iterator &pos) -> iterator
Function erases Node after specified ForwardList const_iterator.
constexpr auto get_allocator() const -> allocator_type
Get the allocator object.
auto insert_after(const const_iterator &pos, const_reference value) -> iterator
Function inserts new Node after specified ForwardList iterator.
void merge(ForwardList< T > &other)
Function combines two sorted ForwardLists into one sorted ForwardList.
auto end() noexcept -> iterator
Function returns pointer to ForwardList last Node.
auto remove(const_reference value) -> size_type
Function removes all elements equal to value.
auto size() const -> size_type
Function returns ForwardList size.
value_type * pointer
Alias for pointer to data type used in class.
void sort()
Function sorts the elements and preserves the order of equivalent elements.
auto unique() -> size_type
Function removes consecutive duplicated elements.
auto cbefore_begin() const noexcept -> const_iterator
Function returns const_iterator just before ForwardList first Node.
auto erase(ForwardList< T > &container, const U &value) -> ForwardList< T >::size_type
Function erases from container all elements that are equal to value.
auto erase_if(ForwardList< T > &container, Pred pred) -> ForwardList< T >::size_type
Function erases from container all elements that satisfy the predicate pred.