#pragma once #include #include #include namespace hpr { // forward declaration template class DynamicArray; // type traits template struct is_sequence> : public std::true_type {}; // aliases template using darray = DynamicArray; // class definition template class DynamicArray : public Sequence { using base = Sequence; public: using difference_type = std::ptrdiff_t; using value_type = T; using size_type = Size; using pointer = T*; using reference = T&; using iterator = Iterator; using const_pointer = T const*; using const_reference = T const&; using const_iterator = Iterator; public: friend constexpr void swap(DynamicArray& main, DynamicArray& other) noexcept { using std::swap; swap(static_cast(main), static_cast(other)); } constexpr DynamicArray() noexcept : base {} {} constexpr explicit DynamicArray(const base& b) noexcept : base {b} {} constexpr explicit DynamicArray(base&& b) noexcept : base {std::forward(b)} {} constexpr DynamicArray(const DynamicArray& arr) noexcept : base {static_cast(arr)} {} //! Move constructor constexpr DynamicArray(DynamicArray&& arr) noexcept : base {std::forward(static_cast(arr))} {} template constexpr DynamicArray(Iter start, Iter end) : base {start, end} {} constexpr DynamicArray(typename base::iterator start, typename base::iterator end) : base {start, end} {} constexpr DynamicArray(typename base::const_iterator start, typename base::const_iterator end) : base {start, end} {} constexpr DynamicArray(typename base::iterator start, typename base::iterator end, size_type capacity) : base {start, end, capacity} {} constexpr DynamicArray(typename base::const_iterator start, typename base::const_iterator end, size_type capacity) : base {start, end, capacity} {} constexpr DynamicArray(std::initializer_list list) : base {list.begin(), list.end()} {} constexpr DynamicArray(size_type size, value_type value) noexcept : base {size, value} {} constexpr DynamicArray& operator=(base other) noexcept { swap(*this, other); return *this; } constexpr DynamicArray& operator=(DynamicArray other) noexcept { swap(*this, other); return *this; } constexpr DynamicArray& operator=(DynamicArray&& arr) noexcept { swap(*this, arr); return *this; } virtual ~DynamicArray() = default; // Member functions [[nodiscard]] virtual constexpr size_type capacity() const noexcept { return base::p_capacity; } [[nodiscard]] virtual constexpr bool is_empty() const { return base::begin() == base::end(); } virtual constexpr iterator storage_end() { return iterator(base::p_start + base::p_capacity); } virtual constexpr const_iterator storage_end() const { return const_iterator(base::p_start + base::p_capacity); } virtual constexpr void resize(size_type newCapacity) { if (newCapacity == base::p_capacity) return; if (std::numeric_limits::max() - base::size() < newCapacity) throw hpr::LengthError("Invalid capacity value passed"); if (newCapacity > base::p_capacity) { DynamicArray tmp {base::begin(), base::end(), newCapacity}; swap(*this, tmp); } else { if (newCapacity >= base::p_size) { DynamicArray tmp {base::begin(), base::end()}; swap(*this, tmp); } else { DynamicArray tmp {base::begin(), base::begin() + newCapacity}; swap(*this, tmp); } } } virtual constexpr void push(const value_type& val) { if (base::end() == storage_end()) resize(base::p_capacity * 2); *base::end() = val; ++base::p_size; } virtual constexpr void push(value_type&& val) { if (base::end() == storage_end()) resize(base::p_capacity * 2); *base::end() = std::move(val); ++base::p_size; } virtual constexpr void push(const DynamicArray& arr) { for (const value_type& el : arr) push(el); } virtual constexpr value_type pop() { if (is_empty()) throw hpr::LengthError("Cannot pop element from empty array"); value_type val = base::back(); std::destroy_at(base::p_start + base::p_size); --base::p_size; return val; } virtual constexpr void insert(size_type position, const value_type& val) { if (base::end() == storage_end()) resize(base::p_capacity * 2); for (size_type n = base::p_size; n > position; --n) *(base::p_start + n) = std::move(*(base::p_start + n - 1)); *(base::p_start + position) = val; ++base::p_size; } virtual constexpr void insert(size_type position, value_type&& val) { if (base::end() == storage_end()) resize(base::p_capacity * 2); for (size_type n = base::p_size; n > position; --n) *(base::p_start + n) = std::move(*(base::p_start + n - 1)); *(base::p_start + position) = std::move(val); ++base::p_size; } virtual constexpr void remove(size_type position) { for (size_type n = position; n < base::p_size - 1; ++n) *(base::p_start + n) = std::move(*(base::p_start + n + 1)); std::destroy_at(base::p_start + base::p_size); --base::p_size; } virtual constexpr void remove(iterator position) { if (position + 1 != base::end()) std::copy(position + 1, base::end(), position); std::destroy_at(base::p_start + base::p_size); --base::p_size; } virtual constexpr void remove(const std::function& condition) { size_type newSize = base::p_size; for (size_type offset = 0; offset < newSize; ++offset) { if (condition(*(base::p_start + offset))) { for (size_type n = offset; n < newSize; ++n) *(base::p_start + n) = std::move(*(base::p_start + n + 1)); --newSize; --offset; } } base::p_size = newSize; } virtual constexpr void clear() { delete[] base::p_start; base::p_size = 0; base::p_capacity = 1; base::p_start = new value_type[base::p_capacity]; } DynamicArray slice(iterator start, iterator end) { return DynamicArray {start, end}; } }; } // end namespace hpr