mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 21:22:46 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			168 lines
		
	
	
	
		
			3.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			168 lines
		
	
	
	
		
			3.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #pragma once
 | |
| 
 | |
| #include <AK/Assertions.h>
 | |
| #include <AK/Noncopyable.h>
 | |
| #include <AK/StdLibExtras.h>
 | |
| #include <AK/Types.h>
 | |
| #include <AK/kmalloc.h>
 | |
| 
 | |
| namespace AK {
 | |
| 
 | |
| class Bitmap {
 | |
|     AK_MAKE_NONCOPYABLE(Bitmap)
 | |
| public:
 | |
|     // NOTE: A wrapping Bitmap won't try to free the wrapped data.
 | |
|     static Bitmap wrap(u8* data, int size)
 | |
|     {
 | |
|         return Bitmap(data, size);
 | |
|     }
 | |
| 
 | |
|     static Bitmap create(int size, bool default_value = 0)
 | |
|     {
 | |
|         return Bitmap(size, default_value);
 | |
|     }
 | |
| 
 | |
|     static Bitmap create()
 | |
|     {
 | |
|         return Bitmap();
 | |
|     }
 | |
| 
 | |
|     Bitmap(Bitmap&& other)
 | |
|     {
 | |
|         m_owned = exchange(other.m_owned, false);
 | |
|         m_data = exchange(other.m_data, nullptr);
 | |
|         m_size = exchange(other.m_size, 0);
 | |
|     }
 | |
| 
 | |
|     Bitmap& operator=(Bitmap&& other)
 | |
|     {
 | |
|         if (this != &other) {
 | |
|             if (m_owned)
 | |
|                 kfree(m_data);
 | |
|             m_owned = exchange(other.m_owned, false);
 | |
|             m_data = exchange(other.m_data, nullptr);
 | |
|             m_size = exchange(other.m_size, 0);
 | |
|         }
 | |
|         return *this;
 | |
|     }
 | |
| 
 | |
|     ~Bitmap()
 | |
|     {
 | |
|         if (m_owned)
 | |
|             kfree(m_data);
 | |
|         m_data = nullptr;
 | |
|     }
 | |
| 
 | |
|     int size() const { return m_size; }
 | |
|     bool get(int index) const
 | |
|     {
 | |
|         ASSERT(index < m_size);
 | |
|         return 0 != (m_data[index / 8] & (1u << (index % 8)));
 | |
|     }
 | |
|     void set(int index, bool value) const
 | |
|     {
 | |
|         ASSERT(index < m_size);
 | |
|         if (value)
 | |
|             m_data[index / 8] |= static_cast<u8>((1u << (index % 8)));
 | |
|         else
 | |
|             m_data[index / 8] &= static_cast<u8>(~(1u << (index % 8)));
 | |
|     }
 | |
| 
 | |
|     u8* data() { return m_data; }
 | |
|     const u8* data() const { return m_data; }
 | |
| 
 | |
|     void grow(int size, bool default_value)
 | |
|     {
 | |
|         ASSERT(size > m_size);
 | |
| 
 | |
|         auto previous_size_bytes = size_in_bytes();
 | |
|         auto previous_size = m_size;
 | |
|         auto previous_data = m_data;
 | |
| 
 | |
|         m_size = size;
 | |
|         m_data = reinterpret_cast<u8*>(kmalloc(size_in_bytes()));
 | |
| 
 | |
|         fill(default_value);
 | |
| 
 | |
|         if (previous_data != nullptr) {
 | |
|             memcpy(m_data, previous_data, previous_size_bytes);
 | |
| 
 | |
|             if ((previous_size % 8) != 0) {
 | |
|                 if (default_value)
 | |
|                     m_data[previous_size_bytes - 1] |= (0xff >> (previous_size % 8));
 | |
|                 else
 | |
|                     m_data[previous_size_bytes - 1] &= ~(0xff >> (previous_size % 8));
 | |
|             }
 | |
| 
 | |
|             kfree(previous_data);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     void fill(bool value)
 | |
|     {
 | |
|         memset(m_data, value ? 0xff : 0x00, size_in_bytes());
 | |
|     }
 | |
| 
 | |
|     int find_first_set() const
 | |
|     {
 | |
|         int i = 0;
 | |
|         while (i < m_size / 8 && m_data[i] == 0x00)
 | |
|             i++;
 | |
| 
 | |
|         int j = 0;
 | |
|         for (j = i * 8; j < m_size; j++)
 | |
|             if (get(j))
 | |
|                 return j;
 | |
| 
 | |
|         return -1;
 | |
|     }
 | |
| 
 | |
|     int find_first_unset() const
 | |
|     {
 | |
|         int i = 0;
 | |
|         while (i < m_size / 8 && m_data[i] == 0xff)
 | |
|             i++;
 | |
| 
 | |
|         int j = 0;
 | |
|         for (j = i * 8; j < m_size; j++)
 | |
|             if (!get(j))
 | |
|                 return j;
 | |
| 
 | |
|         return -1;
 | |
|     }
 | |
| 
 | |
|     explicit Bitmap()
 | |
|         : m_size(0)
 | |
|         , m_owned(true)
 | |
|     {
 | |
|         m_data = nullptr;
 | |
|     }
 | |
| 
 | |
|     explicit Bitmap(int size, bool default_value)
 | |
|         : m_size(size)
 | |
|         , m_owned(true)
 | |
|     {
 | |
|         ASSERT(m_size != 0);
 | |
|         m_data = reinterpret_cast<u8*>(kmalloc(size_in_bytes()));
 | |
|         fill(default_value);
 | |
|     }
 | |
| 
 | |
|     Bitmap(u8* data, int size)
 | |
|         : m_data(data)
 | |
|         , m_size(size)
 | |
|         , m_owned(false)
 | |
|     {
 | |
|     }
 | |
| 
 | |
| private:
 | |
| 
 | |
|     int size_in_bytes() const { return ceil_div(m_size, 8); }
 | |
| 
 | |
|     u8* m_data { nullptr };
 | |
|     int m_size { 0 };
 | |
|     bool m_owned { false };
 | |
| };
 | |
| 
 | |
| }
 | |
| 
 | |
| using AK::Bitmap;
 | 
