mirror of
https://github.com/wichtounet/thor-os.git
synced 2025-09-15 07:27:42 -04:00
Implementation of a deque
This commit is contained in:
parent
c2c184f693
commit
b09d34e468
567
tstl/include/deque.hpp
Normal file
567
tstl/include/deque.hpp
Normal file
@ -0,0 +1,567 @@
|
||||
//=======================================================================
|
||||
// Copyright Baptiste Wicht 2013-2016.
|
||||
// Distributed under the terms of the MIT License.
|
||||
// (See accompanying file LICENSE or copy at
|
||||
// http://www.opensource.org/licenses/MIT)
|
||||
//=======================================================================
|
||||
|
||||
#ifndef DEQUE_H
|
||||
#define DEQUE_H
|
||||
|
||||
#include <initializer_list.hpp>
|
||||
#include <types.hpp>
|
||||
#include <algorithms.hpp>
|
||||
#include <new.hpp>
|
||||
#include <iterator.hpp>
|
||||
|
||||
namespace std {
|
||||
|
||||
template <typename T>
|
||||
struct deque;
|
||||
|
||||
template <typename T>
|
||||
struct deque_iterator {
|
||||
using iterator_type = deque_iterator<T>; ///< The iterator type
|
||||
using value_type = T; ///< The value type
|
||||
using difference_type = int64_t; ///< The difference type
|
||||
using pointer = value_type*; ///< The pointer type
|
||||
using reference = value_type&; ///< The reference type
|
||||
|
||||
deque_iterator(deque<T>* container, int64_t index)
|
||||
: container(container), index(index) {
|
||||
// Nothing else to init
|
||||
}
|
||||
|
||||
deque_iterator(const deque_iterator& rhs) : container(rhs.container), index(rhs.index) {
|
||||
// Nothing else to init
|
||||
}
|
||||
|
||||
deque_iterator& operator=(const deque_iterator& rhs){
|
||||
if(this != &rhs){
|
||||
this->container = rhs.container;
|
||||
this->index = rhs.index;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
T& operator*() {
|
||||
return (*container)[index];
|
||||
}
|
||||
|
||||
deque_iterator& operator++() {
|
||||
++index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
deque_iterator operator++(int) {
|
||||
auto it = *this;
|
||||
++(*this);
|
||||
return it;
|
||||
}
|
||||
|
||||
deque_iterator& operator--() {
|
||||
--index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
deque_iterator operator--(int) {
|
||||
auto it = *this;
|
||||
--(*this);
|
||||
return it;
|
||||
}
|
||||
|
||||
deque_iterator& operator+=(int n) {
|
||||
index += n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
deque_iterator operator+(int n) {
|
||||
auto it = *this;
|
||||
it += n;
|
||||
return it;
|
||||
}
|
||||
|
||||
deque_iterator& operator-=(int n) {
|
||||
index -= n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
deque_iterator operator-(int n) {
|
||||
auto it = *this;
|
||||
it -= n;
|
||||
return it;
|
||||
}
|
||||
|
||||
bool operator==(const deque_iterator& rhs) {
|
||||
return index == rhs.index;
|
||||
}
|
||||
|
||||
bool operator!=(const deque_iterator& rhs) {
|
||||
return index != rhs.index;
|
||||
}
|
||||
|
||||
difference_type operator-(const deque_iterator& rhs) {
|
||||
return index - rhs.index;
|
||||
}
|
||||
|
||||
friend struct deque<T>;
|
||||
|
||||
private:
|
||||
deque<T>* container;
|
||||
int64_t index;
|
||||
};
|
||||
|
||||
// TODO We should find a way to get rid of the painful situation when size
|
||||
// = 0 for the indices
|
||||
|
||||
/*!
|
||||
* \brief A double-ended queue.
|
||||
*
|
||||
* Insertions at the front and at the back are done in O(1) and random access is
|
||||
* possible in O(1). Insertions at other positions is done in O(n).
|
||||
*/
|
||||
template <typename T>
|
||||
struct deque {
|
||||
using value_type = T; ///< The value type contained in the vector
|
||||
using pointer_type = value_type*; ///< The pointer type contained in the vector
|
||||
using size_type = size_t; ///< The size type
|
||||
using reference_type = value_type&; ///< The reference type
|
||||
using const_reference_type = const value_type&; ///< The const reference type
|
||||
|
||||
using iterator = deque_iterator<T>; ///< The iterator type
|
||||
using const_iterator = deque_iterator<const T>; ///< The const iterator type
|
||||
|
||||
using reverse_iterator = std::reverse_iterator<iterator>; ///< The reverse iterator type
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>; ///< The const reverse iterator type
|
||||
|
||||
static constexpr const size_t block_elements = 16; ///< Number of entries per block
|
||||
static constexpr const size_t block_size = block_elements * sizeof(T); ///< Size of a block, in bytes
|
||||
|
||||
/*!
|
||||
* \brief Construct an empty deque
|
||||
*/
|
||||
deque()
|
||||
: data(nullptr), first_element(0), last_element(0), blocks(0), _size(0) {
|
||||
// By default, no capacity
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Construct a deque containing the given values
|
||||
*/
|
||||
deque(initializer_list<T> values)
|
||||
: deque() {
|
||||
ensure_capacity_back(values.size());
|
||||
|
||||
for (auto& value : values) {
|
||||
push_back(value);
|
||||
}
|
||||
}
|
||||
|
||||
~deque() {
|
||||
for (size_t i = 0; i < _size; ++i) {
|
||||
(*this)[i].~value_type();
|
||||
}
|
||||
}
|
||||
|
||||
void push_back(T&& element) {
|
||||
ensure_capacity_back(1);
|
||||
|
||||
if (_size) {
|
||||
auto block = (last_element + 1) / block_elements;
|
||||
auto index = (last_element + 1) % block_elements;
|
||||
|
||||
data[block][index] = std::move(element);
|
||||
|
||||
++last_element;
|
||||
} else {
|
||||
auto block = last_element / block_elements;
|
||||
auto index = last_element % block_elements;
|
||||
|
||||
data[block][index] = std::move(element);
|
||||
}
|
||||
|
||||
++_size;
|
||||
}
|
||||
|
||||
void push_back(const T& element) {
|
||||
ensure_capacity_back(1);
|
||||
|
||||
if (_size) {
|
||||
auto block = (last_element + 1) / block_elements;
|
||||
auto index = (last_element + 1) % block_elements;
|
||||
|
||||
data[block][index] = element;
|
||||
|
||||
++last_element;
|
||||
} else {
|
||||
auto block = last_element / block_elements;
|
||||
auto index = last_element % block_elements;
|
||||
|
||||
data[block][index] = element;
|
||||
}
|
||||
|
||||
++_size;
|
||||
}
|
||||
|
||||
reference_type emplace_back() {
|
||||
ensure_capacity_back(1);
|
||||
|
||||
if (_size) {
|
||||
auto block = (last_element + 1) / block_elements;
|
||||
auto index = (last_element + 1) % block_elements;
|
||||
|
||||
new (&data[block][index]) T();
|
||||
|
||||
++last_element;
|
||||
} else {
|
||||
auto block = last_element / block_elements;
|
||||
auto index = last_element % block_elements;
|
||||
|
||||
new (&data[block][index]) T();
|
||||
}
|
||||
|
||||
++_size;
|
||||
|
||||
return back();
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
reference_type emplace_back(Args&&... args) {
|
||||
ensure_capacity_back(1);
|
||||
|
||||
if (_size) {
|
||||
auto block = (last_element + 1) / block_elements;
|
||||
auto index = (last_element + 1) % block_elements;
|
||||
|
||||
new (&data[block][index]) T(std::forward<Args>(args)...);
|
||||
|
||||
++last_element;
|
||||
} else {
|
||||
auto block = last_element / block_elements;
|
||||
auto index = last_element % block_elements;
|
||||
|
||||
new (&data[block][index]) T(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
++_size;
|
||||
|
||||
return back();
|
||||
}
|
||||
|
||||
void push_front(T&& element) {
|
||||
ensure_capacity_front(1);
|
||||
|
||||
if (_size) {
|
||||
auto block = (first_element - 1) / block_elements;
|
||||
auto index = (first_element - 1) % block_elements;
|
||||
|
||||
data[block][index] = std::move(element);
|
||||
|
||||
--first_element;
|
||||
} else {
|
||||
auto block = first_element / block_elements;
|
||||
auto index = first_element % block_elements;
|
||||
|
||||
data[block][index] = std::move(element);
|
||||
}
|
||||
|
||||
++_size;
|
||||
}
|
||||
|
||||
void push_front(const T& element) {
|
||||
ensure_capacity_front(1);
|
||||
|
||||
if (_size) {
|
||||
auto block = (first_element - 1) / block_elements;
|
||||
auto index = (first_element - 1) % block_elements;
|
||||
|
||||
data[block][index] = element;
|
||||
|
||||
--first_element;
|
||||
} else {
|
||||
auto block = first_element / block_elements;
|
||||
auto index = first_element % block_elements;
|
||||
|
||||
data[block][index] = element;
|
||||
}
|
||||
|
||||
++_size;
|
||||
}
|
||||
|
||||
reference_type emplace_front() {
|
||||
ensure_capacity_front(1);
|
||||
|
||||
if (_size) {
|
||||
auto block = (first_element - 1) / block_elements;
|
||||
auto index = (first_element - 1) % block_elements;
|
||||
|
||||
new (&data[block][index]) T();
|
||||
|
||||
--first_element;
|
||||
} else {
|
||||
auto block = first_element / block_elements;
|
||||
auto index = first_element % block_elements;
|
||||
|
||||
new (&data[block][index]) T();
|
||||
}
|
||||
|
||||
++_size;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
reference_type emplace_front(Args&&... args) {
|
||||
ensure_capacity_front(1);
|
||||
|
||||
if (_size) {
|
||||
auto block = (first_element - 1) / block_elements;
|
||||
auto index = (first_element - 1) % block_elements;
|
||||
|
||||
new (&data[block][index]) T(std::forward<Args>(args)...);
|
||||
|
||||
--first_element;
|
||||
} else {
|
||||
auto block = first_element / block_elements;
|
||||
auto index = first_element % block_elements;
|
||||
|
||||
new (&data[block][index]) T(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
++_size;
|
||||
}
|
||||
|
||||
void pop_back() {
|
||||
auto block = (last_element) / block_elements;
|
||||
auto index = (last_element) % block_elements;
|
||||
data[block][index].~value_type();
|
||||
|
||||
--_size;
|
||||
--last_element;
|
||||
|
||||
if (!_size) {
|
||||
first_element = last_element = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void pop_front() {
|
||||
auto block = (first_element) / block_elements;
|
||||
auto index = (first_element) % block_elements;
|
||||
data[block][index].~value_type();
|
||||
|
||||
--_size;
|
||||
++first_element;
|
||||
|
||||
if (!_size) {
|
||||
first_element = last_element = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void erase(size_t position) {
|
||||
for (size_t i = position; i < _size - 1; ++i) {
|
||||
(*this)[i] = std::move((*this)[i + 1]);
|
||||
}
|
||||
|
||||
auto block = (last_element) / block_elements;
|
||||
auto index = (last_element) % block_elements;
|
||||
data[block][index].~value_type();
|
||||
|
||||
--last_element;
|
||||
--_size;
|
||||
}
|
||||
|
||||
iterator erase(iterator position) {
|
||||
erase(position.index);
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
void erase(iterator first, iterator last) {
|
||||
auto n = last - first;
|
||||
|
||||
for (size_t i = first.index; i < _size - n; ++i) {
|
||||
(*this)[i] = std::move((*this)[i + n]);
|
||||
}
|
||||
|
||||
for (size_t i = _size - n; i < _size; ++i) {
|
||||
(*this)[i].~value_type();
|
||||
}
|
||||
|
||||
_size -= n;
|
||||
last_element -= n;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Removes all the elements of the deque
|
||||
*/
|
||||
void clear() {
|
||||
for (size_t i = 0; i < _size; ++i) {
|
||||
(*this)[i].~value_type();
|
||||
}
|
||||
|
||||
first_element = 0;
|
||||
last_element = 0;
|
||||
|
||||
_size = 0;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return _size;
|
||||
}
|
||||
|
||||
size_t max_size() const {
|
||||
return blocks * block_elements;
|
||||
}
|
||||
|
||||
reference_type operator[](size_t i) {
|
||||
auto block = (i + first_element) / block_elements;
|
||||
auto index = (i + first_element) % block_elements;
|
||||
return data[block][index];
|
||||
}
|
||||
|
||||
reference_type back() {
|
||||
auto block = (last_element) / block_elements;
|
||||
auto index = (last_element) % block_elements;
|
||||
return data[block][index];
|
||||
}
|
||||
|
||||
const_reference_type back() const {
|
||||
auto block = (last_element) / block_elements;
|
||||
auto index = (last_element) % block_elements;
|
||||
return data[block][index];
|
||||
}
|
||||
|
||||
reference_type front() {
|
||||
auto block = (first_element) / block_elements;
|
||||
auto index = (first_element) % block_elements;
|
||||
return data[block][index];
|
||||
}
|
||||
|
||||
const_reference_type front() const {
|
||||
auto block = (first_element) / block_elements;
|
||||
auto index = (first_element) % block_elements;
|
||||
return data[block][index];
|
||||
}
|
||||
|
||||
//Iterators
|
||||
|
||||
iterator begin() {
|
||||
return iterator(this, 0);
|
||||
}
|
||||
|
||||
constexpr const_iterator begin() const {
|
||||
return const_iterator(this, 0);
|
||||
}
|
||||
|
||||
iterator end() {
|
||||
return iterator(this, _size);
|
||||
}
|
||||
|
||||
constexpr const_iterator end() const {
|
||||
return const_iterator(this, _size);
|
||||
}
|
||||
|
||||
//Iterators
|
||||
|
||||
reverse_iterator rbegin() {
|
||||
return reverse_iterator(iterator(this, _size - 1));
|
||||
}
|
||||
|
||||
constexpr const_reverse_iterator rbegin() const {
|
||||
return const_iterator(const_iterator(this, _size - 1));
|
||||
}
|
||||
|
||||
reverse_iterator rend() {
|
||||
return reverse_iterator(iterator(this, -1));
|
||||
}
|
||||
|
||||
constexpr const_reverse_iterator rend() const {
|
||||
return const_reverse_iterator(const_iterator(this, -1));
|
||||
}
|
||||
|
||||
private:
|
||||
void ensure_capacity_front(size_t n) {
|
||||
auto capacity_front = first_element;
|
||||
|
||||
if (capacity_front < n) {
|
||||
if (!data) {
|
||||
blocks = n % block_elements == 0 ? n / block_elements : (n / block_elements) + 1;
|
||||
|
||||
data = new T*[blocks];
|
||||
|
||||
for (size_t i = 0; i < blocks; ++i) {
|
||||
data[i] = new T[block_elements];
|
||||
}
|
||||
|
||||
first_element = blocks * block_elements - 1;
|
||||
last_element = blocks * block_elements - 1;
|
||||
} else {
|
||||
auto expand_front = n - capacity_front;
|
||||
auto new_blocks = expand_front % block_elements == 0 ? expand_front / block_elements : (expand_front / block_elements) + 1;
|
||||
|
||||
auto new_data = new T*[blocks + new_blocks];
|
||||
|
||||
for (size_t i = 0; i < blocks; ++i) {
|
||||
new_data[i + new_blocks] = data[i];
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < new_blocks; ++i) {
|
||||
new_data[i] = new T[block_elements];
|
||||
}
|
||||
|
||||
first_element += new_blocks * block_elements;
|
||||
last_element += new_blocks * block_elements;
|
||||
|
||||
delete[] data;
|
||||
data = new_data;
|
||||
blocks += new_blocks;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ensure_capacity_back(size_t n) {
|
||||
auto very_last_element = blocks ? blocks * block_elements - 1 : 0;
|
||||
auto capacity_back = very_last_element - last_element;
|
||||
|
||||
if (capacity_back < n) {
|
||||
if (!data) {
|
||||
blocks = n % block_elements == 0 ? n / block_elements : (n / block_elements) + 1;
|
||||
|
||||
data = new T*[blocks];
|
||||
|
||||
for (size_t i = 0; i < blocks; ++i) {
|
||||
data[i] = new T[block_elements];
|
||||
}
|
||||
|
||||
first_element = 0;
|
||||
last_element = 0;
|
||||
} else {
|
||||
auto expand_back = n - capacity_back;
|
||||
auto new_blocks = expand_back % block_elements == 0 ? expand_back / block_elements : (expand_back / block_elements) + 1;
|
||||
|
||||
auto new_data = new T*[blocks + new_blocks];
|
||||
|
||||
for (size_t i = 0; i < blocks; ++i) {
|
||||
new_data[i] = data[i];
|
||||
}
|
||||
|
||||
for (size_t i = blocks; i < blocks + new_blocks; ++i) {
|
||||
new_data[i] = new T[block_elements];
|
||||
}
|
||||
|
||||
delete[] data;
|
||||
data = new_data;
|
||||
blocks += new_blocks;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
T** data;
|
||||
size_t first_element;
|
||||
size_t last_element;
|
||||
size_t blocks;
|
||||
size_t _size;
|
||||
};
|
||||
|
||||
} //end of namespace std
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user