Coverage Report

Created: 2026-02-16 07:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/AK/Bitmap.h
Line
Count
Source
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/BitmapView.h>
10
#include <AK/Error.h>
11
#include <AK/Noncopyable.h>
12
#include <AK/Optional.h>
13
#include <AK/Platform.h>
14
#include <AK/StdLibExtras.h>
15
#include <AK/Try.h>
16
#include <AK/Types.h>
17
#include <AK/kmalloc.h>
18
19
namespace AK {
20
21
class Bitmap : public BitmapView {
22
    AK_MAKE_NONCOPYABLE(Bitmap);
23
24
public:
25
    static ErrorOr<Bitmap> create(size_t size, bool default_value)
26
0
    {
27
0
        VERIFY(size != 0);
28
29
0
        auto* data = kmalloc(ceil_div(size, static_cast<size_t>(8)));
30
0
        if (!data)
31
0
            return Error::from_errno(ENOMEM);
32
33
0
        auto bitmap = Bitmap { static_cast<u8*>(data), size, true };
34
0
        bitmap.fill(default_value);
35
0
        return bitmap;
36
0
    }
37
38
    Bitmap() = default;
39
40
    Bitmap(u8* data, size_t size, bool is_owning = false)
41
0
        : BitmapView(data, size)
42
0
        , m_is_owning(is_owning)
43
0
    {
44
0
    }
45
46
    Bitmap(Bitmap&& other)
47
0
        : BitmapView(exchange(other.m_data, nullptr), exchange(other.m_size, 0))
48
0
    {
49
0
        m_is_owning = exchange(other.m_is_owning, false);
50
0
    }
51
52
    Bitmap& operator=(Bitmap&& other)
53
0
    {
54
0
        if (this != &other) {
55
0
            kfree_sized(m_data, size_in_bytes());
56
0
            m_data = exchange(other.m_data, nullptr);
57
0
            m_size = exchange(other.m_size, 0);
58
0
        }
59
0
        return *this;
60
0
    }
61
62
    ~Bitmap()
63
0
    {
64
0
        if (m_is_owning) {
65
0
            kfree_sized(m_data, size_in_bytes());
66
0
        }
67
0
        m_data = nullptr;
68
0
    }
69
70
0
    [[nodiscard]] BitmapView view() const { return *this; }
71
72
    void set(size_t index, bool value)
73
0
    {
74
0
        VERIFY(index < m_size);
75
0
        if (value)
76
0
            m_data[index / 8] |= static_cast<u8>((1u << (index % 8)));
77
0
        else
78
0
            m_data[index / 8] &= static_cast<u8>(~(1u << (index % 8)));
79
0
    }
80
81
    // NOTE: There's a const method variant of this method at the parent class BitmapView.
82
0
    [[nodiscard]] u8* data() { return m_data; }
83
84
    void grow(size_t size, bool default_value)
85
0
    {
86
0
        VERIFY(size > m_size);
87
0
88
0
        auto previous_size_bytes = size_in_bytes();
89
0
        auto previous_size = m_size;
90
0
        auto* previous_data = m_data;
91
0
92
0
        m_size = size;
93
0
        m_data = reinterpret_cast<u8*>(kmalloc(size_in_bytes()));
94
0
95
0
        fill(default_value);
96
0
97
0
        if (previous_data != nullptr) {
98
0
            __builtin_memcpy(m_data, previous_data, previous_size_bytes);
99
0
            if ((previous_size % 8) != 0)
100
0
                set_range(previous_size, 8 - previous_size % 8, default_value);
101
0
            kfree_sized(previous_data, previous_size_bytes);
102
0
        }
103
0
    }
104
105
    template<bool VALUE, bool verify_that_all_bits_flip = false>
106
    void set_range(size_t start, size_t len)
107
0
    {
108
0
        VERIFY(start < m_size);
109
0
        VERIFY(start + len <= m_size);
110
0
        if (len == 0)
111
0
            return;
112
0
113
0
        u8* first = &m_data[start / 8];
114
0
        u8* last = &m_data[(start + len) / 8];
115
0
        u8 byte_mask = bitmask_first_byte[start % 8];
116
0
        if (first == last) {
117
0
            byte_mask &= bitmask_last_byte[(start + len) % 8];
118
0
            if constexpr (verify_that_all_bits_flip) {
119
0
                if constexpr (VALUE) {
120
0
                    VERIFY((*first & byte_mask) == 0);
121
0
                } else {
122
0
                    VERIFY((*first & byte_mask) == byte_mask);
123
0
                }
124
0
            }
125
0
            if constexpr (VALUE)
126
0
                *first |= byte_mask;
127
0
            else
128
0
                *first &= ~byte_mask;
129
0
        } else {
130
0
            if constexpr (verify_that_all_bits_flip) {
131
0
                if constexpr (VALUE) {
132
0
                    VERIFY((*first & byte_mask) == 0);
133
0
                } else {
134
0
                    VERIFY((*first & byte_mask) == byte_mask);
135
0
                }
136
0
            }
137
0
            if constexpr (VALUE)
138
0
                *first |= byte_mask;
139
0
            else
140
0
                *first &= ~byte_mask;
141
0
            byte_mask = bitmask_last_byte[(start + len) % 8];
142
0
            if constexpr (verify_that_all_bits_flip) {
143
0
                if constexpr (VALUE) {
144
0
                    VERIFY((*last & byte_mask) == 0);
145
0
                } else {
146
0
                    VERIFY((*last & byte_mask) == byte_mask);
147
0
                }
148
0
            }
149
0
            if constexpr (VALUE)
150
0
                *last |= byte_mask;
151
0
            else
152
0
                *last &= ~byte_mask;
153
0
            if (++first < last) {
154
0
                if constexpr (VALUE)
155
0
                    __builtin_memset(first, 0xFF, last - first);
156
0
                else
157
0
                    __builtin_memset(first, 0x0, last - first);
158
0
            }
159
0
        }
160
0
    }
Unexecuted instantiation: void AK::Bitmap::set_range<true, false>(unsigned long, unsigned long)
Unexecuted instantiation: void AK::Bitmap::set_range<false, false>(unsigned long, unsigned long)
Unexecuted instantiation: void AK::Bitmap::set_range<true, true>(unsigned long, unsigned long)
Unexecuted instantiation: void AK::Bitmap::set_range<false, true>(unsigned long, unsigned long)
161
162
    void set_range(size_t start, size_t len, bool value)
163
0
    {
164
0
        if (value)
165
0
            set_range<true, false>(start, len);
166
0
        else
167
0
            set_range<false, false>(start, len);
168
0
    }
169
170
    void set_range_and_verify_that_all_bits_flip(size_t start, size_t len, bool value)
171
0
    {
172
0
        if (value)
173
0
            set_range<true, true>(start, len);
174
0
        else
175
0
            set_range<false, true>(start, len);
176
0
    }
177
178
    void fill(bool value)
179
0
    {
180
0
        __builtin_memset(m_data, value ? 0xff : 0x00, size_in_bytes());
181
0
    }
182
183
private:
184
    bool m_is_owning { true };
185
};
186
187
}
188
189
#if USING_AK_GLOBALLY
190
using AK::Bitmap;
191
#endif