2022-12-04 14:14:07 +00:00
|
|
|
#include <luna/Bitmap.h>
|
2022-12-16 19:40:04 +00:00
|
|
|
#include <luna/CString.h>
|
2022-12-04 14:14:07 +00:00
|
|
|
#include <luna/Check.h>
|
2023-01-21 22:16:50 +00:00
|
|
|
#include <luna/Heap.h>
|
2022-12-04 14:14:07 +00:00
|
|
|
|
|
|
|
Bitmap::Bitmap()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2022-12-07 10:47:46 +00:00
|
|
|
Bitmap::Bitmap(void* location, usize size_in_bytes) : m_location((u8*)location), m_size_in_bytes(size_in_bytes)
|
2022-12-04 14:14:07 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void Bitmap::initialize(void* location, usize size_in_bytes)
|
|
|
|
{
|
2022-12-07 10:47:46 +00:00
|
|
|
m_location = (u8*)location;
|
2022-12-04 14:14:07 +00:00
|
|
|
m_size_in_bytes = size_in_bytes;
|
|
|
|
}
|
|
|
|
|
2023-01-21 22:16:50 +00:00
|
|
|
Result<void> Bitmap::allocate(usize size_in_bytes)
|
|
|
|
{
|
|
|
|
initialize(TRY(malloc_impl(size_in_bytes)), size_in_bytes);
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
Result<void*> Bitmap::resize(usize new_size_in_bytes)
|
|
|
|
{
|
|
|
|
m_location = (u8*)TRY(realloc_impl(m_location, new_size_in_bytes));
|
|
|
|
m_size_in_bytes = new_size_in_bytes;
|
|
|
|
return (void*)m_location;
|
|
|
|
}
|
|
|
|
|
|
|
|
Result<void> Bitmap::deallocate()
|
|
|
|
{
|
|
|
|
return free_impl(m_location);
|
|
|
|
}
|
|
|
|
|
2022-12-04 14:14:07 +00:00
|
|
|
void* Bitmap::move(void* new_location, usize new_location_size_in_bytes)
|
|
|
|
{
|
|
|
|
if (new_location_size_in_bytes > m_size_in_bytes) memcpy(new_location, m_location, m_size_in_bytes);
|
|
|
|
else
|
|
|
|
memcpy(new_location, m_location, new_location_size_in_bytes);
|
|
|
|
|
2023-01-21 22:04:21 +00:00
|
|
|
void* const old_location = (void*)m_location;
|
2022-12-04 14:14:07 +00:00
|
|
|
|
2022-12-07 10:47:46 +00:00
|
|
|
m_location = (u8*)new_location;
|
2022-12-04 14:14:07 +00:00
|
|
|
m_size_in_bytes = new_location_size_in_bytes;
|
|
|
|
|
|
|
|
return old_location;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Bitmap::set(usize index, bool value)
|
|
|
|
{
|
|
|
|
expect(index < size(), "Bitmap access out of range");
|
2023-01-21 22:04:21 +00:00
|
|
|
const u64 byte_index = index / 8;
|
|
|
|
const u8 bit_mask = (u8)(0b10000000 >> (index % 8));
|
2022-12-04 14:14:07 +00:00
|
|
|
m_location[byte_index] &= (u8)(~bit_mask);
|
|
|
|
if (value) { m_location[byte_index] |= bit_mask; }
|
|
|
|
}
|
|
|
|
|
2022-12-05 11:50:30 +00:00
|
|
|
bool Bitmap::get(usize index) const
|
2022-12-04 14:14:07 +00:00
|
|
|
{
|
|
|
|
expect(index < size(), "Bitmap access out of range");
|
2023-01-21 22:04:21 +00:00
|
|
|
const usize byte_index = index / 8;
|
|
|
|
const u8 bit_mask = (u8)(0b10000000 >> (index % 8));
|
2022-12-04 14:14:07 +00:00
|
|
|
return (m_location[byte_index] & bit_mask) > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Bitmap::clear(bool value)
|
|
|
|
{
|
2022-12-05 11:53:16 +00:00
|
|
|
memset(m_location, value_byte(value), m_size_in_bytes);
|
2022-12-04 14:14:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Bitmap::clear_region(usize start, usize bits, bool value)
|
|
|
|
{
|
|
|
|
expect((start + bits) <= size(), "Bitmap clear out of range");
|
|
|
|
|
2022-12-07 13:32:41 +00:00
|
|
|
if (!bits) return;
|
|
|
|
|
2022-12-04 14:14:07 +00:00
|
|
|
// Set individual bits while not on a byte boundary.
|
2022-12-07 13:46:11 +00:00
|
|
|
while ((start % 8) && bits)
|
2022-12-04 14:14:07 +00:00
|
|
|
{
|
|
|
|
set(start, value);
|
|
|
|
start++;
|
2022-12-07 13:46:11 +00:00
|
|
|
bits--;
|
2022-12-04 14:14:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Clear out the rest in bytes.
|
2023-01-21 22:04:21 +00:00
|
|
|
const usize bytes = bits / 8;
|
2022-12-04 14:14:07 +00:00
|
|
|
|
2022-12-05 11:53:16 +00:00
|
|
|
memset(&m_location[start / 8], value_byte(value), bytes);
|
2022-12-04 14:14:07 +00:00
|
|
|
start += bytes * 8;
|
|
|
|
bits -= bytes * 8;
|
|
|
|
|
|
|
|
// Set the remaining individual bits.
|
|
|
|
while (bits--)
|
|
|
|
{
|
|
|
|
set(start, value);
|
|
|
|
start++;
|
|
|
|
}
|
2023-01-02 12:07:29 +00:00
|
|
|
}
|
2023-01-09 16:59:52 +00:00
|
|
|
|
|
|
|
Option<usize> Bitmap::find(bool value, usize begin) const
|
|
|
|
{
|
2023-01-10 18:31:41 +00:00
|
|
|
const usize size = this->size();
|
2023-01-09 16:59:52 +00:00
|
|
|
|
|
|
|
expect(begin < size, "Start index out of range");
|
|
|
|
|
|
|
|
while (begin % 8)
|
|
|
|
{
|
|
|
|
if (get(begin) == value) return begin;
|
|
|
|
begin++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (begin == size) return {};
|
|
|
|
|
|
|
|
usize i = begin / 8;
|
2023-01-10 18:31:41 +00:00
|
|
|
const u8 byte_that_does_not_contain_value = value_byte(!value);
|
2023-01-09 16:59:52 +00:00
|
|
|
while (i < m_size_in_bytes)
|
|
|
|
{
|
|
|
|
if (m_location[i] == byte_that_does_not_contain_value)
|
|
|
|
{
|
|
|
|
i++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
usize index = i * 8;
|
|
|
|
for (usize j = 0; j < 8; j++, index++)
|
|
|
|
{
|
|
|
|
if (get(index) == value) return index;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Once we've located a byte that contains the value, we should succeed in finding it.
|
|
|
|
unreachable();
|
|
|
|
}
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
2023-01-09 17:08:50 +00:00
|
|
|
|
|
|
|
Option<usize> Bitmap::find_and_toggle(bool value, usize begin)
|
|
|
|
{
|
2023-01-10 18:31:41 +00:00
|
|
|
const usize index = TRY(find(value, begin));
|
2023-01-09 17:08:50 +00:00
|
|
|
set(index, !value);
|
|
|
|
return index;
|
|
|
|
}
|
2023-01-13 17:55:31 +00:00
|
|
|
|
|
|
|
Option<usize> Bitmap::find_region(bool value, usize count, usize begin) const
|
|
|
|
{
|
|
|
|
// FIXME: Optimize this using bit and byte manipulation.
|
|
|
|
u64 region_bits_found = 0;
|
|
|
|
u64 region_start = 0;
|
|
|
|
|
|
|
|
for (u64 index = begin; index < m_size_in_bytes * 8; index++)
|
|
|
|
{
|
|
|
|
if (get(index) != value)
|
|
|
|
{
|
|
|
|
region_bits_found = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (region_bits_found == 0)
|
|
|
|
{
|
|
|
|
region_start = index;
|
|
|
|
region_bits_found++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
region_bits_found++;
|
|
|
|
|
|
|
|
if (region_bits_found == count) return region_start;
|
|
|
|
}
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
Option<usize> Bitmap::find_and_toggle_region(bool value, usize count, usize begin)
|
|
|
|
{
|
2023-01-21 22:04:21 +00:00
|
|
|
const usize index = TRY(find_region(value, count, begin));
|
2023-01-13 17:55:31 +00:00
|
|
|
clear_region(index, count, !value);
|
|
|
|
return index;
|
|
|
|
}
|
2023-01-16 20:16:38 +00:00
|
|
|
|
2023-01-22 13:25:51 +00:00
|
|
|
bool Bitmap::match_region_impl(usize start, usize bits, bool value)
|
2023-01-16 20:16:38 +00:00
|
|
|
{
|
|
|
|
if (!bits) return true;
|
|
|
|
|
|
|
|
// Match individual bits while not on a byte boundary.
|
|
|
|
while ((start % 8) && bits)
|
|
|
|
{
|
|
|
|
if (get(start) != value) return false;
|
|
|
|
start++;
|
|
|
|
bits--;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Match the rest in bytes.
|
2023-01-21 22:04:21 +00:00
|
|
|
const usize bytes = bits / 8;
|
2023-01-16 20:16:38 +00:00
|
|
|
const u8 byte_that_contains_only_value = value_byte(value);
|
|
|
|
|
|
|
|
for (usize i = start; i < start + bytes; i += 8)
|
|
|
|
{
|
|
|
|
if (m_location[i / 8] != byte_that_contains_only_value) return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
start += bytes * 8;
|
|
|
|
bits -= bytes * 8;
|
|
|
|
|
|
|
|
// Match the remaining individual bits.
|
|
|
|
while (bits--)
|
|
|
|
{
|
|
|
|
if (get(start) != value) return false;
|
|
|
|
start++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2023-01-22 13:25:51 +00:00
|
|
|
|
|
|
|
bool Bitmap::match_region(usize start, usize bits, bool value)
|
|
|
|
{
|
|
|
|
expect((start + bits) <= size(), "Bitmap match out of range");
|
|
|
|
|
|
|
|
return match_region_impl(start, bits, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
Result<bool> Bitmap::try_match_region(usize start, usize bits, bool value)
|
|
|
|
{
|
|
|
|
if ((start + bits) > size()) return err(EINVAL);
|
|
|
|
|
|
|
|
return match_region_impl(start, bits, value);
|
|
|
|
}
|