diff --git a/AK/SegmentedVector.h b/AK/SegmentedVector.h new file mode 100644 index 0000000000..b78760bc10 --- /dev/null +++ b/AK/SegmentedVector.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2023, Aliaksandr Kalenik + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace AK { + +template +class SegmentedVector { +private: + using VisibleType = RemoveReference; + static constexpr bool contains_reference = IsLvalueReference; + +public: + SegmentedVector() = default; + + size_t size() const { return m_size; } + bool is_empty() const { return m_size == 0; } + + using Iterator = SimpleIterator; + + Iterator begin() { return Iterator::begin(*this); } + Iterator end() { return Iterator::end(*this); } + + ALWAYS_INLINE VisibleType const& at(size_t i) const + { + VERIFY(i < m_size); + auto segment_index = i / segment_size; + auto index_in_segment = i % segment_size; + return m_segments[segment_index]->at(index_in_segment); + } + + ALWAYS_INLINE VisibleType& at(size_t i) + { + VERIFY(i < m_size); + auto segment_index = i / segment_size; + auto index_in_segment = i % segment_size; + return m_segments[segment_index]->at(index_in_segment); + } + + ALWAYS_INLINE VisibleType const& operator[](size_t i) const { return at(i); } + ALWAYS_INLINE VisibleType& operator[](size_t i) { return at(i); } + + void append(T&& value) + { + if (m_segments.is_empty() || m_segments.last()->size() >= segment_size) + m_segments.append(make>()); + + if constexpr (contains_reference) { + m_segments.last()->append(value); + } else { + m_segments.last()->append(move(value)); + } + ++m_size; + } + +private: + Vector>> m_segments; + size_t m_size { 0 }; +}; + +} diff --git a/Tests/AK/CMakeLists.txt b/Tests/AK/CMakeLists.txt index 8ccab64845..5391c1dacd 100644 --- a/Tests/AK/CMakeLists.txt +++ b/Tests/AK/CMakeLists.txt @@ -63,6 +63,7 @@ set(AK_TEST_SOURCES TestQuickSort.cpp TestRedBlackTree.cpp TestRefPtr.cpp + TestSegmentedVector.cpp TestSIMD.cpp TestSinglyLinkedList.cpp TestSlugify.cpp diff --git a/Tests/AK/TestSegmentedVector.cpp b/Tests/AK/TestSegmentedVector.cpp new file mode 100644 index 0000000000..13378638df --- /dev/null +++ b/Tests/AK/TestSegmentedVector.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023, Aliaksandr Kalenik + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +TEST_CASE(append) +{ + AK::SegmentedVector segmented_vector; + segmented_vector.append(1); + segmented_vector.append(2); + segmented_vector.append(3); + EXPECT_EQ(segmented_vector.size(), 3u); +} + +TEST_CASE(at) +{ + AK::SegmentedVector segmented_vector; + segmented_vector.append(1); + segmented_vector.append(2); + segmented_vector.append(3); + EXPECT_EQ(segmented_vector[0], 1); + EXPECT_EQ(segmented_vector[1], 2); + EXPECT_EQ(segmented_vector[2], 3); +} diff --git a/Userland/Libraries/LibWeb/Painting/RecordingPainter.h b/Userland/Libraries/LibWeb/Painting/RecordingPainter.h index 7de155d457..5499009e23 100644 --- a/Userland/Libraries/LibWeb/Painting/RecordingPainter.h +++ b/Userland/Libraries/LibWeb/Painting/RecordingPainter.h @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -623,7 +624,7 @@ private: PaintingCommand command; }; - Vector m_painting_commands; + AK::SegmentedVector m_painting_commands; Vector m_state_stack; };