/** * @file Bitmap.h * @author apio (cloudapio.eu) * @brief An interface to an array of bits. * * @copyright Copyright (c) 2022-2023, the Luna authors. * */ #pragma once #include #include /** * @brief A class providing an interface to an array of bits. */ class Bitmap { public: /** * @brief Construct a new empty Bitmap object. * * This object is invalid until initialize() is called on it. */ Bitmap(); /** * @brief Construct a new Bitmap object. * * @param location The memory to use. This memory is not managed by Bitmap; if it is dynamically allocated, you must * free it after it is no longer used by the bitmap. * @param size_in_bytes The size (in bytes, the number of bits available will be 8 times more) of the memory used. */ Bitmap(void* location, usize size_in_bytes); /** * @brief Initialize a Bitmap object. * * If the object was previously initialized, you should call move() instead. * * @param location The memory to use. This memory is not managed by Bitmap; if it is dynamically allocated, you must * free it after it is no longer used by the bitmap. * @param size_in_bytes The size (in bytes, the number of bits available will be 8 times more) of the memory used. */ void initialize(void* location, usize size_in_bytes); /** * @brief Initialize a previously initialized Bitmap object and return the memory location it was previously using. * * If the object was not previously initialized, you should call initialize() instead. * * @param new_location The memory to use. This memory is not managed by Bitmap; if it is dynamically allocated, you * must free it after it is no longer used by the bitmap. * @param new_location_size_in_bytes The size (in bytes, the number of bits available will be 8 times more) of the * memory used. * @return void* The old memory location previously used by the bitmap. */ void* move(void* new_location, usize new_location_size_in_bytes); /** * @brief Change the value of the bit at a specific index. * * @param index The index of the bit to change. * @param value The value to set. */ void set(usize index, bool value); /** * @brief Read the value of the bit at a specific index. * * @param index The index of the bit to read. * @return bool The value of the specified bit. */ bool get(usize index) const; /** * @brief Return the size in bits of the bitmap. * * @return usize The size in bits. */ usize size() const { return m_size_in_bytes * 8; } /** * @brief Return the size in bytes of the bitmap. * * @return usize The size in bytes. */ usize size_in_bytes() const { return m_size_in_bytes; } /** * @brief Return the memory location used by the bitmap. * * @return void* The memory location used. If it is NULL, the bitmap was not initialized. */ void* location() const { return (void*)m_location; } /** * @brief Check whether the bitmap has been initialized. * * @return true The bitmap was initialized by a constructor or initialize(). * @return false The bitmap was not initialized and you should not call other methods on it until initialize() is * called. */ bool initialized() const { return m_location; } /** * @brief Find the first bit with a specific value. * * @param value The value to look for. * @param begin If different from 0, the bit index to start looking at. * @return Option If a matching bit was found, the index of said bit, otherwise an empty Option. */ Option find(bool value, usize begin = 0) const; /** * @brief Find the first bit with a specific value and toggle it. * * @param value The value to look for. * @param begin If different from 0, the bit index to start looking at. * @return Option If a matching bit was found, the index of said bit, otherwise an empty Option. */ Option find_and_toggle(bool value, usize begin = 0); /** * @brief Find the first region of bits all with a specific value. * * @param value The value to look for. * @param count The number of consecutive bits that should all match the value. * @param begin If different from 0, the bit index to start looking at. * @return Option If a matching region was found, the index of the first bit in said region, otherwise an * empty Option. */ Option find_region(bool value, usize count, usize begin = 0) const; /** * @brief Find the first region of bits all with a specific value, and toggle them all. * * @param value The value to look for. * @param count The number of consecutive bits that should all match the value. * @param begin If different from 0, the bit index to start looking at. * @return Option If a matching region was found, the index of the first bit in said region, otherwise an * empty Option. */ Option find_and_toggle_region(bool value, usize count, usize begin = 0); /** * @brief Check whether a region of bits all match a value. * * @param start The bit index of the first bit in the region. * @param bits The number of bits in the region. * @param value The value to check against. * @return bool Whether the region matches. */ bool match_region(usize start, usize bits, bool value); /** * @brief Check whether a region of bits all match a value, returning an error if the region is outside of the * Bitmap's bounds (instead of crashing). * * @param start The bit index of the first bit in the region. * @param bits The number of bits in the region. * @param value The value to check against. * @return Result An error if the region is out of bounds, or whether the region matches. */ Result try_match_region(usize start, usize bits, bool value); /** * @brief Set the entire bitmap to a value. * * @param value The value to use. */ void clear(bool value); /** * @brief Set a region of bits to a value. * * @param start The bit index of the first bit in the region. * @param bits The number of bits in the region. * @param value The value to set. */ void clear_region(usize start, usize bits, bool value); private: u8 value_byte(bool b) const { return b ? 0xff : 0; } bool match_region_impl(usize start, usize bits, bool value); u8* m_location = nullptr; usize m_size_in_bytes = 0; };