So here is an implementation of a dynarray
. Many people might not know about it, so here is a reference.
Note that I am not trying to write a 100% standard conforming implementation. Also, this is for a library, so resist the urge to scold me on using a leading underscore for two of my variables.
#include <cstddef>
#include <iterator>
#include <stdexcept>
#include <initializer_list>
template<typename T>
class dynarray
{
public: //TYPE ALIASES
using value_type = T;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using reference = T&;
using const_reference = const T&;
using pointer = T*;
using const_pointer = const T*;
private: //ITERATOR
template<typename U>
class dynarray_iter : public std::iterator<std::random_access_iterator_tag, U>
{
private:
U* pos = nullptr;
public:
constexpr explicit dynarray_iter(U* position)
: pos(position)
{}
constexpr dynarray_iter() = default;
constexpr dynarray_iter(const dynarray_iter&) = default;
dynarray_iter& operator=(const dynarray_iter&) = default;
//INCREMENT/DECREMENT OPERATORS
dynarray_iter& operator++() { ++pos; return *this; }
dynarray_iter& operator--() { --pos; return *this; }
dynarray_iter operator++(int) { dynarray_iter temp(*this); operator++(); return temp; }
dynarray_iter operator--(int) { dynarray_iter temp(*this); operator--(); return temp; }
//ARITHMETIC OPERATORS
dynarray_iter operator+(difference_type off) const { return dynarray_iter(pos + off); }
dynarray_iter operator-(difference_type off) const { return dynarray_iter(pos - off); }
dynarray_iter& operator+=(difference_type off) { pos += off; return *this; }
dynarray_iter& operator-=(difference_type off) { pos -= off; return *this; }
difference_type operator-(const dynarray_iter& rhs) const { return pos - rhs.pos; }
friend dynarray_iter operator+(difference_type off, const dynarray_iter& it) { return dynarray_iter(it + off); }
U& operator*() { return *pos; }
U* operator->() { return pos; }
U& operator[](difference_type n) const { return pos[n]; }
operator dynarray_iter<const T>() { return dynarray_iter<const T>(pos); }
//COMPARISON OPERATORS
constexpr bool operator==(const dynarray_iter& rhs) const noexcept { return pos == rhs.pos; }
constexpr bool operator!=(const dynarray_iter& rhs) const noexcept { return pos != rhs.pos; }
constexpr bool operator>(const dynarray_iter& rhs) const noexcept { return pos > rhs.pos; }
constexpr bool operator<(const dynarray_iter& rhs) const noexcept { return pos < rhs.pos; }
constexpr bool operator>=(const dynarray_iter& rhs) const noexcept { return pos >= rhs.pos; }
constexpr bool operator<=(const dynarray_iter& rhs) const noexcept { return pos <= rhs.pos; }
};
public:
using iterator = dynarray_iter<T>;
using const_iterator = dynarray_iter<const T>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
private:
T* _data = nullptr;
std::size_t _size = 0;
public:
//CONSTRUCTORS
template<typename InputIt>
dynarray(InputIt first, InputIt last)
{
_data = new T[std::distance(first, last)];
std::size_t i = 0;
for (; first != last; ++first, ++i) {
_data[i] = *first;
}
_size = ++i;
}
dynarray(std::size_t count, const T& fill_val = 0)
{
_data = new T[count];
for (std::size_t i = 0; i < count; ++i) {
_data[i] = fill_val;
}
_size = count;
}
dynarray(std::initializer_list<T> ilist)
: dynarray(ilist.begin(), ilist.end())
{}
//COPY/MOVE CONSTRUCTORS AND ASSIGNMENT
dynarray(const dynarray& rhs)
{
_data = new T[rhs.size()];
for (std::size_t i = 0; i < _size; ++i) {
_data[i] = rhs._data[i];
}
_size = rhs.size();
}
dynarray(dynarray&& rhs) noexcept
{
swap(rhs);
}
dynarray& operator=(const dynarray& rhs)
{
dynarray temp(rhs.begin(), rhs.end());
swap(temp);
return *this;
}
dynarray& operator=(dynarray&& rhs) noexcept
{
//clear()
swap(rhs);
return *this;
}
~dynarray()
{
delete[] _data;
}
//ACCESS FUNCTIONS
T& front() { return _data[0]; }
T& back() { return _data[_size - 1]; }
const T& front() const { return _data[0]; }
const T& back() const { return _data[_size - 1]; }
T& operator[](std::size_t i) noexcept { return _data[i]; }
const T& operator[](std::size_t i) const noexcept { return _data[i]; }
T& at(std::size_t i)
{
if (!(i < _size)) {
throw std::out_of_range("Index out of bounds!");
}
return _data[i];
}
const T& at(std::size_t i) const
{
if (!(i < _size)) {
throw std::out_of_range("Index out of bounds!");
}
return _data[i];
}
T* data() noexcept { return _data; }
const T* data() const noexcept { return _data; }
//CAPACITY FUNCTIONS
std::size_t size() const noexcept { return _size; }
bool empty() const noexcept { return _size; }
//ITERATORS
iterator begin() noexcept { return iterator(_data); }
iterator end() noexcept { return iterator(_data + _size); }
const_iterator begin() const noexcept { return const_iterator(_data); }
const_iterator end() const noexcept { return const_iterator(_data + _size); }
const_iterator cbegin() const noexcept { return const_iterator(_data); }
const_iterator cend() const noexcept { return const_iterator(_data + _size); }
//REVERSE ITERATORS
reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(cend()); }
const_reverse_iterator crend() const noexcept { return const_reverse_iterator(cbegin()); }
//OTHER FUNCTIONS AND ALGORITHMS
void swap(dynarray& rhs) noexcept
{
using std::swap;
swap(_data, rhs._data);
swap(_size, rhs._size);
}
//FILL
void fill(const T& val)
{
for (size_t i = 0; i < _size; ++i) {
_data[i] = val;
}
}
};