#pragma once
#include <atomic>
#include <cstddef>
#include <new>
#include <thread>
#include <folly/CPortability.h>
#include <folly/ConstexprMath.h>
#include <folly/Likely.h>
#include <folly/ScopeGuard.h>
#include <folly/lang/Align.h>
#include <folly/lang/Bits.h>
#include <folly/lang/New.h>
namespace folly {
template <typename Item>
struct atomic_grow_array_policy_default { … };
template <
typename Item,
typename Policy = atomic_grow_array_policy_default<Item>>
class atomic_grow_array : private Policy {
public:
using size_type = std::size_t;
using value_type = Item;
class iterator;
class const_iterator;
private:
static constexpr bool is_nothrow_grow_v =
noexcept(FOLLY_DECLVAL(Policy const&).grow(0, 0)) &&
noexcept(FOLLY_DECLVAL(Policy const&).make()) &&
noexcept(::operator new(0));
struct array;
struct end_tag {};
template <bool>
class basic_view;
template <bool Const, typename Down>
class basic_iterator {
private:
template <bool, typename>
friend class basic_iterator;
template <bool>
friend class basic_view;
using self = basic_iterator;
using down = Down;
friend down;
template <typename T>
using maybe_add_const_t = conditional_t<Const, T const, T>;
array const* array_{};
size_type index_{};
basic_iterator(array const* const a, size_type const i) noexcept
: array_{a}, index_{i} {}
basic_iterator(array const* const a, end_tag) noexcept
: array_{a}, index_{a ? a->size : 0} {}
template <
bool ThatC,
typename ThatDown,
bool ThisC = Const,
typename = std::enable_if_t<!ThatC && ThisC>>
explicit basic_iterator(basic_iterator<ThatC, ThatDown> that) noexcept
: array_{that.array_}, index_{that.index_} {}
down& as_down() noexcept { return static_cast<down&>(*this); }
down const& as_down() const noexcept {
return static_cast<down const&>(*this);
}
public:
using iterator_category = std::random_access_iterator_tag;
using value_type = atomic_grow_array::value_type;
using difference_type = std::ptrdiff_t;
using pointer = maybe_add_const_t<value_type>*;
using reference = maybe_add_const_t<value_type>&;
basic_iterator() = default;
down& operator++() noexcept { return ++index_, as_down(); }
down operator++(int) noexcept { return down{array_, index_++}; }
down& operator+=(difference_type const n) noexcept {
return index_ += n, as_down();
}
down operator+(difference_type const n) noexcept {
return down{as_down()} += n;
}
down& operator-=(difference_type const n) noexcept {
return index_ -= n, as_down();
}
down operator-(difference_type const n) noexcept {
return down{as_down()} -= n;
}
friend difference_type operator-(down const lhs, down const rhs) noexcept {
return lhs.index_ - rhs.index_;
}
friend bool operator==(down const lhs, down const rhs) noexcept {
return lhs.index_ == rhs.index_;
}
friend bool operator!=(down const lhs, down const rhs) noexcept {
return lhs.index_ != rhs.index_;
}
friend bool operator<(down const lhs, down const rhs) noexcept {
return lhs.index < rhs.index_;
}
friend bool operator<=(down const lhs, down const rhs) noexcept {
return lhs.index <= rhs.index_;
}
friend bool operator>(down const lhs, down const rhs) noexcept {
return lhs.index > rhs.index_;
}
friend bool operator>=(down const lhs, down const rhs) noexcept {
return lhs.index >= rhs.index_;
}
reference operator*() noexcept { return *array_->list[index_]; }
reference operator[](difference_type const n) { return *(*this + n); }
};
template <bool Const>
class basic_view {
private:
friend atomic_grow_array;
template <typename T>
using maybe_add_const_t = conditional_t<Const, T const, T>;
using up = atomic_grow_array;
array const* array_{};
explicit basic_view(array const* arr) noexcept : array_{arr} {}
template <
bool ThatC,
bool ThisC = Const,
typename = std::enable_if_t<!ThatC && ThisC>>
explicit basic_view(basic_view<ThatC> that) noexcept
: array_{that.array_} {}
public:
using value_type = typename atomic_grow_array::value_type;
using size_type = typename atomic_grow_array::size_type;
using reference = maybe_add_const_t<value_type>&;
using const_reference = value_type const&;
using iterator = conditional_t<Const, up::const_iterator, up::iterator>;
using const_iterator = up::const_iterator;
basic_view() = default;
iterator begin() noexcept { return iterator{array_, 0}; }
const_iterator begin() const noexcept { return iterator{array_, 0}; }
const_iterator cbegin() const noexcept { return iterator{array_, 0}; }
iterator end() noexcept { return iterator{array_, end_tag{}}; }
const_iterator end() const noexcept { return iterator{array_, end_tag{}}; }
const_iterator cend() const noexcept { return iterator{array_, end_tag{}}; }
size_type size() const noexcept { return array_ ? array_->size : 0; }
bool empty() const noexcept { return !size(); }
reference operator[](size_type index) noexcept {
return *array_->list[index];
}
const_reference operator[](size_type index) const noexcept {
return *array_->list[index];
}
};
public:
atomic_grow_array() = default;
explicit atomic_grow_array(Policy const& policy_)
noexcept(noexcept(Policy{ … }
~atomic_grow_array() { … }
Policy const& policy() const noexcept { … }
size_t size() const noexcept { … }
bool empty() const noexcept { … }
FOLLY_ALWAYS_INLINE value_type& operator[](size_type const index)
noexcept(is_nothrow_grow_v) { … }
class iterator : private basic_iterator<false, iterator> {
using base = basic_iterator<false, iterator>;
friend base;
friend const_iterator;
template <bool>
friend class basic_view;
public:
using typename base::difference_type;
using typename base::iterator_category;
using typename base::pointer;
using typename base::reference;
using typename base::value_type;
using base::base;
using base::operator++;
using base::operator+;
using base::operator+=;
using base::operator-;
using base::operator-=;
using base::operator*;
using base::operator[];
};
class const_iterator : private basic_iterator<true, const_iterator> {
using base = basic_iterator<true, const_iterator>;
friend base;
template <bool>
friend class basic_view;
public:
using typename base::difference_type;
using typename base::iterator_category;
using typename base::pointer;
using typename base::reference;
using typename base::value_type;
using base::base;
using base::operator++;
using base::operator+;
using base::operator+=;
using base::operator-;
using base::operator-=;
using base::operator*;
using base::operator[];
const_iterator(iterator that) noexcept : base{that} {}
};
class view : private basic_view<false> {
friend atomic_grow_array;
using base = basic_view<false>;
public:
using typename base::const_iterator;
using typename base::const_reference;
using typename base::iterator;
using typename base::reference;
using typename base::size_type;
using typename base::value_type;
using base::base;
using base::begin;
using base::cbegin;
using base::cend;
using base::empty;
using base::end;
using base::size;
using base::operator[];
};
class const_view : private basic_view<true> {
friend atomic_grow_array;
using base = basic_view<true>;
public:
using typename base::const_iterator;
using typename base::const_reference;
using typename base::iterator;
using typename base::reference;
using typename base::size_type;
using typename base::value_type;
using base::base;
using base::begin;
using base::cbegin;
using base::cend;
using base::empty;
using base::end;
using base::size;
using base::operator[];
const_view(view that) noexcept : base{that} {}
};
view as_view() noexcept { … }
const_view as_view() const noexcept { … }
private:
static constexpr auto mo_acquire = std::memory_order_acquire;
static constexpr auto mo_release = std::memory_order_release;
static constexpr auto mo_acq_rel = std::memory_order_acq_rel;
struct array {
array* next{};
size_type size{};
value_type* list[];
};
FOLLY_NOINLINE array* at_slow(size_type const index)
noexcept(is_nothrow_grow_v) { … }
static constexpr size_type array_align() { … }
static size_type array_size(size_type const size, size_type const base) { … }
static value_type* array_slab(array* const curr) { … }
array* new_array(size_type const size, array*& next) { … }
void del_array(array* const curr) { … }
void reset() { … }
std::atomic<size_type> size_{0};
std::atomic<array*> array_{nullptr};
};
}