/* * Copyright (c) 2021-2024, Ali Mohammad Pur * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include namespace AK { template class COWVector { struct Detail : RefCounted { Vector m_members; }; public: COWVector() : m_detail(make_ref_counted()) { } COWVector(std::initializer_list entries) : m_detail(make_ref_counted()) { for (auto& entry : entries) m_detail->m_members.append(entry); } COWVector(COWVector const&) = default; COWVector(COWVector&&) = default; COWVector& operator=(COWVector const&) = default; COWVector& operator=(COWVector&&) = default; Vector release() && { if (m_detail->ref_count() == 1) return exchange(m_detail->m_members, Vector()); return m_detail->m_members; } void append(T const& value) { return append(T { value }); } void append(T&& value) { copy(); m_detail->m_members.append(move(value)); } void extend(Vector&& values) { copy(); m_detail->m_members.extend(move(values)); } void extend(Vector const& values) { copy(); m_detail->m_members.extend(values); } void extend(COWVector const& values) { copy(); m_detail->m_members.extend(values.m_detail->m_members); } void resize(size_t size) { copy(); m_detail->m_members.resize(size); } void ensure_capacity(size_t capacity) { if (m_detail->m_members.capacity() >= capacity) return; copy(); m_detail->m_members.ensure_capacity(capacity); } void prepend(T value) { copy(); m_detail->m_members.prepend(move(value)); } template void empend(Args&&... args) { copy(); m_detail->m_members.empend(forward(args)...); } void clear() { if (m_detail->ref_count() > 1) m_detail = make_ref_counted(); else m_detail->m_members.clear(); } T& mutable_at(size_t index) { // We're handing out a mutable reference, so make sure we own the data exclusively. copy(); return m_detail->m_members.at(index); } T const& at(size_t index) const { return m_detail->m_members.at(index); } T const& operator[](size_t index) const { return m_detail->m_members[index]; } size_t capacity() const { return m_detail->m_members.capacity(); } size_t size() const { return m_detail->m_members.size(); } bool is_empty() const { return m_detail->m_members.is_empty(); } T const& first() const { return m_detail->m_members.first(); } T const& last() const { return m_detail->m_members.last(); } private: void copy() { if (m_detail->ref_count() <= 1) return; auto new_detail = make_ref_counted(); new_detail->m_members = m_detail->m_members; m_detail = new_detail; } NonnullRefPtr m_detail; }; } #if USING_AK_GLOBALLY using AK::COWVector; #endif