diff --git a/data_structures/arrays/Array.cpp b/data_structures/arrays/Array.cpp new file mode 100644 index 0000000..59df996 --- /dev/null +++ b/data_structures/arrays/Array.cpp @@ -0,0 +1 @@ +#include "Array.h" \ No newline at end of file diff --git a/data_structures/arrays/Array.h b/data_structures/arrays/Array.h new file mode 100644 index 0000000..b134152 --- /dev/null +++ b/data_structures/arrays/Array.h @@ -0,0 +1,1137 @@ +#ifndef DSAA_ARRAY_H +#define DSAA_ARRAY_H + +#include +#include +#include +#include +#include +#include + +#include "test/Test.h" + +namespace dsaa +{ + template > + class Array + { + public: + class ConstIterator; + class Iterator; + + using value_type = Elem; + using allocator_type = Alloc; + using reference = value_type &; + using const_reference = const value_type &; + using pointer = typename std::allocator_traits::pointer; + using const_pointer = typename std::allocator_traits::const_pointer; + using iterator = Iterator; // A random access iterator to value_type. + using const_iterator = ConstIterator; // A random access iterator to const value_type + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + // An unsigned integral type that can represent any non-negative value of difference_type. + using difference_type = typename std::iterator_traits::difference_type; // usually the same as ptrdiff_t. + using size_type = size_t; + + // Returns an iterator pointing to the first element in the container. + constexpr iterator begin() noexcept; + constexpr const_iterator begin() const noexcept; + constexpr const_iterator cbegin() const noexcept; + // Returns an iterator referring to the past-the-end element in the container. + constexpr iterator end() noexcept; + constexpr const_iterator end() const noexcept; + constexpr const_iterator cend() const noexcept; + // Returns a reverse_iterator pointing to the last element in the container. + constexpr reverse_iterator rbegin() noexcept; + constexpr const_reverse_iterator rbegin() const noexcept; + constexpr const_reverse_iterator crbegin() const noexcept; + // Returns a reverse iterator pointing to the theoretical element preceding the first element in the container. + constexpr reverse_iterator rend() noexcept; + constexpr const_reverse_iterator rend() const noexcept; + constexpr const_reverse_iterator crend() const noexcept; + + // Creates a container with no element. + constexpr Array(const allocator_type &p_allocator = allocator_type()) noexcept; + // Creates a container of p_size with default value. + constexpr explicit Array(const size_type &p_size, const allocator_type &p_allocator = allocator_type()); + // Creates a container of p_size and init its element by p_value. + constexpr Array(const size_type &p_size, const_reference p_value, const allocator_type &p_allocator = allocator_type()); + // Creates a container with size of p_elements and init its elements by p_elements's element. + constexpr Array(std::initializer_list p_elements, const allocator_type &p_allocator = allocator_type()); + // Creates a container and init its elements by content of IIterator in range (first, last]. + template + constexpr Array(IIterator p_first, IIterator p_last, const allocator_type &p_allocator = allocator_type()); + // Creates a container by copy all emements from p_other. + constexpr Array(const Array &p_other); + // Creates a container by copy all emements from p_other. + constexpr Array(const Array &p_other, const allocator_type &p_allocator); + // Moves all elements from p_other into this. + constexpr Array(Array &&p_other) noexcept; + // Moves all elements from p_other into this. + constexpr Array(Array &&p_other, const allocator_type &p_allocator) noexcept; + // Destroys old elements and copy all emements from p_other into this. + constexpr Array &operator=(const Array &p_other); + // Destroys old elements and moves all emements from p_other into this. + constexpr Array &operator=(Array &&p_other) noexcept(std::allocator_traits::propagate_on_container_move_assignment::value || std::allocator_traits::is_always_equal::value); + // Destroys old elements and copy all elements from initializer_list. + constexpr Array &operator=(std::initializer_list p_elements); + // Destroys all elements and clean used space. + ~Array(); + + // Assigns new contents to the vector, replacing its current contents, and modifying its size accordingly. + template + constexpr void assign(IIterator p_first, IIterator p_last); + constexpr void assign(size_type p_size, const value_type &p_value = value_type()); + constexpr void assign(std::initializer_list p_elements); + + // Returns a reference to the element at position p_index in the container. + constexpr inline reference operator[](size_type p_index); + constexpr inline const_reference operator[](size_type p_index) const; + // Bounds checking that returns a reference to the element at position p_index in the container. + constexpr inline reference at(const size_type &p_index); + constexpr const_reference at(const size_type &p_index) const; + // Returns a reference to the first element in the container. + constexpr inline reference first(); + constexpr inline const_reference first() const; + // Returns a reference to the last element in the container. + constexpr inline reference last(); + constexpr inline const_reference last() const; + // Returns a direct pointer to the memory array used internally by the container to store its owned elements. + constexpr inline pointer data() noexcept; + constexpr inline const_pointer data() const noexcept; + // Returns a copy of the allocator object associated with the container. + constexpr inline allocator_type get_allocator() const noexcept; + + // Test whether container is empty. + [[nodiscard]] constexpr inline bool empty() const noexcept; + // Returns the size of the storage space currently allocated for the container. + constexpr inline size_type capacity() const noexcept; + // Returns the number of elements in the container. + constexpr inline size_type size() const noexcept; + // Returns the maximum number of elements that the container can hold. + constexpr inline size_type max_size() const noexcept; + // Resizes the container so that it contains p_size elements. + constexpr void resize(const size_type &p_size, const_reference p_value = value_type()); + // Allocates new space and copy elements to new space. + constexpr void reserve(const size_type &p_capacity); + // Requests the container to reduce its capacity to fit its size. + constexpr void shrink_to_fit(); + constexpr inline size_type get_index(const_iterator p_iterator); + constexpr inline iterator get_iterator(size_type p_index); + + // Increase Array size by one, initialize new element with p_value. + constexpr iterator insert_last(const_reference p_value); + constexpr iterator insert_last(value_type &&p_value); + constexpr iterator insert_last(size_type p_size, const_reference p_value); + template + constexpr iterator insert_last(IIterator p_first, IIterator p_last); + template + constexpr iterator emplace_last(Args &&...p_args); + + constexpr iterator insert_at(const_iterator p_position, const_reference p_value); + constexpr iterator insert_at(const_iterator p_position, value_type &&p_value); + constexpr iterator insert_at(const_iterator p_position, size_type p_size, const_reference p_value); + constexpr iterator insert_at(const_iterator p_position, std::initializer_list p_elements); + template + constexpr iterator insert_at(const_iterator p_position, IIterator p_first, IIterator p_last); + template + constexpr iterator emplace_at(const_iterator p_position, Args &&...p_args); + + // Destroy element at p_position and reduce size of container. + constexpr iterator erase_at(const_iterator p_position); + // Destroy element in range (first,last] and reduce size of container. + constexpr iterator erase(const_iterator p_first, const_iterator p_last); + // Removes the last element in the vector, effectively reducing the container size by one. + constexpr void erase_last(); + // Destroys all elements from the container, leaving the size of 0. + constexpr void clear() noexcept; + + // Exchanges the content of the container by the content of p_other, + // which is another Array object of the same type. Sizes may differ. + constexpr void swap(Array &p_other) noexcept(std::allocator_traits::propagate_on_container_swap::value || std::allocator_traits::is_always_equal::value); + + private: + allocator_type m_allocator; + size_type m_capacity; + size_type m_size; + pointer m_elements; + }; +} + +template +class dsaa::Array::ConstIterator +{ +public: + using iterator_category = std::random_access_iterator_tag; + using value_type = Elem; + using difference_type = std::ptrdiff_t; + using pointer = Elem *; + using reference = Elem &; + + ConstIterator() : m_pointer{nullptr} {} + explicit ConstIterator(pointer p_pointer) : m_pointer{p_pointer} {} + ConstIterator(const ConstIterator &p_iterator) : m_pointer{p_iterator.content()} {} + + ConstIterator &operator=(const ConstIterator &p_iterator) + { + m_pointer = p_iterator.content(); + return *this; + } + + virtual ~ConstIterator() {} + + bool operator==(const ConstIterator &p_iterator) const { return m_pointer == p_iterator.m_pointer; } + bool operator!=(const ConstIterator &p_iterator) const { return m_pointer != p_iterator.m_pointer; } + + ConstIterator &operator++() + { + ++m_pointer; + return *this; + } + + ConstIterator operator++(int) + { + ConstIterator old(*this); // copy old value + operator++(); // prefix increment + return old; // return old value + } + + ConstIterator &operator--() + { + --m_pointer; + return *this; + } + + ConstIterator operator--(int) const + { + ConstIterator old(*this); + operator--(); + return old; + } + + ConstIterator operator+(const int64_t &p_rhs) const + { + ConstIterator result; + result.m_pointer = m_pointer + p_rhs; + return result; + } + + ConstIterator operator-(const int64_t &p_rhs) const + { + ConstIterator result; + result.m_pointer = m_pointer - p_rhs; + return result; + } + + ConstIterator operator*(const ConstIterator &p_rhs) const + { + ConstIterator result; + result.m_pointer = m_pointer * p_rhs; + return result; + } + + ConstIterator operator/(const ConstIterator &p_rhs) const + { + ConstIterator result; + result.m_pointer = m_pointer / p_rhs; + return result; + } + + ConstIterator &operator+=(const int64_t &p_rhs) + { + m_pointer += p_rhs; + return *this; + } + + ConstIterator &operator-=(const int64_t &p_rhs) + { + m_pointer -= p_rhs; + return *this; + } + + int64_t operator-(const ConstIterator &p_rhs) const + { + int64_t result{m_pointer - p_rhs.m_pointer}; + return result; + } + + bool operator<(const ConstIterator &p_rhs) const + { + return (m_pointer - p_rhs.m_pointer) < 0; + } + + bool operator>(const ConstIterator &p_rhs) const + { + return 0 < (m_pointer - p_rhs.m_pointer); + } + + bool operator<=(const ConstIterator &p_rhs) const + { + return (m_pointer - p_rhs.m_pointer) <= 0; + } + + bool operator>=(const ConstIterator &p_rhs) const + { + return 0 <= (m_pointer - p_rhs.m_pointer); + } + + const reference operator*() const { return *m_pointer; } + const reference operator[](const int64_t &p_index) const { return m_pointer[p_index]; } + pointer const &content() const { return m_pointer; } + +protected: + pointer m_pointer; +}; + +template +class dsaa::Array::Iterator : public dsaa::Array::ConstIterator +{ +public: + Iterator() : ConstIterator() {} + Iterator(pointer p_pointer) + try : ConstIterator(p_pointer) + { /*function body.*/ + } + catch (...) + { + throw; + } + Iterator(const Iterator &p_iterator) : ConstIterator(p_iterator) {} + Iterator(const ConstIterator &p_iterator) : ConstIterator(p_iterator) {} + + Iterator &operator=(const Iterator &p_iterator) + { + content() = p_iterator.content(); + return *this; + } + + ~Iterator() {} + + bool operator==(const Iterator &p_iterator) const { return content() == p_iterator.content(); } + bool operator!=(const Iterator &p_iterator) const { return content() != p_iterator.content(); } + + Iterator &operator++() + { + ++content(); + return *this; + } + + Iterator operator++(int) + { + Iterator old(*this); // copy old value + operator++(); // prefix increment + return old; // return old value + } + + Iterator &operator--() + { + --content(); + return *this; + } + + Iterator operator--(int) const + { + Iterator old(*this); + operator--(); + return old; + } + + Iterator operator+(const int64_t &p_rhs) const + { + Iterator result; + result.content() = content() + p_rhs; + return result; + } + + Iterator operator-(const int64_t &p_rhs) const + { + Iterator result; + result.content() = content() - p_rhs; + return result; + } + + Iterator operator*(const Iterator &p_rhs) const + { + Iterator result; + result.content() = content() * p_rhs; + return result; + } + + Iterator operator/(const Iterator &p_rhs) const + { + Iterator result; + result.content() = content() / p_rhs; + return result; + } + + Iterator &operator+=(const int64_t &p_rhs) + { + content() += p_rhs; + return *this; + } + + Iterator &operator-=(const int64_t &p_rhs) + { + content() -= p_rhs; + return *this; + } + + int64_t operator-(const Iterator &p_rhs) const + { + int64_t result{content() - p_rhs.content()}; + return result; + } + + bool operator<(const Iterator &p_rhs) const + { + return (content() - p_rhs.content()) < 0; + } + + bool operator>(const Iterator &p_rhs) const + { + return 0 < (content() - p_rhs.content()); + } + + bool operator<=(const Iterator &p_rhs) const + { + return (content() - p_rhs.content()) <= 0; + } + + bool operator>=(const Iterator &p_rhs) const + { + return 0 <= (content() - p_rhs.content()); + } + + reference operator*() { return *ConstIterator::m_pointer; } + reference operator[](const int64_t &p_index) { return ConstIterator::m_pointer[p_index]; } + pointer &content() { return ConstIterator::m_pointer; } + pointer content() const { return ConstIterator::m_pointer; } +}; + +template +constexpr typename dsaa::Array::iterator dsaa::Array::begin() noexcept +{ + return m_elements ? iterator(&m_elements[0]) : iterator(nullptr); +} + +template +constexpr typename dsaa::Array::const_iterator dsaa::Array::begin() const noexcept +{ + return m_elements ? const_iterator(&m_elements[0]) : const_iterator(nullptr); +} + +template +constexpr typename dsaa::Array::const_iterator dsaa::Array::cbegin() const noexcept +{ + return m_elements ? const_iterator(&m_elements[0]) : const_iterator(nullptr); +} + +template +constexpr typename dsaa::Array::iterator dsaa::Array::end() noexcept +{ + return m_elements ? iterator(&m_elements[size()]) : iterator(nullptr); +} + +template +constexpr typename dsaa::Array::const_iterator dsaa::Array::end() const noexcept +{ + return m_elements ? const_iterator(&m_elements[size()]) : const_iterator(nullptr); +} + +template +constexpr typename dsaa::Array::const_iterator dsaa::Array::cend() const noexcept +{ + return m_elements ? const_iterator(&m_elements[size()]) : const_iterator(nullptr); +} + +template +constexpr typename dsaa::Array::reverse_iterator dsaa::Array::rbegin() noexcept +{ + return reverse_iterator(end()); +} + +template +constexpr typename dsaa::Array::const_reverse_iterator dsaa::Array::rbegin() const noexcept +{ + return const_reverse_iterator(end()); +} + +template +constexpr typename dsaa::Array::const_reverse_iterator dsaa::Array::crbegin() const noexcept +{ + return const_reverse_iterator(end()); +} + +template +constexpr typename dsaa::Array::reverse_iterator dsaa::Array::rend() noexcept +{ + return reverse_iterator(begin()); +} + +template +constexpr typename dsaa::Array::const_reverse_iterator dsaa::Array::rend() const noexcept +{ + return const_reverse_iterator(begin()); +} + +template +constexpr typename dsaa::Array::const_reverse_iterator dsaa::Array::crend() const noexcept +{ + return const_reverse_iterator(begin()); +} + +template +constexpr dsaa::Array::Array(const allocator_type &p_allocator) noexcept + : m_allocator{p_allocator}, m_capacity{0}, m_size{0}, m_elements{nullptr} {} + +template +constexpr dsaa::Array::Array(const size_type &p_size, const allocator_type &p_allocator) + : m_allocator{p_allocator}, m_capacity{p_size}, m_size{p_size}, m_elements{nullptr} +{ + m_elements = std::allocator_traits::allocate(m_allocator, capacity()); + for (iterator i{begin()}; i != end(); ++i) + std::allocator_traits::construct(m_allocator, i.content(), value_type()); +} + +template +constexpr dsaa::Array::Array(const size_type &p_size, const_reference p_value, const allocator_type &p_allocator) + : m_allocator{p_allocator}, m_capacity{p_size}, m_size{p_size}, m_elements{nullptr} +{ + m_elements = std::allocator_traits::allocate(m_allocator, capacity()); + for (iterator i{begin()}; i != end(); ++i) + std::allocator_traits::construct(m_allocator, i.content(), p_value); +} + +template +constexpr dsaa::Array::Array(std::initializer_list p_elements, const allocator_type &p_allocator) + : m_allocator{p_allocator}, m_capacity{p_elements.size()}, m_size{p_elements.size()}, m_elements{nullptr} +{ + m_elements = std::allocator_traits::allocate(m_allocator, capacity()); + iterator iter(m_elements); + for (auto i{p_elements.begin()}; i != p_elements.end(); ++i, ++iter) + std::allocator_traits::construct(m_allocator, iter.content(), *i); +} + +template +template +constexpr dsaa::Array::Array(IIterator p_first, IIterator p_last, const allocator_type &p_allocator) + : m_allocator{p_allocator}, m_capacity{0}, m_size{0}, m_elements{nullptr} +{ + while (p_first != p_last) + { + insert_last(*p_first); + ++p_first; + } +} + +template +constexpr dsaa::Array::Array(const Array &p_other) + : m_allocator{std::allocator_traits::select_on_container_copy_construction(p_other.get_allocator())}, + m_capacity{p_other.size()}, m_size{p_other.size()}, m_elements{nullptr} +{ + m_elements = std::allocator_traits::allocate(m_allocator, capacity()); + iterator iter(m_elements); + for (const_iterator i{p_other.begin()}; i != p_other.end(); ++i, ++iter) + std::allocator_traits::construct(m_allocator, iter.content(), *i); +} + +template +constexpr dsaa::Array::Array(const Array &p_other, const allocator_type &p_allocator) + : m_allocator{p_allocator}, m_capacity{p_other.size()}, m_size{p_other.size()}, m_elements{nullptr} +{ + m_elements = std::allocator_traits::allocate(m_allocator, capacity()); + iterator iter(m_elements); + for (const_iterator i{p_other.begin()}; i != p_other.end(); ++i, ++iter) + std::allocator_traits::construct(m_allocator, iter.content(), *i); +} + +template +constexpr dsaa::Array::Array(Array &&p_other) noexcept + : m_allocator{std::allocator_traits::select_on_container_copy_construction(p_other.get_allocator())}, + m_capacity{p_other.capacity()}, m_size{p_other.size()}, m_elements{p_other.m_elements} +{ + p_other.m_allocator = allocator_type(); + p_other.m_capacity = 0; + p_other.m_size = 0; + p_other.m_elements = nullptr; +} + +template +constexpr dsaa::Array::Array(Array &&p_other, const allocator_type &p_allocator) noexcept + : m_allocator{p_allocator}, m_capacity{p_other.capacity()}, m_size{p_other.size()}, m_elements{p_other.m_elements} +{ + p_other.m_allocator = allocator_type(); + p_other.m_capacity = 0; + p_other.m_size = 0; + p_other.m_elements = nullptr; +} + +template +constexpr dsaa::Array &dsaa::Array::operator=(const Array &p_other) +{ + // Avoid self-reference. + if (this == &p_other) + return *this; + + // No need to allocate new space if we already have enough capacity. + if (p_other.size() <= capacity()) + { + // Destroy old elements. + for (iterator i{begin()}; i != end(); ++i) + std::allocator_traits::destroy(m_allocator, i.content()); + // Copy. + iterator iter(m_elements); + for (const_iterator i{p_other.begin()}; i != p_other.end(); ++i, ++iter) + std::allocator_traits::construct(m_allocator, iter.content(), *i); + + m_size = p_other.size(); + return *this; + } + + // Quarantees elements are copies and no error happens before delete old elements. + pointer elements{std::allocator_traits::allocate(m_allocator, p_other.size())}; + iterator iter(elements); + for (const_iterator i{p_other.begin()}; i != p_other.end(); ++i, ++iter) + std::allocator_traits::construct(m_allocator, iter.content(), *i); + // Destroy old elements. + for (iterator i{begin()}; i != end(); ++i) + std::allocator_traits::destroy(m_allocator, i.content()); + + std::allocator_traits::deallocate(m_allocator, m_elements, capacity()); + m_capacity = m_size = p_other.size(); + m_elements = elements; + return *this; +} + +template +constexpr dsaa::Array &dsaa::Array::operator=(Array &&p_other) noexcept(std::allocator_traits::propagate_on_container_move_assignment::value || std::allocator_traits::is_always_equal::value) +{ + for (iterator i{begin()}; i != end(); ++i) + std::allocator_traits::destroy(m_allocator, i.content()); + + std::allocator_traits::deallocate(m_allocator, m_elements, capacity()); + + // Difference allocator may throw...! + m_allocator = std::allocator_traits::select_on_container_copy_construction(p_other.get_allocator()); + m_capacity = p_other.capacity(); + m_size = p_other.size(); + m_elements = p_other.m_elements; + + p_other.m_allocator = allocator_type(); + p_other.m_capacity = 0; + p_other.m_size = 0; + p_other.m_elements = nullptr; + + return *this; +} + +template +constexpr dsaa::Array &dsaa::Array::operator=(std::initializer_list p_elements) +{ + // Quarantees elements are copies and no error happens before delete old elements. + pointer elements = std::allocator_traits::allocate(m_allocator, p_elements.size()); + iterator iter(elements); + for (auto i{p_elements.begin()}; i != p_elements.end(); ++i, ++iter) + std::allocator_traits::construct(m_allocator, iter.content(), *i); + + // Destroy old elements. + for (iterator i{begin()}; i != end(); ++i) + std::allocator_traits::destroy(m_allocator, i.content()); + + std::allocator_traits::deallocate(m_allocator, m_elements, capacity()); + + m_capacity = m_size = p_elements.size(); + m_elements = elements; + return *this; +} + +template +dsaa::Array::~Array() +{ + for (iterator i{begin()}; i != end(); ++i) + std::allocator_traits::destroy(m_allocator, i.content()); + + std::allocator_traits::deallocate(m_allocator, m_elements, capacity()); +} + +// Assigns new contents to the vector, replacing its current contents, and modifying its size accordingly. +template +template +constexpr void dsaa::Array::assign(IIterator p_first, IIterator p_last) +{ + for (iterator i{begin()}; i != end(); ++i) + std::allocator_traits::destroy(m_allocator, i.content()); + + std::allocator_traits::deallocate(m_allocator, m_elements, capacity()); + + while (p_first != p_last) + { + insert_last(*p_first); + ++p_first; + } +} + +template +constexpr void dsaa::Array::assign(size_type p_size, const value_type &p_value) +{ + // Allocate new space. + pointer elements = std::allocator_traits::allocate(m_allocator, p_size); + for (size_type i = 0; i < p_size; ++i) + std::allocator_traits::construct(m_allocator, &elements[i], p_value); + + // Clean up old allocated space. + for (iterator i{begin()}; i != end(); ++i) + std::allocator_traits::destroy(m_allocator, i.content()); + std::allocator_traits::deallocate(m_allocator, m_elements, capacity()); + + m_capacity = m_size = p_size; + m_elements = elements; +} + +template +constexpr void dsaa::Array::assign(std::initializer_list p_elements) +{ + // Quarantees elements are copies and no error happens before delete old elements. + pointer elements = std::allocator_traits::allocate(m_allocator, p_elements.size()); + iterator iter(elements); + for (auto i{p_elements.begin()}; i != p_elements.end(); ++i, ++iter) + std::allocator_traits::construct(m_allocator, iter.content(), *i); + + // Destroy old elements. + for (iterator i{begin()}; i != end(); ++i) + std::allocator_traits::destroy(m_allocator, i.content()); + + std::allocator_traits::deallocate(m_allocator, m_elements, capacity()); + + m_capacity = m_size = p_elements.size(); + m_elements = elements; +} + +template +constexpr typename dsaa::Array::reference dsaa::Array::operator[](size_type p_index) +{ + return m_elements[p_index]; +} + +template +constexpr typename dsaa::Array::const_reference dsaa::Array::operator[](size_type p_index) const +{ + return m_elements[p_index]; +} + +template +constexpr typename dsaa::Array::reference dsaa::Array::at(const size_type &p_index) +{ + if (p_index < 0 || size() <= p_index) + throw std::out_of_range("p_index out of range exception.\n;"); + + return m_elements[p_index]; +} + +template +constexpr typename dsaa::Array::const_reference dsaa::Array::at(const size_type &p_index) const +{ + if (p_index < 0 || size() <= p_index) + throw std::out_of_range("p_index out of range exception.\n"); + + return m_elements[p_index]; +} + +template +constexpr typename dsaa::Array::reference dsaa::Array::first() +{ + return m_elements[0]; +} + +template +constexpr typename dsaa::Array::const_reference dsaa::Array::first() const +{ + return m_elements[0]; +} + +template +constexpr typename dsaa::Array::reference dsaa::Array::last() +{ + return m_elements[size() - 1]; +} + +template +constexpr typename dsaa::Array::const_reference dsaa::Array::last() const +{ + return m_elements[size() - 1]; +} + +template +constexpr typename dsaa::Array::pointer dsaa::Array::data() noexcept +{ + return m_elements; +} + +template +constexpr typename dsaa::Array::const_pointer dsaa::Array::data() const noexcept +{ + return m_elements; +} + +template +constexpr typename dsaa::Array::allocator_type dsaa::Array::get_allocator() const noexcept +{ + return m_allocator; +} + +template +constexpr bool dsaa::Array::empty() const noexcept +{ + return size() == 0; +} + +template +constexpr typename dsaa::Array::size_type dsaa::Array::capacity() const noexcept +{ + return m_capacity; +} + +template +constexpr typename dsaa::Array::size_type dsaa::Array::size() const noexcept +{ + return m_size; +} + +template +constexpr typename dsaa::Array::size_type dsaa::Array::max_size() const noexcept +{ + return std::numeric_limits::max() / sizeof(value_type); +} + +template +constexpr void dsaa::Array::resize(const size_type &p_size, const value_type &p_value) +{ + reserve(p_size); + if (size() <= p_size) + { + iterator from{end()}, to{get_iterator(size() + p_size)}; + while (from != to) + { + std::allocator_traits::construct(m_allocator, from.content(), p_value); + ++from; + } + } + else + { + iterator from{get_iterator(p_size)}, to{end()}; + while (from != to) + { + std::allocator_traits::destroy(m_allocator, from.content()); + ++from; + } + } + + m_size = p_size; +} + +template +constexpr void dsaa::Array::reserve(const size_type &p_capacity) +{ + // Never decrease allocation. + if (p_capacity <= m_capacity) + return; + + pointer elements = std::allocator_traits::allocate(m_allocator, p_capacity); + // Copy old element to new place. + iterator iter(elements); + for (iterator i{begin()}; i != end(); ++i, ++iter) + std::allocator_traits::construct(m_allocator, iter.content(), *i); + // Clean up old allocated space. + for (iterator i{begin()}; i != end(); ++i) + std::allocator_traits::destroy(m_allocator, i.content()); + std::allocator_traits::deallocate(m_allocator, m_elements, capacity()); + + m_capacity = p_capacity; + m_elements = elements; +} + +// Requests the container to reduce its capacity to fit its size. +template +constexpr void dsaa::Array::shrink_to_fit() +{ + if (size() == capacity()) + return; + // Allocate new space. + pointer elements = std::allocator_traits::allocate(m_allocator, size()); + // Copy old element to new place. + iterator iter(elements); + for (const_iterator i{begin()}; i != end(); ++i, ++iter) + std::allocator_traits::construct(m_allocator, iter.content(), *i); + // Clean up old allocated space. + for (iterator i{begin()}; i != end(); ++i) + std::allocator_traits::destroy(m_allocator, i.content()); + + std::allocator_traits::deallocate(m_allocator, m_elements, capacity()); + + m_capacity = size(); + m_elements = elements; +} + +template +constexpr typename dsaa::Array::size_type dsaa::Array::get_index(const_iterator p_iterator) +{ + return p_iterator - begin(); +} + +template +constexpr typename dsaa::Array::iterator dsaa::Array::get_iterator(size_type p_index) +{ + return begin() + p_index; +} + +template +constexpr typename dsaa::Array::iterator dsaa::Array::insert_last(const_reference p_value) +{ + if (size() == capacity()) + reserve(size() == 0 ? 8 : 2 * size()); // Make sure we have enough space. + + std::allocator_traits::construct(m_allocator, end().content(), p_value); + ++m_size; + return iterator(end() - 1); +} + +template +constexpr typename dsaa::Array::iterator dsaa::Array::insert_last(value_type &&p_value) +{ + if (size() == capacity()) + reserve(size() == 0 ? 8 : 2 * size()); // Make sure we have enough space. + std::allocator_traits::construct(m_allocator, end().content(), std::move(p_value)); + ++m_size; + return end() - 1; +} + +template +constexpr typename dsaa::Array::iterator dsaa::Array::insert_last(size_type p_size, const_reference p_value) +{ + size_type num_elem{p_size}; + while (num_elem--) + insert_last(p_value); + + return end() - 1; +} + +template +template +constexpr typename dsaa::Array::iterator dsaa::Array::insert_last(IIterator p_first, IIterator p_last) +{ + while (p_first != p_last) + { + insert_last(*p_first); + ++p_first; + } + return end() - 1; +} + +template +template +constexpr typename dsaa::Array::iterator dsaa::Array::emplace_last(Args &&...p_args) +{ + // if (size() == capacity()) + // reserve(size() == 0 ? 8 : 2 * size()); // Make sure we have enough space. + // std::allocator_traits::construct(m_allocator, end(), p_args); + // ++m_size; + // return end() - 1; +} + +template +constexpr typename dsaa::Array::iterator dsaa::Array::insert_at(const_iterator p_position, const_reference p_value) +{ + size_t index{get_index(p_position)}; // reserve can make iterator to p_position become invalid. + if (size() == capacity()) + reserve(size() == 0 ? 8 : 2 * size()); // Make sure we have enough space. + + // First copy last element into uninitialized space. + std::allocator_traits::construct(m_allocator, end().content(), last()); + ++m_size; + + iterator desired{get_iterator(index)}; // The place to put value. + for (iterator last_elem{&last()}; last_elem != desired; --last_elem) + *last_elem = *(last_elem - 1); // Copy element one position to the right. + + *desired = p_value; // Insert value; + + return desired; +} + +template +constexpr typename dsaa::Array::iterator dsaa::Array::insert_at(const_iterator p_position, value_type &&p_value) +{ + size_t index{get_index(p_position)}; + if (size() == capacity()) + reserve(size() == 0 ? 8 : 2 * size()); // Make sure we have enough space. + + // First copy last element into uninitialized space. + std::allocator_traits::construct(m_allocator, end().content(), last()); + ++m_size; + + iterator position{get_iterator(index)}; // The place to put value. + for (iterator last_elem{end() - 1}; last_elem != position; --last_elem) + *last_elem = *(last_elem - 1); // Copy element one position to the right. + + *position = std::move(p_value); // Insert value; + + return position; +} +template +constexpr typename dsaa::Array::iterator dsaa::Array::insert_at(const_iterator p_position, size_type p_size, const_reference p_value) +{ + { + size_type index{get_index(p_position)}; + + if (capacity() < size() + p_size) + reserve(size() + p_size); + + iterator pivot{get_iterator(index)}; + iterator convey{get_iterator(size() - 1)}; + iterator target{get_iterator(size() + p_size - 1)}; + + while (pivot <= convey) + { + std::allocator_traits::construct(m_allocator, target.content(), *convey); + std::allocator_traits::destroy(m_allocator, convey.content()); + --target; + --convey; + } + ++convey; + ++target; + while (convey != target) + { + std::allocator_traits::construct(m_allocator, convey.content(), p_value); + ++convey; + } + + m_size += p_size; + + return --convey; + } +} + +template +constexpr typename dsaa::Array::iterator dsaa::Array::insert_at(const_iterator p_position, std::initializer_list p_elements) +{ + size_type index{get_index(p_position)}; + + if (capacity() < size() + p_elements.size()) + reserve(size() + p_elements.size()); + + iterator pivot{get_iterator(index)}; + iterator convey{get_iterator(size() - 1)}; + iterator target{get_iterator(size() + p_elements.size() - 1)}; + + while (pivot <= convey) + { + std::allocator_traits::construct(m_allocator, target.content(), *convey); + std::allocator_traits::destroy(m_allocator, convey.content()); + --target; + --convey; + } + ++convey; + ++target; + for (auto iter{p_elements.begin()}; iter != p_elements.end(); ++iter, ++convey) + std::allocator_traits::construct(m_allocator, convey.content(), *iter); + + m_size += p_elements.size(); + + return --convey; +} + +template +template +constexpr typename dsaa::Array::iterator dsaa::Array::insert_at(const_iterator p_position, IIterator p_first, IIterator p_last) +{ + size_type index{get_index(p_position)}; + size_type count_size{0}; + for (auto i{p_first}; i != p_last; ++i) + ++count_size; + if (capacity() < size() + count_size) + reserve(size() + count_size); + + iterator pivot{get_iterator(index)}; + iterator convey{get_iterator(size() - 1)}; + iterator target{get_iterator(size() + count_size - 1)}; + + while (pivot <= convey) + { + std::allocator_traits::construct(m_allocator, target.content(), *convey); + std::allocator_traits::destroy(m_allocator, convey.content()); + --target; + --convey; + } + ++convey; + ++target; + while (p_first != p_last) + { + std::allocator_traits::construct(m_allocator, convey.content(), *p_first); + ++p_first; + ++convey; + } + + m_size += count_size; + + return --convey; +} + +template +template +constexpr typename dsaa::Array::iterator dsaa::Array::emplace_at(const_iterator p_position, Args &&...p_args) +{ +} + +template +constexpr typename dsaa::Array::iterator dsaa::Array::erase_at(const_iterator p_position) +{ + iterator position(p_position + 1); + for (; position != end(); ++position) + { + *(position - 1) = *position; + } + + erase_last(); + return position; +} + +template +constexpr typename dsaa::Array::iterator dsaa::Array::erase(const_iterator p_first, const_iterator p_last) +{ + iterator first(p_first), last(p_last); + + while (last != end()) + { + *first = *last; + ++first; + ++last; + } + + while (first != end()) + erase_last(); + return first; +} + +template +constexpr void dsaa::Array::erase_last() +{ + std::allocator_traits::destroy(m_allocator, iterator(&last()).content()); + --m_size; +} + +template +constexpr void dsaa::Array::clear() noexcept +{ + // Clean up all elements. + for (iterator i{begin()}; i != end(); ++i) + std::allocator_traits::destroy(m_allocator, i.content()); + + m_size = 0; +} + +// template +// constexpr void dsaa::Array::swap(Array &p_other) noexcept(std::allocator_traits::propagate_on_container_swap::value || std::allocator_traits::is_always_equal::value) +// { +// } + +#endif // !DSAA_ARRAY_H \ No newline at end of file diff --git a/data_structures/arrays/Vector.h b/data_structures/arrays/Vector.h deleted file mode 100644 index 87355e0..0000000 --- a/data_structures/arrays/Vector.h +++ /dev/null @@ -1,665 +0,0 @@ -#ifndef VECTOR_H -#define VECTOR_H - -#include -#include -#include -#include -#include - -namespace dsaa -{ - template > - class Vector - { - public: - using value_type = Elem; - using const_value_type = const value_type; - using reference = value_type &; - using const_reference = const value_type &; - using allocator_type = Alloc; - using size_type = size_t; - using pointer = typename std::allocator_traits::pointer; // Equivalent to: value_type* - using const_pointer = typename std::allocator_traits::const_pointer; // Equivalent to: const value_type* - using iterator = value_type *; // A random access iterator to value_type. - using const_iterator = const value_type *; // A random access iterator to const value_type - using reverse_iterator = std::reverse_iterator; - using const_reverse_iterator = std::reverse_iterator; - // An unsigned integral type that can represent any non-negative value of difference_type usually the same as size_t. - using difference_type = typename std::iterator_traits::difference_type; // usually the same as ptrdiff_t. - - // Returns an iterator pointing to the first element in the vector. - iterator begin() noexcept; - const_iterator begin() const noexcept; - // Returns an iterator referring to the past-the-end element in the vector container. - iterator end() noexcept; - const_iterator end() const noexcept; - // Returns a reverse iterator pointing to the last element in the vector (i.e., its reverse beginning). - reverse_iterator rbegin() noexcept; - const_reverse_iterator rbegin() const noexcept; - // Returns a reverse iterator pointing to the theoretical element preceding the first element in the vector - // (which is considered its reverse end). - reverse_iterator rend() noexcept; - const_reverse_iterator rend() const noexcept; - // Returns a const_iterator pointing to the first element in the container. - const_iterator cbegin() const noexcept; - // Returns a const_iterator pointing to the past-the-end element in the container. - const_iterator cend() const noexcept; - // Returns a const_reverse_iterator pointing to the last element in the container (i.e., its reverse beginning). - const_reverse_iterator crbegin() const noexcept; - // Returns a const_reverse_iterator pointing to the theoretical element preceding the first element in the container - // (which is considered its reverse end). - const_reverse_iterator crend() const noexcept; - - Vector(const allocator_type &p_allocator = allocator_type()); - explicit Vector(const size_type &p_size, const allocator_type &p_allocator = allocator_type()); - Vector(const size_type &p_size, const_reference p_value, const allocator_type &p_allocator = allocator_type()); - Vector(const Vector &p_other); - Vector(const Vector &p_other, const allocator_type &p_allocator); - Vector(Vector &&p_other); - Vector(Vector &&p_other, const allocator_type &p_allocator); - Vector &operator=(const Vector &p_other); - Vector &operator=(Vector &&p_other); - Vector &operator=(std::initializer_list p_elements); - Vector(std::initializer_list p_elements, const allocator_type &p_allocator = allocator_type()); - template - Vector(IIterator p_first, IIterator p_last, const allocator_type &p_allocator = allocator_type()); - ~Vector(); - - // Returns a reference to the element at position p_index in the vector container. - reference operator[](size_type p_index); - const_reference operator[](size_type p_index) const; - // Returns a reference to the element at position p_index in the vector. - reference at(const size_type &p_index); - const_reference at(const size_type &p_index) const; - // Returns a reference to the first element in the vector. - reference front(); - const_reference front() const; - // Returns a reference to the last element in the vector. - reference back(); - const_reference back() const; - // Returns a direct pointer to the memory array used internally by the vector to store its owned elements. - pointer data() noexcept; - const_pointer data() const noexcept; - // Returns a copy of the allocator object associated with the vector. - allocator_type get_allocator() const noexcept; - // Test whether vector is empty. - bool empty() const noexcept; - // Returns the size of the storage space currently allocated for the Vector. - size_type capacity() const noexcept; - // Returns the number of elements in the Vector. - size_type size() const noexcept; - // Returns the maximum number of elements that the Vector can hold. - size_type max_size() const noexcept; - // Resizes the container so that it contains p_size elements. - void resize(const size_type &p_size, const value_type &p_value = value_type()); - // Allocates new space and copy elements to new space. - void reserve(const size_type &p_capacity); - // Requests the container to reduce its capacity to fit its size. - void shrink_to_fit(); - // Increase Vector size by one, initialize new element with p_value. - void push_back(const_reference p_value = value_type()); - void push_back(value_type &&p_value); - // Removes the last element in the vector, effectively reducing the container size by one. - void pop_back(); - iterator insert(const_iterator p_position, const_reference p_value); - // Inserts p_size elements and init it with value p_value start from p_position. - iterator insert(const_iterator p_position, size_type p_size, const_reference p_value); - // Copies of the elements in the range [first,last) are inserted at position (in the same order). - template - iterator insert(const_iterator p_position, IIterator p_first, IIterator p_last); - iterator insert(const_iterator p_position, value_type &&p_value); - iterator insert(const_iterator p_position, std::initializer_list p_list); - // Removes from the vector a single element (position). - // This effectively reduces the container size by the number of elements removed, which are destroyed. - iterator erase(const_iterator p_position); - // Removes from the vector a range of elements ([first,last)). - // This effectively reduces the container size by the number of elements removed, which are destroyed. - iterator erase(const_iterator p_first, const_iterator p_last); - // Exchanges the content of the container by the content of p_other, - // which is another vector object of the same type. Sizes may differ. - void swap(Vector &p_other); - // Removes all elements from the vector (which are destroyed), leaving the container with a size of 0. - void clear() noexcept; - // Assigns new contents to the vector, replacing its current contents, and modifying its size accordingly. - template - void assign(BIterator p_first, BIterator p_last); - void assign(size_type p_size, const value_type &p_value = value_type()); - void assign(std::initializer_list p_list); - - private: - allocator_type m_allocator; - size_type m_capacity; - size_type m_size; - pointer m_elements; - }; -} - -template -typename dsaa::Vector::iterator dsaa::Vector::begin() noexcept -{ - return m_elements ? iterator(&m_elements[0]) : iterator(nullptr); -} - -template -typename dsaa::Vector::const_iterator dsaa::Vector::begin() const noexcept -{ - return m_elements ? const_iterator(&m_elements[0]) : const_iterator(nullptr); -} - -template -typename dsaa::Vector::iterator dsaa::Vector::end() noexcept -{ - return m_elements ? iterator(&m_elements[size()]) : iterator(nullptr); -} - -template -typename dsaa::Vector::const_iterator dsaa::Vector::end() const noexcept -{ - return m_elements ? const_iterator(&m_elements[size()]) : const_iterator(nullptr); -} - -template -typename dsaa::Vector::reverse_iterator dsaa::Vector::rbegin() noexcept -{ - return reverse_iterator(end()); -} - -template -typename dsaa::Vector::const_reverse_iterator dsaa::Vector::rbegin() const noexcept -{ - return const_reverse_iterator(end()); -} - -template -typename dsaa::Vector::reverse_iterator dsaa::Vector::rend() noexcept -{ - return reverse_iterator(begin()); -} - -template -typename dsaa::Vector::const_reverse_iterator dsaa::Vector::rend() const noexcept -{ - return const_reverse_iterator(begin()); -} - -template -typename dsaa::Vector::const_iterator dsaa::Vector::cbegin() const noexcept -{ - return m_elements ? const_iterator(&m_elements[0]) : const_iterator(nullptr); -} - -template -typename dsaa::Vector::const_iterator dsaa::Vector::cend() const noexcept -{ - return m_elements ? const_iterator(&m_elements[size()]) : const_iterator(nullptr); -} - -template -typename dsaa::Vector::const_reverse_iterator dsaa::Vector::crbegin() const noexcept -{ - return const_reverse_iterator(end()); -} - -template -typename dsaa::Vector::const_reverse_iterator dsaa::Vector::crend() const noexcept -{ - return const_reverse_iterator(begin()); -} - -template -dsaa::Vector::Vector(const allocator_type &p_allocator) - : m_allocator{p_allocator}, m_capacity{0}, m_size{0}, m_elements{nullptr} {} - -template -dsaa::Vector::Vector(const size_type &p_size, const allocator_type &p_allocator) - : m_allocator{p_allocator}, m_capacity{p_size}, m_size{p_size}, m_elements{nullptr} -{ - m_elements = std::allocator_traits::allocate(m_allocator, capacity()); - for (iterator i{begin()}; i != end(); ++i) - std::allocator_traits::construct(m_allocator, i, value_type()); -} - -template -dsaa::Vector::Vector(const size_type &p_size, const_reference p_value, const allocator_type &p_allocator) - : m_allocator{p_allocator}, m_capacity{p_size}, m_size{p_size}, m_elements{nullptr} -{ - m_elements = std::allocator_traits::allocate(m_allocator, capacity()); - - for (iterator i{begin()}; i != end(); ++i) - std::allocator_traits::construct(m_allocator, i, p_value); -} - -template -dsaa::Vector::Vector(const Vector &p_other) - : m_allocator{std::allocator_traits::select_on_container_copy_construction(p_other.m_allocator)}, - m_capacity{p_other.size()}, m_size{p_other.size()}, m_elements{nullptr} -{ - m_elements = std::allocator_traits::allocate(m_allocator, capacity()); - pointer temp_p{m_elements}; - for (const_iterator i{p_other.begin()}; i != p_other.end(); ++i, ++temp_p) - std::allocator_traits::construct(m_allocator, temp_p, *i); -} - -template -dsaa::Vector::Vector(const Vector &p_other, const allocator_type &p_allocator) - : m_allocator{p_allocator}, m_capacity{p_other.size()}, m_size{p_other.size()}, m_elements{nullptr} -{ - m_elements = std::allocator_traits::allocate(m_allocator, capacity()); - pointer temp_p{m_elements}; - for (const_iterator i{p_other.begin()}; i != p_other.end(); ++i, ++temp_p) - std::allocator_traits::construct(m_allocator, temp_p, *i); -} - -template -dsaa::Vector::Vector(Vector &&p_other) - : m_capacity{p_other.capacity()}, m_size{p_other.size()}, m_elements{p_other.m_elements} -{ - m_allocator = std::allocator_traits::select_on_container_copy_construction(p_other.m_allocator); - - p_other.m_allocator = allocator_type(); - p_other.m_capacity = 0; - p_other.m_size = 0; - p_other.m_elements = nullptr; -} - -template -dsaa::Vector::Vector(Vector &&p_other, const allocator_type &p_allocator) - : m_allocator{p_allocator}, m_capacity{p_other.capacity()}, m_size{p_other.size()}, m_elements{p_other.m_elements} -{ - p_other.m_allocator = allocator_type(); - p_other.m_capacity = 0; - p_other.m_size = 0; - p_other.m_elements = nullptr; -} - -template -dsaa::Vector &dsaa::Vector::operator=(const Vector &p_other) -{ - // Avoid self-reference. - if (this == &p_other) - return *this; - - // No need to allocate new space if we already have enough capacity. - if (p_other.size() <= capacity()) - { - // Destroy old elements. - for (iterator i{begin()}; i != end(); ++i) - std::allocator_traits::destroy(m_allocator, i); - // Copy. - pointer temp_p{m_elements}; - for (const_iterator i{p_other.begin()}; i != p_other.end(); ++i, ++temp_p) - std::allocator_traits::construct(m_allocator, temp_p, *i); - - m_size = p_other.size(); - return *this; - } - - // Quarantees elements are copies and no error happens before delete old elements. - pointer elements = std::allocator_traits::allocate(m_allocator, p_other.size()); - pointer temp_p = elements; - for (const_iterator i{p_other.begin()}; i != p_other.end(); ++i, ++temp_p) - std::allocator_traits::construct(m_allocator, temp_p, *i); - // Destroy old elements. - for (iterator i{begin()}; i != end(); ++i) - std::allocator_traits::destroy(m_allocator, i); - - std::allocator_traits::deallocate(m_allocator, m_elements, capacity()); - m_capacity = m_size = p_other.size(); - m_elements = elements; - return *this; -} - -template -dsaa::Vector &dsaa::Vector::operator=(Vector &&p_other) -{ - for (iterator i{begin()}; i != end(); ++i) - std::allocator_traits::destroy(m_allocator, i); - - std::allocator_traits::deallocate(m_allocator, m_elements, capacity()); - - m_allocator = std::allocator_traits::select_on_container_copy_construction(p_other.m_allocator); - m_capacity = p_other.capacity(); - m_size = p_other.size(); - m_elements = p_other.m_elements; - - p_other.m_allocator = allocator_type(); - p_other.m_capacity = 0; - p_other.m_size = 0; - p_other.m_elements = nullptr; - - return *this; -} - -template -dsaa::Vector &dsaa::Vector::operator=(std::initializer_list p_elements) -{ - // Quarantees elements are copies and no error happens before delete old elements. - pointer elements = std::allocator_traits::allocate(m_allocator, p_elements.size()); - pointer temp_p = elements; - for (auto i{p_elements.begin()}; i != p_elements.end(); ++i, ++temp_p) - std::allocator_traits::construct(m_allocator, temp_p, *i); - - // Destroy old elements. - for (iterator i{begin()}; i != end(); ++i) - std::allocator_traits::destroy(m_allocator, i); - - std::allocator_traits::deallocate(m_allocator, m_elements, capacity()); - - m_capacity = m_size = p_elements.size(); - m_elements = elements; -} - -template -dsaa::Vector::Vector(std::initializer_list p_list, const allocator_type &p_allocator) - : m_allocator{p_allocator}, m_capacity{p_list.size()}, m_size{p_list.size()}, m_elements{nullptr} -{ - m_elements = std::allocator_traits::allocate(m_allocator, capacity()); - pointer temp_p = m_elements; - for (auto i{p_list.begin()}; i != p_list.end(); ++i, ++temp_p) - std::allocator_traits::construct(m_allocator, temp_p, *i); -} - -template -template -dsaa::Vector::Vector(IIterator p_first, IIterator p_last, const allocator_type &p_allocator) - : m_allocator{p_allocator}, m_capacity{0}, m_size{0}, m_elements{nullptr} -{ - resize(10); - for (size_type index{0}, count{0}; p_first != p_last; ++p_first, ++index, ++count) - { - if (capacity() == count) - resize(size() * 2); - - std::allocator_traits::construct(m_allocator, &m_elements[index], *p_first); - } -} - -template -dsaa::Vector::~Vector() -{ - for (iterator i{begin()}; i != end(); ++i) - std::allocator_traits::destroy(m_allocator, i); - - std::allocator_traits::deallocate(m_allocator, m_elements, capacity()); -} - -template -typename dsaa::Vector::reference dsaa::Vector::operator[](size_type p_index) -{ - return m_elements[p_index]; -} - -template -typename dsaa::Vector::const_reference dsaa::Vector::operator[](size_type p_index) const -{ - return m_elements[p_index]; -} - -template -typename dsaa::Vector::reference dsaa::Vector::at(const size_type &p_index) -{ - if (p_index < 0 || size() <= p_index) - throw std::out_of_range("p_index out of range exception.\n;"); - - return m_elements[p_index]; -} - -template -typename dsaa::Vector::const_reference dsaa::Vector::at(const size_type &p_index) const -{ - if (p_index < 0 || size() <= p_index) - throw std::out_of_range("p_index out of range exception.\n"); - - return m_elements[p_index]; -} - -template -typename dsaa::Vector::reference dsaa::Vector::front() -{ - return m_elements[0]; -} - -template -typename dsaa::Vector::const_reference dsaa::Vector::front() const -{ - return m_elements[0]; -} - -template -typename dsaa::Vector::reference dsaa::Vector::back() -{ - return m_elements[size() - 1]; -} - -template -typename dsaa::Vector::const_reference dsaa::Vector::back() const -{ - return m_elements[size() - 1]; -} - -template -typename dsaa::Vector::pointer dsaa::Vector::data() noexcept -{ - return m_elements; -} - -template -typename dsaa::Vector::const_pointer dsaa::Vector::data() const noexcept -{ - return m_elements; -} - -template -typename dsaa::Vector::allocator_type dsaa::Vector::get_allocator() const noexcept -{ - return m_allocator; -} - -template -bool dsaa::Vector::empty() const noexcept -{ - return begin() == end(); -} - -template -typename dsaa::Vector::size_type dsaa::Vector::capacity() const noexcept -{ - return m_capacity; -} - -template -typename dsaa::Vector::size_type dsaa::Vector::size() const noexcept -{ - return m_size; -} - -template -typename dsaa::Vector::size_type dsaa::Vector::max_size() const noexcept -{ - return std::numeric_limits::max() / sizeof(value_type); -} - -template -void dsaa::Vector::resize(const size_type &p_size, const value_type &p_value) -{ - reserve(p_size); - - if (size() <= p_size) - { - iterator begin(iterator(size())), end(iterator(p_size)); - for (iterator i(begin); i != end; ++i) - std::iterator_traits::construct(m_allocator, i, p_value); - } - else - { - iterator begin(iterator(p_size)), end(iterator(size())); - for (iterator i(begin); i != end; ++i) - std::iterator_traits::destroy(m_allocator, i); - } - - m_size = p_size; -} - -template -void dsaa::Vector::reserve(const size_type &p_capacity) -{ - // Never decrease allocation. - if (p_capacity <= m_capacity) - return; - - pointer elements = std::allocator_traits::allocate(m_allocator, p_capacity); - // Copy old element to new place. - pointer temp_p{elements}; - for (const_iterator i{begin()}; i != end(); ++i, ++temp_p) - std::allocator_traits::construct(m_allocator, temp_p, *i); - // Clean up old allocated space. - for (iterator i{begin()}; i != end(); ++i) - std::allocator_traits::destroy(m_allocator, i); - std::allocator_traits::deallocate(m_allocator, m_elements, capacity()); - - m_capacity = p_capacity; - m_elements = elements; -} - -// Requests the container to reduce its capacity to fit its size. -template -void dsaa::Vector::shrink_to_fit() -{ - if (size() == capacity()) - return; - // Allocate new space. - pointer elements = std::allocator_traits::allocate(m_allocator, size()); - // Copy old element to new place. - pointer temp_p{elements}; - for (const_iterator i{begin()}; i != end(); ++i, ++temp_p) - std::allocator_traits::construct(m_allocator, temp_p, *i); - // Clean up old allocated space. - for (iterator i{begin()}; i != end(); ++i) - std::allocator_traits::destroy(m_allocator, i); - std::allocator_traits::deallocate(m_allocator, m_elements, capacity()); - - m_capacity = size(); - m_elements = elements; -} - -template -void dsaa::Vector::push_back(const_reference p_value) -{ - if (size() == capacity()) - reserve(size() == 0 ? 8 : 2 * size()); // Make sure we have enough space. - - std::allocator_traits::construct(m_allocator, end(), p_value); - ++m_size; -} - -template -void dsaa::Vector::push_back(value_type &&p_value) -{ - if (size() == capacity()) - reserve(size() == 0 ? 8 : 2 * size()); // Make sure we have enough space. - *end() = p_value; - p_value = value_type(); - ++m_size; -} - -template -void dsaa::Vector::pop_back() -{ - std::allocator_traits::destroy(m_allocator, end()); - --m_size; -} - -template -typename dsaa::Vector::iterator dsaa::Vector::insert(const_iterator p_position, const_reference p_value) -{ - size_t index{p_position - begin()}; - if (size() == capacity()) - reserve(size() == 0 ? 8 : 2 * size()); // Make sure we have enough space. - - // First copy last element into uninitialized space. - std::allocator_traits::construct(m_allocator, end(), back()); - ++m_size; - - iterator pp = begin() + index; // The place to put value. - for (iterator pos{end() - 1}; pos != pp; --pos) - *pos = *(pos - 1); // Copy element one position to the right. - - *pp = p_value; // Insert value; - - return pp; -} - -template -typename dsaa::Vector::iterator dsaa::Vector::erase(const_iterator p_position) -{ - if (p_position == end()) - return p_position; - - for (auto pos{p_position + 1}; pos != end(); ++pos) - { - *(pos - 1) = *pos; // Copy element "one position to the left". - } - - pop_back(); - - return p_position; -} - -template -void dsaa::Vector::clear() noexcept -{ - // Clean up all elements. - for (iterator i{begin()}; i != end(); ++i) - std::allocator_traits::destroy(m_allocator, i); - - m_size = 0; -} - -// Assigns new contents to the vector, replacing its current contents, and modifying its size accordingly. -template -template -void dsaa::Vector::assign(BIterator p_first, BIterator p_last) -{ - if (capacity() < (p_last - p_first)) - reserve(p_last - p_first); - - // Clean up old allocated space. - for (iterator i{begin()}; i != end(); ++i) - std::allocator_traits::destroy(m_allocator, i); - - pointer temp_p{m_elements}; - for (BIterator i{p_first}; i != p_last; ++i) - std::allocator_traits::construct(m_allocator, temp_p, *i); - m_size = p_last - p_first; -} - -template -void dsaa::Vector::assign(size_type p_size, const value_type &p_value) -{ - // Allocate new space. - pointer elements = std::allocator_traits::allocate(m_allocator, p_size); - for (size_type i = 0; i < p_size; ++i) - std::allocator_traits::construct(m_allocator, &elements[i], p_value); - - // Clean up old allocated space. - for (iterator i{begin()}; i != end(); ++i) - std::allocator_traits::destroy(m_allocator, i); - std::allocator_traits::deallocate(m_allocator, m_elements, capacity()); - - m_capacity = m_size = p_size; - m_elements = elements; -} - -template -void dsaa::Vector::assign(std::initializer_list p_list) -{ - m_allocator = allocator_type(); - m_capacity = m_size = p_list.size(); - - m_elements = std::allocator_traits::allocate(m_allocator, capacity()); - pointer temp_p = m_elements; - for (auto i{p_list.begin()}; i != p_list.end(); ++i, ++temp_p) - *temp_p = *i; -} -#endif \ No newline at end of file diff --git a/test/Test.cpp b/test/Test.cpp index 716eaba..d12b8f7 100644 --- a/test/Test.cpp +++ b/test/Test.cpp @@ -1,5 +1,9 @@ -#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file -#include "Catch2/Catch.hpp" +#include "test/Test.h" -// warning: Do not write your tests in header files!/ -// It causes compile time increase greatly, because the way Catch2 single header file work. \ No newline at end of file +unsigned int dsaa::random_range(unsigned int start, unsigned int end) +{ + std::random_device device; + std::mt19937 engine(device()); + std::uniform_int_distribution dist6(start, end); // distribution in range [1, 6] + return dist6(engine); +} diff --git a/test/Test.h b/test/Test.h index 310104b..4edb472 100644 --- a/test/Test.h +++ b/test/Test.h @@ -1,110 +1,20 @@ -#ifndef TEST_H -#define TEST_H +#ifndef DSAA_TEST_H +#define DSAA_TEST_H #include #include #include -// An "ordinary sequence": {1, 2, 3, 5, 8, 13, 21} -// The empty sequence: { } -// Just one element: { 1 } -// Even number of elements: {1, 2, 3, 4} -// Odd number of elements: {1, 2, 3, 4, 5} -// All elements equal: {1, 1, 1, 1, 1, 1, 1} -// Difference element at begining: {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} -// Difference element at end: {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1} - -// Some test sequences are best generated by a program: -// A very large sequence. -// Some sequences with a random number of elements. -// Some sequences with random elements (but still ordered). - -struct verify; -class tester -{ - friend verify; - const tester *self; - double m_value; - -public: - static int livecount; - tester() : self(this), m_value(0) { ++livecount; } - tester(double p_value) : self(this), m_value(p_value) { ++livecount; } - tester(const tester &p_other) noexcept : self(this), m_value(p_other.m_value) { ++livecount; } - ~tester() - { - assert(self == this); - --livecount; - } - tester &operator=(const tester &p_other) - { - assert(self == this && p_other.self == &p_other); - m_value = p_other.m_value; - return *this; - } - double &value() { return m_value; } - double const &value() const { return m_value; } - void cfunction() const { assert(self == this); } - void mfunction() { assert(self == this); } -}; - -int tester::livecount = 0; -struct verify -{ - ~verify() { assert(tester::livecount == 0); } -} verifier; - -std::ostream &operator<<(std::ostream &os, tester const &test) -{ - os << test.value(); - return os; -} - -bool operator==(const tester &p_first, const tester &p_last) -{ - return p_first.value() == p_last.value(); -} - -bool operator!=(const tester &p_first, const tester &p_last) +namespace dsaa { - return !(p_first == p_last); -} + unsigned int random_range(unsigned int start = 0, unsigned int end = 678); -bool operator<(const tester &p_first, const tester &p_last) -{ - return (p_first.value() < p_last.value()); -} - -bool operator<=(const tester &p_first, const tester &p_last) -{ - return (p_first.value() <= p_last.value()); -} - -bool operator>(const tester &p_first, const tester &p_last) -{ - return (p_first.value() > p_last.value()); -} - -bool operator>=(const tester &p_first, const tester &p_last) -{ - return (p_first.value() >= p_last.value()); -} - -tester operator-(const tester &p_first, const tester &p_last) -{ - return tester(p_first.value() - p_last.value()); -} - -unsigned int random_range(unsigned int start = 0, unsigned int end = 678) -{ - std::random_device device; - std::mt19937 engine(device()); - std::uniform_int_distribution dist6(start, end); // distribution in range [1, 6] - return dist6(engine); + template + void print_elem(Iterator p_first, Iterator p_last); } template -void print_elem(Iterator p_first, Iterator p_last) +void dsaa::print_elem(Iterator p_first, Iterator p_last) { std::cout << "{ "; while (p_first != p_last) @@ -115,4 +25,4 @@ void print_elem(Iterator p_first, Iterator p_last) std::cout << " }" << std::endl; } -#endif // !TEST_H +#endif // !DSAA_TEST_H diff --git a/test/Tester.h b/test/Tester.h new file mode 100644 index 0000000..8f74e56 --- /dev/null +++ b/test/Tester.h @@ -0,0 +1,87 @@ +#ifndef DSAA_TESTER_H +#define DSAA_TESTER_H +#include +#include + +struct verify; +class tester +{ + friend verify; + const tester *self; + double m_value; + +public: + static int livecount; + tester() : self(this), m_value(0.0) { ++livecount; } + tester(double p_value) : self(this), m_value(p_value) { ++livecount; } + tester(const tester &p_other) noexcept : self(this), m_value(p_other.m_value) { ++livecount; } + tester(tester &&p_other) noexcept : self(this), m_value(p_other.m_value) + { + ++livecount; + p_other.m_value = 0.0; + } + ~tester() + { + assert(self == this); + --livecount; + } + tester &operator=(const tester &p_other) + { + assert(self == this && p_other.self == &p_other); + + m_value = p_other.m_value; + return *this; + } + + tester &operator=(tester &&p_other) + { + assert(self == this && p_other.self == &p_other); + + m_value = p_other.m_value; + + p_other.m_value = 0.0; + return *this; + } + double &value() { return m_value; } + double const &value() const { return m_value; } + void cfunction() const { assert(self == this); } + void mfunction() { assert(self == this); } +}; + +int tester::livecount = 0; +struct verify +{ + ~verify() + { + std::cout << "livecount: " << tester::livecount << std::endl; + assert(tester::livecount == 0); + } +} verifier; + +std::ostream &operator<<(std::ostream &os, tester const &test) +{ + os << test.value(); + return os; +} + +bool operator==(const tester &p_first, const tester &p_last) +{ + return p_first.value() == p_last.value(); +} + +bool operator!=(const tester &p_first, const tester &p_last) +{ + return !(p_first == p_last); +} + +bool operator<=(const tester &p_first, const tester &p_last) +{ + return (p_first.value() <= p_last.value()); +} + +bool operator>=(const tester &p_first, const tester &p_last) +{ + return (p_first.value() >= p_last.value()); +} + +#endif //DSAA_TESTER_H \ No newline at end of file diff --git a/test/algorithms/TestSearch.cpp b/test/algorithms/TestSearch.cpp index 49a16a8..9f071f3 100644 --- a/test/algorithms/TestSearch.cpp +++ b/test/algorithms/TestSearch.cpp @@ -60,7 +60,7 @@ TEST_CASE("test binary search", "[search]") { dsaa::Array arr(222); for (size_t i(0); i < arr.size(); ++i) - arr[i] = random_range(); + arr[i] = dsaa::random_range(); std::sort(arr.begin(), arr.end()); REQUIRE((*dsaa::binary_search(arr.begin(), arr.end(), 75) == 75 || dsaa::binary_search(arr.begin(), arr.end(), 75) == arr.end())); } @@ -119,14 +119,14 @@ TEST_CASE("test linear search", "[search]") { dsaa::Array arr(222); for (size_t i(0); i < arr.size(); ++i) - arr[i] = random_range(); + arr[i] = dsaa::random_range(); REQUIRE((*dsaa::linear_search(arr.begin(), arr.end(), 75) == 75 || dsaa::linear_search(arr.begin(), arr.end(), 75) == arr.end())); } SECTION("Some sequences with random elements (but still ordered)..") { dsaa::Array arr(222); for (size_t i(0); i < arr.size(); ++i) - arr[i] = random_range(); + arr[i] = dsaa::random_range(); std::sort(arr.begin(), arr.end()); REQUIRE((*dsaa::linear_search(arr.begin(), arr.end(), 75) == 75 || dsaa::linear_search(arr.begin(), arr.end(), 75) == arr.end())); diff --git a/test/data_structures/arrays/TestArray.cpp b/test/data_structures/arrays/TestArray.cpp new file mode 100644 index 0000000..1a50c95 --- /dev/null +++ b/test/data_structures/arrays/TestArray.cpp @@ -0,0 +1,874 @@ +#ifndef DSAA_TEST_ARRAY_H +#define DSAA_TEST_ARRAY_H + +#include "Catch2/Catch.hpp" +#include "arrays/Array.h" +#include "test/Tester.h" +#include "test/Test.h" +#include "algorithms/Search.h" +#include +#include +using iterator = dsaa::Array::iterator; +TEST_CASE("Test Array constructor", "[array]") +{ + SECTION("Test Array with default constructor") + { + dsaa::Array arr; + + REQUIRE(iterator() == arr.begin()); + REQUIRE(iterator() == arr.cbegin()); + REQUIRE(iterator() == arr.end()); + REQUIRE(iterator() == arr.cend()); + + REQUIRE(arr.get_allocator() == std::allocator()); + REQUIRE(iterator().content() == arr.data()); + REQUIRE(arr.empty()); + REQUIRE(0 == arr.capacity()); + REQUIRE(0 == arr.size()); + } + + SECTION("Test Array with default constructor and allocator.") + { + dsaa::Array> arr; + + REQUIRE(iterator() == arr.begin()); + REQUIRE(iterator() == arr.cbegin()); + REQUIRE(iterator() == arr.end()); + REQUIRE(iterator() == arr.cend()); + + REQUIRE(arr.get_allocator() == std::allocator()); + REQUIRE(iterator().content() == arr.data()); + REQUIRE(arr.empty()); + REQUIRE(0 == arr.capacity()); + REQUIRE(0 == arr.size()); + } + + SECTION("Test constructor with given size.") + { + size_t arr_size{100}; + dsaa::Array arr(arr_size); + + REQUIRE(iterator() != arr.begin()); + REQUIRE(iterator() != arr.cbegin()); + REQUIRE(iterator() != arr.end()); + REQUIRE(iterator() != arr.cend()); + + REQUIRE(arr.get_allocator() == std::allocator()); + REQUIRE(iterator().content() != arr.data()); + REQUIRE(!arr.empty()); + REQUIRE(arr.capacity() == arr_size); + REQUIRE(arr.size() == arr_size); + for (size_t i{0}; i < arr_size; ++i) + REQUIRE(0.0 == arr[i]); + } + + SECTION("Test constructor with given size and allocator.") + { + size_t arr_size{100}; + dsaa::Array> arr(arr_size); + + REQUIRE(iterator() != arr.begin()); + REQUIRE(iterator() != arr.cbegin()); + REQUIRE(iterator() != arr.end()); + REQUIRE(iterator() != arr.cend()); + + REQUIRE(arr.get_allocator() == std::allocator()); + REQUIRE(iterator().content() != arr.data()); + REQUIRE(!arr.empty()); + REQUIRE(arr.capacity() == arr_size); + REQUIRE(arr.size() == arr_size); + for (size_t i{0}; i < arr_size; ++i) + REQUIRE(0.0 == arr[i]); + } + + SECTION("Test constructor with given size and value.") + { + size_t arr_size{100}; + dsaa::Array arr(arr_size, 4.4); + + REQUIRE(iterator() != arr.begin()); + REQUIRE(iterator() != arr.cbegin()); + REQUIRE(iterator() != arr.end()); + REQUIRE(iterator() != arr.cend()); + + REQUIRE(arr.get_allocator() == std::allocator()); + REQUIRE(iterator().content() != arr.data()); + REQUIRE(!arr.empty()); + REQUIRE(arr.capacity() == arr_size); + REQUIRE(arr.size() == arr_size); + for (size_t i{0}; i < arr_size; ++i) + REQUIRE(4.4 == arr[i]); + } + + SECTION("Test constructor with given size, value and allocator.") + { + size_t arr_size{100}; + dsaa::Array> arr(arr_size, 4.4); + + REQUIRE(iterator() != arr.begin()); + REQUIRE(iterator() != arr.cbegin()); + REQUIRE(iterator() != arr.end()); + REQUIRE(iterator() != arr.cend()); + + REQUIRE(arr.get_allocator() == std::allocator()); + REQUIRE(iterator().content() != arr.data()); + REQUIRE(!arr.empty()); + REQUIRE(arr.capacity() == arr_size); + REQUIRE(arr.size() == arr_size); + for (size_t i{0}; i < arr_size; ++i) + REQUIRE(4.4 == arr[i]); + } + + SECTION("Test constructor with std::initializer_list.") + { + std::initializer_list list{6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6}; + dsaa::Array arr{list}; + + REQUIRE(iterator() != arr.begin()); + REQUIRE(iterator() != arr.cbegin()); + REQUIRE(iterator() != arr.end()); + REQUIRE(iterator() != arr.cend()); + + REQUIRE(arr.get_allocator() == std::allocator()); + REQUIRE(iterator().content() != arr.data()); + REQUIRE(!arr.empty()); + REQUIRE(arr.capacity() == list.size()); + REQUIRE(arr.size() == list.size()); + auto list_iter{list.begin()}; + auto arr_iter{arr.begin()}; + while (list_iter != list.end()) + REQUIRE(*list_iter++ == *arr_iter++); + } + + SECTION("Test constructor with std::initializer_list and std::allocator.") + { + std::initializer_list list{1.1, + 2.2, + 3.3, + 4.4, + 5.5, + 6.6, + 7.7, + 8.7, + 9.8, + 10.6}; + dsaa::Array> arr{list}; + + REQUIRE(iterator() != arr.begin()); + REQUIRE(iterator() != arr.cbegin()); + REQUIRE(iterator() != arr.end()); + REQUIRE(iterator() != arr.cend()); + + REQUIRE(arr.get_allocator() == std::allocator()); + REQUIRE(iterator().content() != arr.data()); + REQUIRE(!arr.empty()); + REQUIRE(arr.capacity() == list.size()); + REQUIRE(arr.size() == list.size()); + auto list_iter{list.begin()}; + auto arr_iter{arr.begin()}; + while (list_iter != list.end()) + REQUIRE(*list_iter++ == *arr_iter++); + } + + SECTION("Test constructor with given pair IIterator.") + { + std::initializer_list list{1.1, + 2.2, + 3.3, + 4.4, + 5.5, + 6.6, + 7.7, + 8.7, + 9.8, + 10.6}; + dsaa::Array arr(list.begin(), list.end()); + + REQUIRE(iterator() != arr.begin()); + REQUIRE(iterator() != arr.cbegin()); + REQUIRE(iterator() != arr.end()); + REQUIRE(iterator() != arr.cend()); + + REQUIRE(arr.get_allocator() == std::allocator()); + REQUIRE(iterator().content() != arr.data()); + REQUIRE(!arr.empty()); + REQUIRE(arr.capacity() >= list.size()); + REQUIRE(arr.size() == list.size()); + auto list_iter{list.begin()}; + auto arr_iter{arr.begin()}; + while (list_iter != list.end()) + REQUIRE(*list_iter++ == *arr_iter++); + } + + SECTION("Test constructor with given pair IIterator and std::allocator.") + { + std::initializer_list list{1.1, + 2.2, + 3.3, + 4.4, + 5.5, + 6.6, + 7.7, + 8.7, + 9.8, + 10.6}; + dsaa::Array> arr(list.begin(), list.end()); + + REQUIRE(iterator() != arr.begin()); + REQUIRE(iterator() != arr.cbegin()); + REQUIRE(iterator() != arr.end()); + REQUIRE(iterator() != arr.cend()); + + REQUIRE(arr.get_allocator() == std::allocator()); + REQUIRE(iterator().content() != arr.data()); + REQUIRE(!arr.empty()); + REQUIRE(arr.capacity() >= list.size()); + REQUIRE(arr.size() == list.size()); + auto list_iter{list.begin()}; + auto arr_iter{arr.begin()}; + while (list_iter != list.end()) + REQUIRE(*list_iter++ == *arr_iter++); + } + + SECTION("Test copy constructor.") + { + std::initializer_list list{6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6}; + dsaa::Array arr(list.begin(), list.end()); + dsaa::Array arr2(arr); + + REQUIRE(iterator() != arr2.begin()); + REQUIRE(iterator() != arr2.cbegin()); + REQUIRE(iterator() != arr2.end()); + REQUIRE(iterator() != arr2.cend()); + + REQUIRE(arr2.get_allocator() == arr.get_allocator()); + REQUIRE(iterator().content() != arr2.data()); + REQUIRE(!arr2.empty()); + REQUIRE(arr2.capacity() == arr.size()); + REQUIRE(arr2.size() == arr.size()); + auto arr_iter{arr.begin()}; + auto arr2_iter{arr2.begin()}; + while (arr_iter != arr.end()) + REQUIRE(*arr_iter++ == *arr2_iter++); + } + + SECTION("Test copy constructor and std::allocator.") + { + std::initializer_list list{6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6}; + dsaa::Array arr(list.begin(), list.end()); + dsaa::Array> arr2(arr); + + REQUIRE(iterator() != arr2.begin()); + REQUIRE(iterator() != arr2.cbegin()); + REQUIRE(iterator() != arr2.end()); + REQUIRE(iterator() != arr2.cend()); + + REQUIRE(arr2.get_allocator() == std::allocator()); + REQUIRE(iterator().content() != arr2.data()); + REQUIRE(!arr2.empty()); + REQUIRE(arr2.capacity() == arr.size()); + REQUIRE(arr2.size() == arr.size()); + auto arr_iter{arr.begin()}; + auto arr2_iter{arr2.begin()}; + while (arr_iter != arr.end()) + REQUIRE(*arr_iter++ == *arr2_iter++); + } + + SECTION("Test move constructor.") + { + std::initializer_list list{6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6}; + dsaa::Array arr(list); + size_t capacity(arr.capacity()), size(arr.size()); + dsaa::Array arr2(std::move(arr)); + + REQUIRE(iterator() == arr.begin()); + REQUIRE(iterator() == arr.cbegin()); + REQUIRE(iterator() == arr.end()); + REQUIRE(iterator() == arr.cend()); + + REQUIRE(arr.get_allocator() == std::allocator()); + REQUIRE(iterator().content() == arr.data()); + REQUIRE(arr.empty()); + REQUIRE(0 == arr.capacity()); + REQUIRE(0 == arr.size()); + + REQUIRE(iterator() != arr2.begin()); + REQUIRE(iterator() != arr2.cbegin()); + REQUIRE(iterator() != arr2.end()); + REQUIRE(iterator() != arr2.cend()); + + REQUIRE(arr2.get_allocator() == std::allocator()); + REQUIRE(iterator().content() != arr2.data()); + REQUIRE(!arr2.empty()); + REQUIRE(arr2.capacity() == capacity); + REQUIRE(arr2.size() == size); + + auto list_iter{list.begin()}; + auto arr2_iter{arr2.begin()}; + while (list_iter != list.end()) + REQUIRE(*list_iter++ == *arr2_iter++); + } + + SECTION("Test move constructor with allocator.") + { + std::initializer_list list{6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6}; + dsaa::Array arr(list); + size_t capacity(arr.capacity()), size(arr.size()); + dsaa::Array arr2(std::move(arr), std::allocator()); + + REQUIRE(iterator() == arr.begin()); + REQUIRE(iterator() == arr.cbegin()); + REQUIRE(iterator() == arr.end()); + REQUIRE(iterator() == arr.cend()); + + REQUIRE(arr.get_allocator() == std::allocator()); + REQUIRE(iterator().content() == arr.data()); + REQUIRE(arr.empty()); + REQUIRE(0 == arr.capacity()); + REQUIRE(0 == arr.size()); + + REQUIRE(iterator() != arr2.begin()); + REQUIRE(iterator() != arr2.cbegin()); + REQUIRE(iterator() != arr2.end()); + REQUIRE(iterator() != arr2.cend()); + + REQUIRE(arr2.get_allocator() == std::allocator()); + REQUIRE(iterator().content() != arr2.data()); + REQUIRE(!arr2.empty()); + REQUIRE(arr2.capacity() == capacity); + REQUIRE(arr2.size() == size); + + auto list_iter{list.begin()}; + auto arr2_iter{arr2.begin()}; + while (list_iter != list.end()) + REQUIRE(*list_iter++ == *arr2_iter++); + } + + SECTION("Test copy assignment.") + { + std::initializer_list list{6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6}; + dsaa::Array arr(list); + dsaa::Array arr2; + arr2 = arr; + + REQUIRE(iterator() != arr2.begin()); + REQUIRE(iterator() != arr2.cbegin()); + REQUIRE(iterator() != arr2.end()); + REQUIRE(iterator() != arr2.cend()); + + REQUIRE(arr2.get_allocator() == arr.get_allocator()); + REQUIRE(iterator().content() != arr2.data()); + REQUIRE(!arr2.empty()); + REQUIRE(arr2.capacity() == arr.size()); + REQUIRE(arr2.size() == arr.size()); + auto arr_iter{arr.begin()}; + auto arr2_iter{arr2.begin()}; + while (arr_iter != arr.end()) + REQUIRE(*arr_iter++ == *arr2_iter++); + } + + SECTION("Test move assigment.") + { + std::initializer_list list{6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6}; + dsaa::Array arr(list); + size_t capacity(arr.capacity()), size(arr.size()); + dsaa::Array arr2; + + arr2 = std::move(arr); + + REQUIRE(iterator() == arr.begin()); + REQUIRE(iterator() == arr.cbegin()); + REQUIRE(iterator() == arr.end()); + REQUIRE(iterator() == arr.cend()); + + REQUIRE(arr.get_allocator() == std::allocator()); + REQUIRE(iterator().content() == arr.data()); + REQUIRE(arr.empty()); + REQUIRE(0 == arr.capacity()); + REQUIRE(0 == arr.size()); + + REQUIRE(iterator() != arr2.begin()); + REQUIRE(iterator() != arr2.cbegin()); + REQUIRE(iterator() != arr2.end()); + REQUIRE(iterator() != arr2.cend()); + + REQUIRE(arr2.get_allocator() == std::allocator()); + REQUIRE(iterator().content() != arr2.data()); + REQUIRE(!arr2.empty()); + REQUIRE(arr2.capacity() == capacity); + REQUIRE(arr2.size() == size); + + auto list_iter{list.begin()}; + auto arr2_iter{arr2.begin()}; + while (list_iter != list.end()) + REQUIRE(*list_iter++ == *arr2_iter++); + } + + SECTION("Test copy assignment using std::initilizer_list.") + { + std::initializer_list list{6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6}; + dsaa::Array arr; + arr = list; + + REQUIRE(iterator() != arr.begin()); + REQUIRE(iterator() != arr.cbegin()); + REQUIRE(iterator() != arr.end()); + REQUIRE(iterator() != arr.cend()); + + REQUIRE(arr.get_allocator() == std::allocator()); + REQUIRE(iterator().content() != arr.data()); + REQUIRE(!arr.empty()); + REQUIRE(arr.capacity() == list.size()); + REQUIRE(arr.size() == list.size()); + + auto list_iter{list.begin()}; + auto arr_iter{arr.begin()}; + while (list_iter != list.end()) + REQUIRE(*list_iter++ == *arr_iter++); + } +} + +TEST_CASE("Test Array assign methods", "[array]") +{ + dsaa::Array arr; + SECTION("Test assign method using pair IIterator") + { + std::initializer_list list{6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6, + 6.6}; + arr.assign(list.begin(), list.end()); + + REQUIRE(iterator() != arr.begin()); + REQUIRE(iterator() != arr.cbegin()); + REQUIRE(iterator() != arr.end()); + REQUIRE(iterator() != arr.cend()); + + REQUIRE(arr.get_allocator() == std::allocator()); + REQUIRE(iterator().content() != arr.data()); + REQUIRE(!arr.empty()); + REQUIRE(arr.capacity() >= list.size()); + REQUIRE(arr.size() == list.size()); + + auto list_iter{list.begin()}; + auto arr_iter{arr.begin()}; + while (list_iter != list.end()) + REQUIRE(*list_iter++ == *arr_iter++); + } + + SECTION("Test assign method with size and value") + { + size_t size{100}; + double value{7.3}; + arr.assign(size, value); + + REQUIRE(iterator() != arr.begin()); + REQUIRE(iterator() != arr.cbegin()); + REQUIRE(iterator() != arr.end()); + REQUIRE(iterator() != arr.cend()); + + REQUIRE(arr.get_allocator() == std::allocator()); + REQUIRE(iterator().content() != arr.data()); + REQUIRE(!arr.empty()); + REQUIRE(arr.capacity() == size); + REQUIRE(arr.size() == size); + + auto arr_iter{arr.begin()}; + while (arr_iter != arr.end()) + REQUIRE(*arr_iter++ == value); + } + + SECTION("Test assign method using std::initializer_list") + { + std::initializer_list list{2.4, + 2.4, + 2.4, + 2.4, + 2.4, + 2.4, + 2.4, + 2.4, + 2.4, + 2.4}; + arr.assign(list); + + REQUIRE(iterator() != arr.begin()); + REQUIRE(iterator() != arr.cbegin()); + REQUIRE(iterator() != arr.end()); + REQUIRE(iterator() != arr.cend()); + + REQUIRE(arr.get_allocator() == std::allocator()); + REQUIRE(iterator().content() != arr.data()); + REQUIRE(!arr.empty()); + REQUIRE(arr.capacity() == list.size()); + REQUIRE(arr.size() == list.size()); + + auto list_iter{list.begin()}; + auto arr_iter{arr.begin()}; + while (list_iter != list.end()) + REQUIRE(*list_iter++ == *arr_iter++); + } +} + +TEST_CASE("Test Array reserve.", "[array]") +{ + dsaa::Array arr; + + SECTION("Array reserve doesn't change capacity") + { + size_t new_capacity{0}; + size_t old_capacity{arr.capacity()}; + size_t old_size{arr.size()}; + arr.reserve(new_capacity); + REQUIRE(arr.capacity() == new_capacity); + REQUIRE(arr.capacity() == old_capacity); + REQUIRE(arr.size() == old_size); + } + + SECTION("Array reserve change capacity") + { + size_t new_capacity{75}; + size_t old_size{arr.size()}; + arr.reserve(new_capacity); + REQUIRE(arr.capacity() == new_capacity); + REQUIRE(arr.size() == old_size); + } +} + +TEST_CASE("Test Array resizing.", "[array]") +{ + dsaa::Array arr; + + SECTION("resize to 0") + { + size_t new_size{0}; + size_t old_capacity{arr.capacity()}; + arr.resize(new_size); + REQUIRE(arr.capacity() == old_capacity); + REQUIRE(arr.size() == new_size); + } + + SECTION("Array resize change capacity and size") + { + size_t new_size{21}; + arr.resize(new_size); + REQUIRE(arr.capacity() == new_size); + REQUIRE(arr.size() == new_size); + } + + SECTION("Array resize change capacity and size") + { + size_t new_size{111}; + arr.resize(new_size); + REQUIRE(arr.capacity() == new_size); + REQUIRE(arr.size() == new_size); + } + + SECTION("Array resize change size but not capacity") + { + size_t new_capacity{100}; + arr.reserve(new_capacity); + + SECTION("Resize to smaller size.") + { + size_t new_size{34}; + size_t old_capacity{arr.capacity()}; + arr.resize(new_size); + REQUIRE(arr.capacity() == old_capacity); + REQUIRE(arr.size() == new_size); + } + + SECTION("Resize to larger size but not larger capacity") + { + size_t new_size{85}; + size_t old_capacity{arr.capacity()}; + arr.resize(new_size); + REQUIRE(arr.capacity() == old_capacity); + REQUIRE(arr.size() == new_size); + } + } +} + +TEST_CASE("Array insert last methods", "[array]") +{ + dsaa::Array arr; + SECTION("Insert last with parameter value") + { + arr.insert_last(92.2); + arr.insert_last(92.2); + arr.insert_last(92.2); + REQUIRE(arr.capacity() >= 3); + REQUIRE(arr.size() == 3); + } + + SECTION("Insert last by move value") + { + tester value1{92.1}, value2{23.1}, value3{73.1}; + arr.insert_last(std::move(value1)); + arr.insert_last(std::move(value2)); + arr.insert_last(std::move(value3)); + REQUIRE(arr.capacity() >= 3); + REQUIRE(arr.size() == 3); + + REQUIRE(value1 == tester(0.0)); + REQUIRE(value2 == tester(0.0)); + REQUIRE(value3 == tester(0.0)); + } + + SECTION("Insert last by a mount of size and value") + { + size_t size(99); + double value(21.1); + arr.insert_last(size, value); + REQUIRE(arr.capacity() >= size); + REQUIRE(arr.size() == size); + } + + SECTION("Insert last by a pair of IIterator") + { + std::initializer_list list{2.4, + 2.4, + 2.4, + 2.4, + 2.4, + 2.4, + 2.4, + 2.4, + 2.4, + 2.4}; + + arr.insert_last(list.begin(), list.end()); + REQUIRE(arr.capacity() >= list.size()); + REQUIRE(arr.size() == list.size()); + } +} + +TEST_CASE("Array insert at methods", "[array]") +{ + dsaa::Array arr(10); + SECTION("Insert at with parameter value") + { + size_t old_size{arr.size()}; + + arr.insert_at(arr.begin(), 93.8); + arr.insert_at(arr.begin(), 93.8); + arr.insert_at(arr.begin(), 93.8); + REQUIRE(arr.capacity() >= 13); + REQUIRE(arr.size() == 13); + + REQUIRE(arr.capacity() >= old_size + 3); + REQUIRE(arr.size() == old_size + 3); + } + + SECTION("Insert at by move value") + { + tester value1{92.1}, value2{23.1}, value3{73.1}; + size_t old_size{arr.size()}; + arr.insert_at(arr.begin(), std::move(value1)); + arr.insert_at(arr.begin(), std::move(value2)); + arr.insert_at(arr.begin(), std::move(value3)); + REQUIRE(arr.capacity() >= 13); + REQUIRE(arr.size() == 13); + + REQUIRE(value1 == tester(0.0)); + REQUIRE(value2 == tester(0.0)); + REQUIRE(value3 == tester(0.0)); + + REQUIRE(arr.capacity() >= old_size + 3); + REQUIRE(arr.size() == old_size + 3); + } + + SECTION("Insert at by a mount of size and value") + { + size_t size(100); + size_t old_size{arr.size()}; + tester value(21.1); + arr.insert_at(arr.begin(), size, value); + REQUIRE(arr.capacity() >= old_size + size); + REQUIRE(arr.size() == old_size + size); + + for (size_t i(0); i < size; ++i) + REQUIRE(arr[i] == value); + } + + SECTION("Insert at by a std::initializer_list") + { + size_t old_size{arr.size()}; + std::initializer_list list{2.4, + 2.4, + 2.4, + 2.4, + 2.4, + 2.4, + 2.4, + 2.4, + 2.4, + 2.4}; + + arr.insert_at(arr.begin(), list); + REQUIRE(arr.capacity() >= old_size + list.size()); + REQUIRE(arr.size() == old_size + list.size()); + size_t index{0}; + for (auto i(list.begin()); i != list.end(); ++i, ++index) + REQUIRE(arr[index] == *i); + } + + SECTION("Insert at by a pair of IIterator") + { + size_t old_size{arr.size()}; + std::initializer_list list{2.4, + 2.4, + 2.4, + 2.4, + 2.4, + 2.4, + 2.4, + 2.4, + 2.4, + 2.4}; + + arr.insert_at(arr.begin(), list.begin(), list.end()); + REQUIRE(arr.capacity() >= old_size + list.size()); + REQUIRE(arr.size() == old_size + list.size()); + size_t index{0}; + for (auto i(list.begin()); i != list.end(); ++i, ++index) + REQUIRE(arr[index] == *i); + } +} + +TEST_CASE("Array erase at method", "[array]") +{ + dsaa::Array arr(100); + + for (size_t i(0); i != arr.size(); ++i) + { + arr[i] = i; + } + + size_t index(75); + tester value(*arr.get_iterator(index)); + arr.erase_at(arr.get_iterator(index)); + + auto result = dsaa::linear_search(arr.begin(), arr.end(), value); + REQUIRE(result == arr.end()); +} + +TEST_CASE("Array erase with a pair iterator", "[array]") +{ + dsaa::Array arr(100); + + for (size_t i(0); i != arr.size(); ++i) + { + arr[i] = i; + } + + arr.erase(arr.begin(), arr.end()); + REQUIRE(arr.size() == 0); +} +TEST_CASE("Array erase last", "[array]") +{ + dsaa::Array arr(100); + + for (size_t i(0); i != arr.size(); ++i) + { + arr[i] = i; + } + + auto value(arr.last()); + arr.erase_last(); + REQUIRE(arr.last() != value); +} + +TEST_CASE("Array clear function", "[array]") +{ + dsaa::Array arr(100); + + for (size_t i(0); i != arr.size(); ++i) + { + arr[i] = i; + } + + auto value(arr.last()); + arr.clear(); + REQUIRE(arr.size() == 0); +} + +#endif // !DSAA_TEST_ARRAY_H \ No newline at end of file diff --git a/test/main.cpp b/test/main.cpp new file mode 100644 index 0000000..dba6d8b --- /dev/null +++ b/test/main.cpp @@ -0,0 +1,18 @@ +#define CATCH_CONFIG_RUNNER +#include "Catch2/Catch.hpp" + +int main(int argc, char *argv[]) +{ + int result(0); + // global setup... + { + result = Catch::Session().run(argc, argv); + } + + // global clean-up... + + return result; +} + +// warning: Do not write your tests in header files!/ +// It causes compile time increase greatly, because Catch2 put everything in single header file. \ No newline at end of file