Serenity Operating System
at master 374 lines 14 kB view raw
1/* 2 * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#pragma once 8 9#include <AK/Array.h> 10#include <AK/BuiltinWrappers.h> 11#include <AK/Optional.h> 12#include <AK/StdLibExtras.h> 13#include <AK/Types.h> 14 15namespace AK { 16 17static constexpr Array bitmask_first_byte = { 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80 }; 18static constexpr Array bitmask_last_byte = { 0x00, 0x1, 0x3, 0x7, 0xF, 0x1F, 0x3F, 0x7F }; 19 20class BitmapView { 21public: 22 BitmapView() = default; 23 24 BitmapView(u8* data, size_t size) 25 : m_data(data) 26 , m_size(size) 27 { 28 } 29 30 [[nodiscard]] size_t size() const { return m_size; } 31 [[nodiscard]] size_t size_in_bytes() const { return ceil_div(m_size, static_cast<size_t>(8)); } 32 [[nodiscard]] bool get(size_t index) const 33 { 34 VERIFY(index < m_size); 35 return 0 != (m_data[index / 8] & (1u << (index % 8))); 36 } 37 38 [[nodiscard]] size_t count_slow(bool value) const 39 { 40 return count_in_range(0, m_size, value); 41 } 42 43 [[nodiscard]] size_t count_in_range(size_t start, size_t len, bool value) const 44 { 45 VERIFY(start < m_size); 46 VERIFY(start + len <= m_size); 47 if (len == 0) 48 return 0; 49 50 size_t count; 51 u8 const* first = &m_data[start / 8]; 52 u8 const* last = &m_data[(start + len) / 8]; 53 u8 byte = *first; 54 byte &= bitmask_first_byte[start % 8]; 55 if (first == last) { 56 byte &= bitmask_last_byte[(start + len) % 8]; 57 count = popcount(byte); 58 } else { 59 count = popcount(byte); 60 // Don't access *last if it's out of bounds 61 if (last < &m_data[size_in_bytes()]) { 62 byte = *last; 63 byte &= bitmask_last_byte[(start + len) % 8]; 64 count += popcount(byte); 65 } 66 if (++first < last) { 67 size_t const* ptr_large = reinterpret_cast<size_t const*>((reinterpret_cast<FlatPtr>(first) + sizeof(size_t) - 1) & ~(sizeof(size_t) - 1)); 68 if (reinterpret_cast<u8 const*>(ptr_large) > last) 69 ptr_large = reinterpret_cast<size_t const*>(last); 70 while (first < reinterpret_cast<u8 const*>(ptr_large)) { 71 count += popcount(*first); 72 first++; 73 } 74 size_t const* last_large = reinterpret_cast<size_t const*>(reinterpret_cast<FlatPtr>(last) & ~(sizeof(size_t) - 1)); 75 while (ptr_large < last_large) { 76 count += popcount(*ptr_large); 77 ptr_large++; 78 } 79 for (first = reinterpret_cast<u8 const*>(ptr_large); first < last; first++) 80 count += popcount(*first); 81 } 82 } 83 84 if (!value) 85 count = len - count; 86 return count; 87 } 88 89 [[nodiscard]] bool is_null() const { return m_data == nullptr; } 90 91 [[nodiscard]] u8 const* data() const { return m_data; } 92 93 template<bool VALUE> 94 Optional<size_t> find_one_anywhere(size_t hint = 0) const 95 { 96 VERIFY(hint < m_size); 97 u8 const* end = &m_data[m_size / 8]; 98 99 for (;;) { 100 // We will use hint as what it is: a hint. Because we try to 101 // scan over entire 32 bit words, we may start searching before 102 // the hint! 103 size_t const* ptr_large = reinterpret_cast<size_t const*>(reinterpret_cast<FlatPtr>(&m_data[hint / 8]) & ~(sizeof(size_t) - 1)); 104 if (reinterpret_cast<u8 const*>(ptr_large) < &m_data[0]) { 105 ptr_large++; 106 107 // m_data isn't aligned, check first bytes 108 size_t start_ptr_large = reinterpret_cast<u8 const*>(ptr_large) - &m_data[0]; 109 size_t i = 0; 110 u8 byte = VALUE ? 0x00 : 0xff; 111 while (i < start_ptr_large && m_data[i] == byte) 112 i++; 113 if (i < start_ptr_large) { 114 byte = m_data[i]; 115 if constexpr (!VALUE) 116 byte = ~byte; 117 VERIFY(byte != 0); 118 return i * 8 + bit_scan_forward(byte) - 1; 119 } 120 } 121 122 size_t val_large = VALUE ? 0x0 : NumericLimits<size_t>::max(); 123 size_t const* end_large = reinterpret_cast<size_t const*>(reinterpret_cast<FlatPtr>(end) & ~(sizeof(size_t) - 1)); 124 while (ptr_large < end_large && *ptr_large == val_large) 125 ptr_large++; 126 127 if (ptr_large == end_large) { 128 // We didn't find anything, check the remaining few bytes (if any) 129 u8 byte = VALUE ? 0x00 : 0xff; 130 size_t i = reinterpret_cast<u8 const*>(ptr_large) - &m_data[0]; 131 size_t byte_count = m_size / 8; 132 VERIFY(i <= byte_count); 133 while (i < byte_count && m_data[i] == byte) 134 i++; 135 if (i == byte_count) { 136 if (hint <= 8) 137 return {}; // We already checked from the beginning 138 139 // Try scanning before the hint 140 end = reinterpret_cast<u8 const*>(reinterpret_cast<FlatPtr>(&m_data[hint / 8]) & ~(sizeof(size_t) - 1)); 141 hint = 0; 142 continue; 143 } 144 byte = m_data[i]; 145 if constexpr (!VALUE) 146 byte = ~byte; 147 VERIFY(byte != 0); 148 return i * 8 + bit_scan_forward(byte) - 1; 149 } 150 151 // NOTE: We don't really care about byte ordering. We found *one* 152 // free bit, just calculate the position and return it 153 val_large = *ptr_large; 154 if constexpr (!VALUE) 155 val_large = ~val_large; 156 VERIFY(val_large != 0); 157 return (reinterpret_cast<u8 const*>(ptr_large) - &m_data[0]) * 8 + bit_scan_forward(val_large) - 1; 158 } 159 } 160 161 Optional<size_t> find_one_anywhere_set(size_t hint = 0) const 162 { 163 return find_one_anywhere<true>(hint); 164 } 165 166 Optional<size_t> find_one_anywhere_unset(size_t hint = 0) const 167 { 168 return find_one_anywhere<false>(hint); 169 } 170 171 template<bool VALUE> 172 Optional<size_t> find_first() const 173 { 174 size_t byte_count = m_size / 8; 175 size_t i = 0; 176 177 u8 byte = VALUE ? 0x00 : 0xff; 178 while (i < byte_count && m_data[i] == byte) 179 i++; 180 if (i == byte_count) 181 return {}; 182 183 byte = m_data[i]; 184 if constexpr (!VALUE) 185 byte = ~byte; 186 VERIFY(byte != 0); 187 return i * 8 + bit_scan_forward(byte) - 1; 188 } 189 190 Optional<size_t> find_first_set() const { return find_first<true>(); } 191 Optional<size_t> find_first_unset() const { return find_first<false>(); } 192 193 // The function will return the next range of unset bits starting from the 194 // @from value. 195 // @from: the position from which the search starts. The var will be 196 // changed and new value is the offset of the found block. 197 // @min_length: minimum size of the range which will be returned. 198 // @max_length: maximum size of the range which will be returned. 199 // This is used to increase performance, since the range of 200 // unset bits can be long, and we don't need the while range, 201 // so we can stop when we've reached @max_length. 202 inline Optional<size_t> find_next_range_of_unset_bits(size_t& from, size_t min_length = 1, size_t max_length = max_size) const 203 { 204 if (min_length > max_length) { 205 return {}; 206 } 207 208 size_t bit_size = 8 * sizeof(size_t); 209 210 size_t* bitmap = reinterpret_cast<size_t*>(m_data); 211 212 // Calculating the start offset. 213 size_t start_bucket_index = from / bit_size; 214 size_t start_bucket_bit = from % bit_size; 215 216 size_t* start_of_free_chunks = &from; 217 size_t free_chunks = 0; 218 219 for (size_t bucket_index = start_bucket_index; bucket_index < m_size / bit_size; ++bucket_index) { 220 if (bitmap[bucket_index] == NumericLimits<size_t>::max()) { 221 // Skip over completely full bucket of size bit_size. 222 if (free_chunks >= min_length) { 223 return min(free_chunks, max_length); 224 } 225 free_chunks = 0; 226 start_bucket_bit = 0; 227 continue; 228 } 229 if (bitmap[bucket_index] == 0x0) { 230 // Skip over completely empty bucket of size bit_size. 231 if (free_chunks == 0) { 232 *start_of_free_chunks = bucket_index * bit_size; 233 } 234 free_chunks += bit_size; 235 if (free_chunks >= max_length) { 236 return max_length; 237 } 238 start_bucket_bit = 0; 239 continue; 240 } 241 242 size_t bucket = bitmap[bucket_index]; 243 u8 viewed_bits = start_bucket_bit; 244 u32 trailing_zeroes = 0; 245 246 bucket >>= viewed_bits; 247 start_bucket_bit = 0; 248 249 while (viewed_bits < bit_size) { 250 if (bucket == 0) { 251 if (free_chunks == 0) { 252 *start_of_free_chunks = bucket_index * bit_size + viewed_bits; 253 } 254 free_chunks += bit_size - viewed_bits; 255 viewed_bits = bit_size; 256 } else { 257 trailing_zeroes = count_trailing_zeroes(bucket); 258 bucket >>= trailing_zeroes; 259 260 if (free_chunks == 0) { 261 *start_of_free_chunks = bucket_index * bit_size + viewed_bits; 262 } 263 free_chunks += trailing_zeroes; 264 viewed_bits += trailing_zeroes; 265 266 if (free_chunks >= min_length) { 267 return min(free_chunks, max_length); 268 } 269 270 // Deleting trailing ones. 271 u32 trailing_ones = count_trailing_zeroes(~bucket); 272 bucket >>= trailing_ones; 273 viewed_bits += trailing_ones; 274 free_chunks = 0; 275 } 276 } 277 } 278 279 if (free_chunks < min_length) { 280 size_t first_trailing_bit = (m_size / bit_size) * bit_size; 281 size_t trailing_bits = size() % bit_size; 282 for (size_t i = 0; i < trailing_bits; ++i) { 283 if (!get(first_trailing_bit + i)) { 284 if (free_chunks == 0) 285 *start_of_free_chunks = first_trailing_bit + i; 286 if (++free_chunks >= min_length) 287 return min(free_chunks, max_length); 288 } else { 289 free_chunks = 0; 290 } 291 } 292 return {}; 293 } 294 295 return min(free_chunks, max_length); 296 } 297 298 Optional<size_t> find_longest_range_of_unset_bits(size_t max_length, size_t& found_range_size) const 299 { 300 size_t start = 0; 301 size_t max_region_start = 0; 302 size_t max_region_size = 0; 303 304 while (true) { 305 // Look for the next block which is bigger than currunt. 306 auto length_of_found_range = find_next_range_of_unset_bits(start, max_region_size + 1, max_length); 307 if (length_of_found_range.has_value()) { 308 max_region_start = start; 309 max_region_size = length_of_found_range.value(); 310 start += max_region_size; 311 } else { 312 // No ranges which are bigger than current were found. 313 break; 314 } 315 } 316 317 found_range_size = max_region_size; 318 if (max_region_size != 0) { 319 return max_region_start; 320 } 321 return {}; 322 } 323 324 Optional<size_t> find_first_fit(size_t minimum_length) const 325 { 326 size_t start = 0; 327 auto length_of_found_range = find_next_range_of_unset_bits(start, minimum_length, minimum_length); 328 if (length_of_found_range.has_value()) { 329 return start; 330 } 331 return {}; 332 } 333 334 Optional<size_t> find_best_fit(size_t minimum_length) const 335 { 336 size_t start = 0; 337 size_t best_region_start = 0; 338 size_t best_region_size = max_size; 339 bool found = false; 340 341 while (true) { 342 // Look for the next block which is bigger than requested length. 343 auto length_of_found_range = find_next_range_of_unset_bits(start, minimum_length, best_region_size); 344 if (length_of_found_range.has_value()) { 345 if (best_region_size > length_of_found_range.value() || !found) { 346 best_region_start = start; 347 best_region_size = length_of_found_range.value(); 348 found = true; 349 } 350 start += length_of_found_range.value(); 351 } else { 352 // There are no ranges which can fit requested length. 353 break; 354 } 355 } 356 357 if (found) { 358 return best_region_start; 359 } 360 return {}; 361 } 362 363 static constexpr size_t max_size = 0xffffffff; 364 365protected: 366 u8* m_data { nullptr }; 367 size_t m_size { 0 }; 368}; 369 370} 371 372#if USING_AK_GLOBALLY 373using AK::BitmapView; 374#endif