#ifndef QUICHE_COMMON_QUICHE_CIRCULAR_DEQUE_H_
#define QUICHE_COMMON_QUICHE_CIRCULAR_DEQUE_H_
#include <algorithm>
#include <cstddef>
#include <cstring>
#include <iterator>
#include <memory>
#include <ostream>
#include <type_traits>
#include "quiche/common/platform/api/quiche_export.h"
#include "quiche/common/platform/api/quiche_logging.h"
namespace quiche {
template <typename T, size_t MinCapacityIncrement = 3,
typename Allocator = std::allocator<T>>
class QUICHE_NO_EXPORT QuicheCircularDeque {
using AllocatorTraits = std::allocator_traits<Allocator>;
template <typename Pointee>
class QUICHE_NO_EXPORT basic_iterator {
using size_type = typename AllocatorTraits::size_type;
public:
using iterator_category = std::random_access_iterator_tag;
using value_type = typename AllocatorTraits::value_type;
using difference_type = typename AllocatorTraits::difference_type;
using pointer = Pointee*;
using reference = Pointee&;
basic_iterator() = default;
basic_iterator(
const basic_iterator<value_type>& it)
: deque_(it.deque_), index_(it.index_) {}
basic_iterator& operator=(const basic_iterator<value_type>& it) {
if (this != &it) {
deque_ = it.deque_;
index_ = it.index_;
}
return *this;
}
reference operator*() const { return *deque_->index_to_address(index_); }
pointer operator->() const { return deque_->index_to_address(index_); }
reference operator[](difference_type i) { return *(*this + i); }
basic_iterator& operator++() {
Increment();
return *this;
}
basic_iterator operator++(int) {
basic_iterator result = *this;
Increment();
return result;
}
basic_iterator operator--() {
Decrement();
return *this;
}
basic_iterator operator--(int) {
basic_iterator result = *this;
Decrement();
return result;
}
friend basic_iterator operator+(const basic_iterator& it,
difference_type delta) {
basic_iterator result = it;
result.IncrementBy(delta);
return result;
}
basic_iterator& operator+=(difference_type delta) {
IncrementBy(delta);
return *this;
}
friend basic_iterator operator-(const basic_iterator& it,
difference_type delta) {
basic_iterator result = it;
result.IncrementBy(-delta);
return result;
}
basic_iterator& operator-=(difference_type delta) {
IncrementBy(-delta);
return *this;
}
friend difference_type operator-(const basic_iterator& lhs,
const basic_iterator& rhs) {
return lhs.ExternalPosition() - rhs.ExternalPosition();
}
friend bool operator==(const basic_iterator& lhs,
const basic_iterator& rhs) {
return lhs.index_ == rhs.index_;
}
friend bool operator!=(const basic_iterator& lhs,
const basic_iterator& rhs) {
return !(lhs == rhs);
}
friend bool operator<(const basic_iterator& lhs,
const basic_iterator& rhs) {
return lhs.ExternalPosition() < rhs.ExternalPosition();
}
friend bool operator<=(const basic_iterator& lhs,
const basic_iterator& rhs) {
return !(lhs > rhs);
}
friend bool operator>(const basic_iterator& lhs,
const basic_iterator& rhs) {
return lhs.ExternalPosition() > rhs.ExternalPosition();
}
friend bool operator>=(const basic_iterator& lhs,
const basic_iterator& rhs) {
return !(lhs < rhs);
}
private:
basic_iterator(const QuicheCircularDeque* deque, size_type index)
: deque_(deque), index_(index) {}
void Increment() {
QUICHE_DCHECK_LE(ExternalPosition() + 1, deque_->size());
index_ = deque_->index_next(index_);
}
void Decrement() {
QUICHE_DCHECK_GE(ExternalPosition(), 1u);
index_ = deque_->index_prev(index_);
}
void IncrementBy(difference_type delta) {
if (delta >= 0) {
QUICHE_DCHECK_LE(static_cast<size_type>(ExternalPosition() + delta),
deque_->size());
} else {
QUICHE_DCHECK_GE(ExternalPosition(), static_cast<size_type>(-delta));
}
index_ = deque_->index_increment_by(index_, delta);
}
size_type ExternalPosition() const {
if (index_ >= deque_->begin_) {
return index_ - deque_->begin_;
}
return index_ + deque_->data_capacity() - deque_->begin_;
}
friend class QuicheCircularDeque;
const QuicheCircularDeque* deque_ = nullptr;
size_type index_ = 0;
};
public:
using allocator_type = typename AllocatorTraits::allocator_type;
using value_type = typename AllocatorTraits::value_type;
using size_type = typename AllocatorTraits::size_type;
using difference_type = typename AllocatorTraits::difference_type;
using reference = value_type&;
using const_reference = const value_type&;
using pointer = typename AllocatorTraits::pointer;
using const_pointer = typename AllocatorTraits::const_pointer;
using iterator = basic_iterator<T>;
using const_iterator = basic_iterator<const T>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
QuicheCircularDeque() : … { … }
explicit QuicheCircularDeque(const allocator_type& alloc)
: … { … }
QuicheCircularDeque(size_type count, const T& value,
const Allocator& alloc = allocator_type())
: … { … }
explicit QuicheCircularDeque(size_type count,
const Allocator& alloc = allocator_type())
: … { … }
template <
class InputIt,
typename = std::enable_if_t<std::is_base_of<
std::input_iterator_tag,
typename std::iterator_traits<InputIt>::iterator_category>::value>>
QuicheCircularDeque(InputIt first, InputIt last,
const Allocator& alloc = allocator_type())
: allocator_and_data_(alloc) { … }
QuicheCircularDeque(const QuicheCircularDeque& other)
: … { … }
QuicheCircularDeque(const QuicheCircularDeque& other,
const allocator_type& alloc)
: … { … }
QuicheCircularDeque(QuicheCircularDeque&& other)
: … { … }
QuicheCircularDeque(QuicheCircularDeque&& other, const allocator_type& alloc)
: … { … }
QuicheCircularDeque(std::initializer_list<T> init,
const allocator_type& alloc = allocator_type())
: … { … }
QuicheCircularDeque& operator=(const QuicheCircularDeque& other) { … }
QuicheCircularDeque& operator=(QuicheCircularDeque&& other) { … }
~QuicheCircularDeque() { … }
void assign(size_type count, const T& value) { … }
template <
class InputIt,
typename = std::enable_if_t<std::is_base_of<
std::input_iterator_tag,
typename std::iterator_traits<InputIt>::iterator_category>::value>>
void assign(InputIt first, InputIt last) { … }
void assign(std::initializer_list<T> ilist) { … }
reference at(size_type pos) { … }
const_reference at(size_type pos) const { … }
reference operator[](size_type pos) { … }
const_reference operator[](size_type pos) const { … }
reference front() { … }
const_reference front() const { … }
reference back() { … }
const_reference back() const { … }
iterator begin() { … }
const_iterator begin() const { … }
const_iterator cbegin() const { … }
iterator end() { … }
const_iterator end() const { … }
const_iterator cend() const { … }
reverse_iterator rbegin() { … }
const_reverse_iterator rbegin() const { … }
const_reverse_iterator crbegin() const { … }
reverse_iterator rend() { … }
const_reverse_iterator rend() const { … }
const_reverse_iterator crend() const { … }
size_type capacity() const { … }
void reserve(size_type new_cap) { … }
void clear() { … }
bool empty() const { … }
size_type size() const { … }
void resize(size_type count) { … }
void resize(size_type count, const value_type& value) { … }
void push_front(const T& value) { … }
void push_front(T&& value) { … }
template <class... Args>
reference emplace_front(Args&&... args) { … }
void push_back(const T& value) { … }
void push_back(T&& value) { … }
template <class... Args>
reference emplace_back(Args&&... args) { … }
void pop_front() { … }
size_type pop_front_n(size_type count) { … }
void pop_back() { … }
size_type pop_back_n(size_type count) { … }
void swap(QuicheCircularDeque& other) { … }
friend void swap(QuicheCircularDeque& lhs, QuicheCircularDeque& rhs) {
lhs.swap(rhs);
}
allocator_type get_allocator() const { … }
friend bool operator==(const QuicheCircularDeque& lhs,
const QuicheCircularDeque& rhs) {
return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
friend bool operator!=(const QuicheCircularDeque& lhs,
const QuicheCircularDeque& rhs) {
return !(lhs == rhs);
}
friend QUICHE_NO_EXPORT std::ostream& operator<<(
std::ostream& os, const QuicheCircularDeque& dq) {
os << "{";
for (size_type pos = 0; pos != dq.size(); ++pos) {
if (pos != 0) {
os << ",";
}
os << " " << dq[pos];
}
os << " }";
return os;
}
private:
void MoveRetainAllocator(QuicheCircularDeque&& other) { … }
template <
typename InputIt,
typename = std::enable_if_t<std::is_base_of<
std::input_iterator_tag,
typename std::iterator_traits<InputIt>::iterator_category>::value>>
void AssignRange(InputIt first, InputIt last) { … }
void DestroyAndDeallocateAll() { … }
void ClearRetainCapacity() { … }
void MaybeShrinkCapacity() { … }
void MaybeExpandCapacity(size_t num_additional_elements) { … }
void Relocate(size_t new_capacity) { … }
template <typename T_ = T>
typename std::enable_if<std::is_trivially_copyable<T_>::value, void>::type
RelocateUnwrappedRange(size_type begin, size_type end, pointer dest) const { … }
template <typename T_ = T>
typename std::enable_if<!std::is_trivially_copyable<T_>::value &&
std::is_move_constructible<T_>::value,
void>::type
RelocateUnwrappedRange(size_type begin, size_type end, pointer dest) const { … }
template <typename T_ = T>
typename std::enable_if<!std::is_trivially_copyable<T_>::value &&
!std::is_move_constructible<T_>::value,
void>::type
RelocateUnwrappedRange(size_type begin, size_type end, pointer dest) const { … }
template <class... U>
void ResizeInternal(size_type count, U&&... u) { … }
void DestroyRange(size_type begin, size_type end) const { … }
void DestroyUnwrappedRange(size_type begin, size_type end) const { … }
void DestroyByIndex(size_type index) const { … }
void DestroyByAddress(pointer address) const { … }
size_type data_capacity() const { … }
pointer index_to_address(size_type index) const { … }
size_type index_prev(size_type index) const { … }
size_type index_next(size_type index) const { … }
size_type index_increment_by(size_type index, difference_type delta) const { … }
struct QUICHE_NO_EXPORT AllocatorAndData : private allocator_type {
explicit AllocatorAndData(const allocator_type& alloc)
: allocator_type(alloc) {}
const allocator_type& allocator() const { return *this; }
allocator_type& allocator() { return *this; }
pointer data = nullptr;
size_type data_capacity = 0;
};
size_type begin_ = 0;
size_type end_ = 0;
AllocatorAndData allocator_and_data_;
};
}
#endif