/* * Copyright (c) 2018-2022, Andreas Kling * Copyright (c) 2022, the SerenityOS developers. * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include namespace AK { template class FixedArray { public: FixedArray() = default; static ErrorOr> try_create(size_t size) { if (size == 0) return FixedArray(); T* elements = static_cast(kmalloc_array(size, sizeof(T))); if (!elements) return Error::from_errno(ENOMEM); for (size_t i = 0; i < size; ++i) new (&elements[i]) T(); return FixedArray(size, elements); } static FixedArray must_create_but_fixme_should_propagate_errors(size_t size) { return MUST(try_create(size)); } ErrorOr> try_clone() const { if (m_size == 0) return FixedArray(); T* elements = static_cast(kmalloc_array(m_size, sizeof(T))); if (!elements) return Error::from_errno(ENOMEM); for (size_t i = 0; i < m_size; ++i) new (&elements[i]) T(m_elements[i]); return FixedArray(m_size, elements); } FixedArray must_clone_but_fixme_should_propagate_errors() const { return MUST(try_clone()); } // NOTE: Nobody can ever use these functions, since it would be impossible to make them OOM-safe due to their signatures. We just explicitly delete them. FixedArray(FixedArray const&) = delete; FixedArray& operator=(FixedArray const&) = delete; FixedArray(FixedArray&& other) : m_size(other.m_size) , m_elements(other.m_elements) { other.m_size = 0; other.m_elements = nullptr; } // NOTE: Nobody uses this function, so we just explicitly delete it. FixedArray& operator=(FixedArray&&) = delete; ~FixedArray() { clear(); } void clear() { if (!m_elements) return; for (size_t i = 0; i < m_size; ++i) m_elements[i].~T(); kfree_sized(m_elements, sizeof(T) * m_size); m_size = 0; m_elements = nullptr; } size_t size() const { return m_size; } T* data() { return m_elements; } T const* data() const { return m_elements; } T& operator[](size_t index) { VERIFY(index < m_size); return m_elements[index]; } T const& operator[](size_t index) const { VERIFY(index < m_size); return m_elements[index]; } bool contains_slow(T const& value) const { for (size_t i = 0; i < m_size; ++i) { if (m_elements[i] == value) return true; } return false; } void swap(FixedArray& other) { ::swap(m_size, other.m_size); ::swap(m_elements, other.m_elements); } using ConstIterator = SimpleIterator; using Iterator = SimpleIterator; ConstIterator begin() const { return ConstIterator::begin(*this); } Iterator begin() { return Iterator::begin(*this); } ConstIterator end() const { return ConstIterator::end(*this); } Iterator end() { return Iterator::end(*this); } Span span() const { return { data(), size() }; } Span span() { return { data(), size() }; } private: FixedArray(size_t size, T* elements) : m_size(size) , m_elements(elements) { } size_t m_size { 0 }; T* m_elements { nullptr }; }; } using AK::FixedArray;