--- qtwebengine-5.15.10_p20230815-orig/src/3rdparty/chromium/third_party/perfetto/include/perfetto/ext/base/circular_queue.h 2021-01-20 12:18:42.000000000 +1100 +++ qtwebengine-5.15.10_p20230815/src/3rdparty/chromium/third_party/perfetto/include/perfetto/ext/base/circular_queue.h 2023-10-08 12:24:47.019651717 +1100 @@ -18,6 +18,9 @@ #define INCLUDE_PERFETTO_EXT_BASE_CIRCULAR_QUEUE_H_ #include +#include + +#include #include #include "perfetto/base/logging.h" @@ -67,26 +70,22 @@ ignore_result(generation); } - T* operator->() { + Iterator(const Iterator&) noexcept = default; + Iterator& operator=(const Iterator&) noexcept = default; + Iterator(Iterator&&) noexcept = default; + Iterator& operator=(Iterator&&) noexcept = default; + + T* operator->() const { #if PERFETTO_DCHECK_IS_ON() PERFETTO_DCHECK(generation_ == queue_->generation()); #endif return queue_->Get(pos_); } - const T* operator->() const { - return const_cast::Iterator*>(this)->operator->(); - } - - T& operator*() { return *(operator->()); } - const T& operator*() const { return *(operator->()); } + T& operator*() const { return *(operator->()); } value_type& operator[](difference_type i) { return *(*this + i); } - const value_type& operator[](difference_type i) const { - return const_cast::Iterator&>(*this)[i]; - } - Iterator& operator++() { Add(1); return *this; @@ -174,21 +173,38 @@ #endif }; - CircularQueue(size_t initial_capacity = 1024) { Grow(initial_capacity); } + explicit CircularQueue(size_t initial_capacity = 1024) { + Grow(initial_capacity); + } - CircularQueue(CircularQueue&& other) noexcept { - // Copy all fields using the (private) default copy assignment operator. - *this = other; + CircularQueue(CircularQueue&& other) noexcept + : entries_(std::move(other.entries_)), + capacity_(other.capacity_), + begin_(other.begin_), + end_(other.end_) { increment_generation(); new (&other) CircularQueue(); // Reset the old queue so it's still usable. } - CircularQueue& operator=(CircularQueue&& other) { + CircularQueue& operator=(CircularQueue&& other) noexcept { this->~CircularQueue(); // Destroy the current state. new (this) CircularQueue(std::move(other)); // Use the move ctor above. return *this; } + explicit CircularQueue(const CircularQueue& other) noexcept { + Grow(other.capacity()); + for (const auto& e : const_cast(other)) + emplace_back(e); + PERFETTO_DCHECK(size() == other.size()); + } + + CircularQueue& operator=(const CircularQueue& other) noexcept { + this->~CircularQueue(); // Destroy the current state. + new (this) CircularQueue(other); // Use the copy ctor above. + return *this; + } + ~CircularQueue() { if (!entries_) { PERFETTO_DCHECK(empty()); @@ -196,7 +212,6 @@ } clear(); // Invoke destructors on all alive entries. PERFETTO_DCHECK(empty()); - free(entries_); } template @@ -220,6 +235,16 @@ void clear() { erase_front(size()); } + void shrink_to_fit() { + // We only bother shrinking if we can fit in quarter of the capacity we are + // currently using. Moreover, don't bother shrinking below 4096 elements as + // that will cause a lot of reallocations for little benefit. + if (size() > capacity() / 2 || capacity() <= 4096) { + return; + } + ChangeCapacity(capacity() / 2); + } + T& at(size_t idx) { PERFETTO_DCHECK(idx < size()); return *Get(begin_ + idx); @@ -248,9 +273,6 @@ #endif private: - CircularQueue(const CircularQueue&) = delete; - CircularQueue& operator=(const CircularQueue&) = default; - void Grow(size_t new_capacity = 0) { // Capacity must be always a power of two. This allows Get() to use a simple // bitwise-AND for handling the wrapping instead of a full division. @@ -260,9 +282,15 @@ // On 32-bit systems this might hit the 4GB wall and overflow. We can't do // anything other than crash in this case. PERFETTO_CHECK(new_capacity > capacity_); - size_t malloc_size = new_capacity * sizeof(T); - PERFETTO_CHECK(malloc_size > new_capacity); - auto* new_vec = static_cast(malloc(malloc_size)); + + ChangeCapacity(new_capacity); + } + + void ChangeCapacity(size_t new_capacity) { + // We should still have enough space to fit all the elements in the queue. + PERFETTO_CHECK(new_capacity >= size()); + + AlignedUniquePtr new_vec = AlignedAllocTyped(new_capacity); // Move all elements in the expanded array. size_t new_size = 0; @@ -273,12 +301,11 @@ // required to call the dtor for them. for (uint64_t i = begin_; i < end_; i++) Get(i)->~T(); - free(entries_); // It's fine to free(nullptr) (for the ctor call case). begin_ = 0; end_ = new_size; capacity_ = new_capacity; - entries_ = new_vec; + entries_ = std::move(new_vec); } inline T* Get(uint64_t pos) { @@ -290,7 +317,7 @@ // Underlying storage. It's raw malloc-ed rather than being a unique_ptr // to allow having uninitialized entries inside it. - T* entries_ = nullptr; + AlignedUniquePtr entries_; size_t capacity_ = 0; // Number of allocated slots (NOT bytes) in |entries_|. // The |begin_| and |end_| indexes are monotonic and never wrap. Modular arith