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