1#ifndef ALGORITHMS_SEGMENTED_VECTOR_H
2#define ALGORITHMS_SEGMENTED_VECTOR_H
52namespace segmented_vector {
53template <
class Entry,
class Allocator = std::allocator<Entry>>
54class SegmentedVector {
55 using ATraits = std::allocator_traits<Allocator>;
56 using EntryAllocator =
typename ATraits::template rebind_alloc<Entry>;
58 static const size_t SEGMENT_BYTES = 8192;
60 static const size_t SEGMENT_ELEMENTS = (SEGMENT_BYTES /
sizeof(Entry)) >= 1
61 ? (SEGMENT_BYTES /
sizeof(Entry))
64 EntryAllocator entry_allocator;
66 std::vector<Entry*> segments;
69 size_t get_segment(
size_t index)
const {
return index / SEGMENT_ELEMENTS; }
71 size_t get_offset(
size_t index)
const {
return index % SEGMENT_ELEMENTS; }
75 Entry* new_segment = entry_allocator.allocate(SEGMENT_ELEMENTS);
76 segments.push_back(new_segment);
79 SegmentedVector(
const SegmentedVector<Entry>&) =
delete;
80 SegmentedVector& operator=(
const SegmentedVector<Entry>&) =
delete;
82 template <
bool is_const>
84 std::vector<Entry*>::iterator current_segment;
85 Entry* current_entry =
nullptr;
86 Entry* first_entry =
nullptr;
87 Entry* last_entry =
nullptr;
90 using value_type = std::conditional_t<is_const, const Entry, Entry>;
91 using pointer = std::conditional_t<is_const, const Entry*, Entry*>;
92 using reference = std::conditional_t<is_const, const Entry&, Entry&>;
93 using difference_type = std::ptrdiff_t;
94 using iterator_category = std::random_access_iterator_tag;
96 sviterator() =
default;
99 std::vector<Entry*>::iterator current_segment,
100 Entry* current_entry)
101 : current_segment(current_segment)
102 , current_entry(current_entry)
103 , first_entry(*current_segment)
104 , last_entry(first_entry + SEGMENT_ELEMENTS)
108 reference operator*()
const {
return *current_entry; }
109 pointer operator->() {
return current_entry; };
111 sviterator& operator++()
115 if (current_entry == last_entry) {
117 first_entry = *current_segment;
118 last_entry = *current_segment + SEGMENT_ELEMENTS;
119 current_entry = first_entry;
125 sviterator& operator--()
127 if (current_entry == first_entry) {
129 first_entry = *current_segment;
130 last_entry = *current_segment + SEGMENT_ELEMENTS;
131 current_entry = last_entry;
139 friend difference_type
140 operator-(
const sviterator& lhs,
const sviterator& rhs)
142 return (lhs.current_segment - rhs.current_segment) *
144 (lhs.current_entry - rhs.current_entry);
147 sviterator& operator+=(
int n)
149 int offset = n + (current_entry - first_entry);
151 if (offset > 0 && offset < SEGMENT_ELEMENTS) {
156 const difference_type segment_offset =
158 ? offset / difference_type(SEGMENT_ELEMENTS)
159 : -difference_type((-offset - 1) / SEGMENT_ELEMENTS) - 1;
161 current_segment += segment_offset;
162 first_entry = *current_segment;
163 last_entry = *current_segment + SEGMENT_ELEMENTS;
166 (offset - segment_offset * difference_type(SEGMENT_ELEMENTS));
171 sviterator operator++(
int)
178 sviterator operator--(
int)
185 friend sviterator operator+(
const sviterator& it,
int n)
192 friend sviterator operator+(
int n,
const sviterator& it)
199 friend sviterator operator-(
const sviterator& it,
int n)
206 sviterator& operator-=(
int n) {
return (*
this) += -n; }
208 reference operator[](
int n) {
return *(*
this + n); };
210 friend auto operator<=>(
const sviterator&,
const sviterator&) =
default;
212 friend void swap(sviterator& left, sviterator& right)
215 swap(left.current_segment, right.current_segment);
216 swap(left.current_entry, right.current_entry);
221 using iterator = sviterator<false>;
222 using const_iterator = sviterator<true>;
231 SegmentedVector(std::size_t size,
const Entry& entry = Entry())
234 while (size > the_size) {
239 SegmentedVector(
const EntryAllocator& allocator_)
240 : entry_allocator(allocator_)
248 for (
size_t i = 0; i < the_size; ++i) {
249 ATraits::destroy(entry_allocator, &
operator[](i));
251 for (
size_t segment = 0; segment < segments.size(); ++segment) {
252 entry_allocator.deallocate(segments[segment], SEGMENT_ELEMENTS);
256 Entry& operator[](
size_t index)
258 assert(index < the_size);
259 size_t segment = get_segment(index);
260 size_t offset = get_offset(index);
261 return segments[segment][offset];
264 const Entry& operator[](
size_t index)
const
266 assert(index < the_size);
267 size_t segment = get_segment(index);
268 size_t offset = get_offset(index);
269 return segments[segment][offset];
272 size_t size()
const {
return the_size; }
274 void push_back(
const Entry& entry)
276 size_t segment = get_segment(the_size);
277 size_t offset = get_offset(the_size);
278 if (segment == segments.size() - 1) {
283 ATraits::construct(entry_allocator, segments[segment] + offset, entry);
289 ATraits::destroy(entry_allocator, &
operator[](the_size - 1));
298 void resize(
size_t new_size, Entry entry = Entry())
300 while (new_size < the_size) {
303 while (new_size > the_size) {
310 for (
size_t i = 0; i < the_size; ++i) {
311 ATraits::destroy(entry_allocator, &
operator[](i));
317 iterator begin() {
return iterator(segments.begin(), segments.front()); }
321 return iterator(segments.end() - 1, *(segments.end() - 1));
324 const_iterator begin()
const
326 return const_iterator(segments.begin(), *segments.front());
329 const_iterator end()
const
331 return const_iterator(segments.end() - 1, *(segments.end() - 1));
335template <
class Element,
class Allocator = std::allocator<Element>>
336class SegmentedArrayVector {
337 using ATraits = std::allocator_traits<Allocator>;
338 using ElementAllocator =
typename ATraits::template rebind_alloc<Element>;
340 static const size_t SEGMENT_BYTES = 8192;
342 const size_t elements_per_array;
343 const size_t arrays_per_segment;
344 const size_t elements_per_segment;
346 ElementAllocator element_allocator;
348 std::vector<Element*> segments;
351 size_t get_segment(
size_t index)
const
353 return index / arrays_per_segment;
356 size_t get_offset(
size_t index)
const
358 return (index % arrays_per_segment) * elements_per_array;
363 Element* new_segment = element_allocator.allocate(elements_per_segment);
364 segments.push_back(new_segment);
367 SegmentedArrayVector(
const SegmentedArrayVector<Element>&) =
delete;
368 SegmentedArrayVector&
369 operator=(
const SegmentedArrayVector<Element>&) =
delete;
372 SegmentedArrayVector(
size_t elements_per_array_)
373 : elements_per_array(elements_per_array_)
374 , arrays_per_segment(
std::max(
375 SEGMENT_BYTES / (elements_per_array * sizeof(Element)),
377 , elements_per_segment(elements_per_array * arrays_per_segment)
382 SegmentedArrayVector(
383 size_t elements_per_array_,
384 const ElementAllocator& allocator_)
385 : element_allocator(allocator_)
386 , elements_per_array(elements_per_array_)
387 , arrays_per_segment(
std::max(
388 SEGMENT_BYTES / (elements_per_array * sizeof(Element)),
390 , elements_per_segment(elements_per_array * arrays_per_segment)
395 ~SegmentedArrayVector()
397 for (
size_t i = 0; i < the_size; ++i) {
398 for (
size_t offset = 0; offset < elements_per_array; ++offset) {
399 ATraits::destroy(element_allocator,
operator[](i) + offset);
402 for (
size_t i = 0; i < segments.size(); ++i) {
403 element_allocator.deallocate(segments[i], elements_per_segment);
407 Element* operator[](
size_t index)
409 assert(index < the_size);
410 size_t segment = get_segment(index);
411 size_t offset = get_offset(index);
412 return segments[segment] + offset;
415 const Element* operator[](
size_t index)
const
417 assert(index < the_size);
418 size_t segment = get_segment(index);
419 size_t offset = get_offset(index);
420 return segments[segment] + offset;
423 size_t size()
const {
return the_size; }
425 void push_back(
const Element* entry)
427 size_t segment = get_segment(the_size);
428 size_t offset = get_offset(the_size);
429 if (segment == segments.size()) {
434 Element* dest = segments[segment] + offset;
435 for (
size_t i = 0; i < elements_per_array; ++i)
436 ATraits::construct(element_allocator, dest++, *entry++);
442 for (
size_t offset = 0; offset < elements_per_array; ++offset) {
445 operator[](the_size - 1) + offset);
455 void resize(
size_t new_size,
const Element* entry)
457 while (new_size < the_size) {
460 while (new_size > the_size) {