Add initial vector implementation
This commit is contained in:
parent
3bba697698
commit
c48e03dc26
284
include/mtl/vector.hpp
Normal file
284
include/mtl/vector.hpp
Normal file
@ -0,0 +1,284 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
|
||||
#include <mtl/exception.hpp>
|
||||
|
||||
namespace mtl {
|
||||
|
||||
/**
|
||||
* \brief Resizable statically allocated array
|
||||
*
|
||||
* Implements most functions from std::vector, see std::vector documentation
|
||||
* for function descriptions. Some operations are unimplemented due to the lack
|
||||
* of dynamic memory usage
|
||||
*/
|
||||
template <typename T>
|
||||
class ivector {
|
||||
private:
|
||||
T* m_arr;
|
||||
size_t m_size;
|
||||
const size_t m_capacity;
|
||||
|
||||
public:
|
||||
using value_type = T;
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
using reference = T&;
|
||||
using const_reference = const T&;
|
||||
using pointer = T*;
|
||||
using const_pointer = const T*;
|
||||
using iterator = T*;
|
||||
using const_iterator = const T*;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
ivector(T* arr, size_t capacity) : m_arr(arr), m_capacity(capacity), m_size(0) {}
|
||||
/**
|
||||
* \brief Copy constructor
|
||||
*
|
||||
* \exception mtl::length_error Thrown if the source vector's size is
|
||||
* larger than the new capacity
|
||||
*/
|
||||
ivector(T* arr, size_t capacity, const ivector& other) : m_arr(arr), m_capacity(capacity) {
|
||||
if (&other == this) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (other.m_size > m_capacity) {
|
||||
throw mtl::length_error();
|
||||
}
|
||||
|
||||
T* x = m_arr;
|
||||
T* begin = other.m_arr;
|
||||
T* end = other.m_arr + other.m_size;
|
||||
for (; begin != end; ++x, ++begin) {
|
||||
*x = *begin;
|
||||
}
|
||||
|
||||
m_size = other.m_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Move constructor
|
||||
*
|
||||
* \exception mtl::length_error Thrown if the source vector's size is
|
||||
* larger than the new capacity
|
||||
*/
|
||||
ivector(ivector&& other) {
|
||||
if (&other == this) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (other.m_size > m_capacity) {
|
||||
throw mtl::length_error();
|
||||
}
|
||||
|
||||
// We're not able to simply swap pointers because dynamic memory
|
||||
// is not used. However, we can still swap each individual
|
||||
// element if possible.
|
||||
T* x = m_arr;
|
||||
T* begin = other.m_arr;
|
||||
T* end = other.m_arr + other.m_size;
|
||||
for (; begin != end; ++x, ++begin) {
|
||||
*x = std::move(*begin);
|
||||
}
|
||||
|
||||
m_size = other.m_size;
|
||||
}
|
||||
|
||||
~ivector() {}
|
||||
|
||||
ivector& operator=(ivector rhs) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
void assign(size_t count, const T& value) {
|
||||
throw mtl::system_error();
|
||||
}
|
||||
/**
|
||||
* \brief Assigns values to the vector
|
||||
*
|
||||
* \exception mtl::length_error Thrown if the number of source elements
|
||||
* is larger than the capacity
|
||||
*/
|
||||
template <typename It>
|
||||
void assign(It begin, It end) {
|
||||
m_size = 0;
|
||||
T* x = m_arr;
|
||||
|
||||
for (; begin != end; ++begin, ++x, ++m_size) {
|
||||
if (m_size > m_capacity) {
|
||||
//throw mtl::length_error();
|
||||
}
|
||||
*x = *begin;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Bounds-checked element access
|
||||
*
|
||||
* \exception mtl::out_of_range Thrown if pos > size
|
||||
*/
|
||||
reference at(size_t pos) {
|
||||
if (pos > m_size) {
|
||||
throw mtl::out_of_range();
|
||||
}
|
||||
|
||||
return m_arr[pos];
|
||||
}
|
||||
const_reference at(size_t pos) const {
|
||||
if (pos > m_size) {
|
||||
throw mtl::out_of_range();
|
||||
}
|
||||
|
||||
return m_arr[pos];
|
||||
}
|
||||
|
||||
reference operator[](size_t pos) {
|
||||
return m_arr[pos];
|
||||
}
|
||||
const_reference operator[](size_t pos) const {
|
||||
return m_arr[pos];
|
||||
}
|
||||
|
||||
reference front() {
|
||||
return m_arr[0];
|
||||
}
|
||||
const_reference front() const {
|
||||
return m_arr[0];
|
||||
}
|
||||
|
||||
reference back() {
|
||||
return m_arr[m_size - 1];
|
||||
}
|
||||
const_reference back() const {
|
||||
return m_arr[m_size - 1];
|
||||
}
|
||||
|
||||
pointer data() {
|
||||
return m_arr;
|
||||
}
|
||||
const_pointer data() const {
|
||||
return m_arr;
|
||||
}
|
||||
|
||||
iterator begin() {
|
||||
return m_arr;
|
||||
}
|
||||
const_iterator begin() const {
|
||||
return m_arr;
|
||||
}
|
||||
const_iterator cbegin() const {
|
||||
return m_arr;
|
||||
}
|
||||
|
||||
iterator end() {
|
||||
return m_arr + m_size;
|
||||
}
|
||||
const_iterator end() const {
|
||||
return m_arr + m_size;
|
||||
}
|
||||
const_iterator cend() const {
|
||||
return m_arr + m_size;
|
||||
}
|
||||
|
||||
reverse_iterator rbegin() {
|
||||
return reverse_iterator(end());
|
||||
}
|
||||
const_reverse_iterator rbegin() const {
|
||||
return const_reverse_iterator(cend());
|
||||
}
|
||||
const_reverse_iterator crbegin() const {
|
||||
return const_reverse_iterator(cend());
|
||||
}
|
||||
|
||||
reverse_iterator rend() {
|
||||
return reverse_iterator(begin());
|
||||
}
|
||||
const_reverse_iterator rend() const {
|
||||
return const_reverse_iterator(cbegin());
|
||||
}
|
||||
const_reverse_iterator crend() const {
|
||||
return const_reverse_iterator(cbegin());
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return m_size == 0;
|
||||
}
|
||||
size_t size() const {
|
||||
return m_size;
|
||||
}
|
||||
size_t capacity() const {
|
||||
return m_capacity;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
iterator insert(const_iterator pos, T value) {
|
||||
if (m_size == m_capacity) {
|
||||
throw mtl::length_error();
|
||||
}
|
||||
|
||||
iterator it = end();
|
||||
while (it != pos) {
|
||||
*it = *(it - 1);
|
||||
--it;
|
||||
}
|
||||
|
||||
*it = std::move(value);
|
||||
++m_size;
|
||||
|
||||
return it;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Erase the element at the given iterator
|
||||
*
|
||||
* \param pos iterator of the element to erase
|
||||
* \exception nothrow if `T` is nothrow assignable
|
||||
* \returns iterator of the element after element erased
|
||||
*/
|
||||
iterator erase(const_iterator pos) noexcept(std::is_nothrow_assignable<T, T>::value) {
|
||||
iterator it = const_cast<iterator>(pos);
|
||||
iterator last = end() - 1;
|
||||
|
||||
while (it != last) {
|
||||
*it = *(it + 1);
|
||||
++it;
|
||||
}
|
||||
|
||||
--m_size;
|
||||
|
||||
return const_cast<iterator>(pos);
|
||||
}
|
||||
|
||||
void push_back(T value) {
|
||||
if (m_size == m_capacity) {
|
||||
throw mtl::length_error();
|
||||
}
|
||||
|
||||
m_arr[m_size] = std::move(value);
|
||||
++m_size;
|
||||
}
|
||||
|
||||
void pop_back() noexcept {
|
||||
if (m_size > 0) {
|
||||
--m_size;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, size_t C>
|
||||
class vector : public ivector<T> {
|
||||
private:
|
||||
T m_arr[C];
|
||||
|
||||
public:
|
||||
vector() : ivector<T>(m_arr, C) { }
|
||||
};
|
||||
|
||||
} // namespace mtl
|
||||
Loading…
x
Reference in New Issue
Block a user