Serenity Operating System
at master 186 lines 5.1 kB view raw
1/* 2 * Copyright (c) 2018-2022, Andreas Kling <kling@serenityos.org> 3 * Copyright (c) 2022, the SerenityOS developers. 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#pragma once 9 10#include <AK/Error.h> 11#include <AK/Iterator.h> 12#include <AK/Span.h> 13#include <AK/kmalloc.h> 14#include <initializer_list> 15 16namespace AK { 17 18// FixedArray is an Array with a size only known at run-time. 19// It guarantees to only allocate when being constructed, and to only deallocate when being destructed. 20template<typename T> 21class FixedArray { 22public: 23 FixedArray() = default; 24 25 static ErrorOr<FixedArray<T>> create(std::initializer_list<T> initializer) 26 { 27 auto array = TRY(create(initializer.size())); 28 auto it = initializer.begin(); 29 for (size_t i = 0; i < array.size(); ++i) { 30 array[i] = move(*it); 31 ++it; 32 } 33 return array; 34 } 35 36 static ErrorOr<FixedArray<T>> create(size_t size) 37 { 38 if (size == 0) 39 return FixedArray<T>(); 40 auto* new_storage = static_cast<Storage*>(kmalloc(storage_allocation_size(size))); 41 if (!new_storage) 42 return Error::from_errno(ENOMEM); 43 new_storage->size = size; 44 for (size_t i = 0; i < size; ++i) 45 new (&new_storage->elements[i]) T(); 46 return FixedArray<T>(new_storage); 47 } 48 49 static FixedArray<T> must_create_but_fixme_should_propagate_errors(size_t size) 50 { 51 return MUST(create(size)); 52 } 53 54 template<size_t N> 55 static ErrorOr<FixedArray<T>> create(T (&&array)[N]) 56 { 57 return create(Span(array, N)); 58 } 59 60 template<typename U> 61 static ErrorOr<FixedArray<T>> create(Span<U> span) 62 { 63 if (span.size() == 0) 64 return FixedArray<T>(); 65 auto* new_storage = static_cast<Storage*>(kmalloc(storage_allocation_size(span.size()))); 66 if (!new_storage) 67 return Error::from_errno(ENOMEM); 68 new_storage->size = span.size(); 69 for (size_t i = 0; i < span.size(); ++i) 70 new (&new_storage->elements[i]) T(span[i]); 71 return FixedArray<T>(new_storage); 72 } 73 74 ErrorOr<FixedArray<T>> clone() const 75 { 76 return create(span()); 77 } 78 79 static size_t storage_allocation_size(size_t size) 80 { 81 return sizeof(Storage) + size * sizeof(T); 82 } 83 84 // 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. 85 FixedArray(FixedArray<T> const&) = delete; 86 FixedArray<T>& operator=(FixedArray<T> const&) = delete; 87 88 FixedArray(FixedArray<T>&& other) 89 : m_storage(exchange(other.m_storage, nullptr)) 90 { 91 } 92 // This function would violate the contract, as it would need to deallocate this FixedArray. As it also has no use case, we delete it. 93 FixedArray<T>& operator=(FixedArray<T>&&) = delete; 94 95 ~FixedArray() 96 { 97 if (!m_storage) 98 return; 99 for (size_t i = 0; i < m_storage->size; ++i) 100 m_storage->elements[i].~T(); 101 kfree_sized(m_storage, storage_allocation_size(m_storage->size)); 102 m_storage = nullptr; 103 } 104 105 size_t size() const { return m_storage ? m_storage->size : 0; } 106 bool is_empty() const { return size() == 0; } 107 T* data() { return m_storage ? m_storage->elements : nullptr; } 108 T const* data() const { return m_storage ? m_storage->elements : nullptr; } 109 110 T& at(size_t index) 111 { 112 VERIFY(index < m_storage->size); 113 return m_storage->elements[index]; 114 } 115 116 T const& at(size_t index) const 117 { 118 VERIFY(index < m_storage->size); 119 return m_storage->elements[index]; 120 } 121 122 T& operator[](size_t index) 123 { 124 return at(index); 125 } 126 127 T const& operator[](size_t index) const 128 { 129 return at(index); 130 } 131 132 bool contains_slow(T const& value) const 133 { 134 if (!m_storage) 135 return false; 136 for (size_t i = 0; i < m_storage->size; ++i) { 137 if (m_storage->elements[i] == value) 138 return true; 139 } 140 return false; 141 } 142 143 void swap(FixedArray<T>& other) 144 { 145 ::swap(m_storage, other.m_storage); 146 } 147 148 void fill_with(T const& value) 149 { 150 if (!m_storage) 151 return; 152 for (size_t i = 0; i < m_storage->size; ++i) 153 m_storage->elements[i] = value; 154 } 155 156 using Iterator = SimpleIterator<FixedArray, T>; 157 using ConstIterator = SimpleIterator<FixedArray const, T const>; 158 159 Iterator begin() { return Iterator::begin(*this); } 160 ConstIterator begin() const { return ConstIterator::begin(*this); } 161 162 Iterator end() { return Iterator::end(*this); } 163 ConstIterator end() const { return ConstIterator::end(*this); } 164 165 Span<T> span() { return { data(), size() }; } 166 ReadonlySpan<T> span() const { return { data(), size() }; } 167 168private: 169 struct Storage { 170 size_t size { 0 }; 171 T elements[0]; 172 }; 173 174 FixedArray(Storage* storage) 175 : m_storage(storage) 176 { 177 } 178 179 Storage* m_storage { nullptr }; 180}; 181 182} 183 184#if USING_AK_GLOBALLY 185using AK::FixedArray; 186#endif