1 /*
2 * Copyright (c) 2018, Sam Kumar <samkumar@cs.berkeley.edu>
3 * Copyright (c) 2018, University of California, Berkeley
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holder nor the
14 * names of its contributors may be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 /* BITMAP */
31
32 #include <stdint.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include "bitmap.h"
38
bmp_init(uint8_t * buf,size_t numbytes)39 void bmp_init(uint8_t* buf, size_t numbytes) {
40 memset(buf, 0x00, numbytes);
41 }
42
43 #define _bmp_getrangeinfo(buf, start, len, first_bit_id, first_byte_ptr, last_bit_id, last_byte_ptr) \
44 do { \
45 first_bit_id = (start & 0x7); \
46 first_byte_ptr = buf + (start >> 3); \
47 last_bit_id = (len & 0x7) + first_bit_id; \
48 last_byte_ptr = first_byte_ptr + (len >> 3) + (last_bit_id >> 3); \
49 last_bit_id &= 0x7; \
50 } while (0)
51
bmp_setrange(uint8_t * buf,size_t start,size_t len)52 void bmp_setrange(uint8_t* buf, size_t start, size_t len) {
53 uint8_t first_bit_id;
54 uint8_t* first_byte_set;
55 uint8_t last_bit_id;
56 uint8_t* last_byte_set;
57 uint8_t first_byte_mask, last_byte_mask;
58 _bmp_getrangeinfo(buf, start, len, first_bit_id, first_byte_set,
59 last_bit_id, last_byte_set);
60
61 first_byte_mask = (uint8_t) (0xFF >> first_bit_id);
62 last_byte_mask = (uint8_t) (0xFF << (8 - last_bit_id));
63
64 /* Set the bits. */
65 if (first_byte_set == last_byte_set) {
66 *first_byte_set |= (first_byte_mask & last_byte_mask);
67 } else {
68 *first_byte_set |= first_byte_mask;
69 memset(first_byte_set + 1, 0xFF, (size_t) (last_byte_set - first_byte_set - 1));
70 if (last_byte_mask != 0x00) {
71 *last_byte_set |= last_byte_mask;
72 }
73 }
74 }
75
bmp_clrrange(uint8_t * buf,size_t start,size_t len)76 void bmp_clrrange(uint8_t* buf, size_t start, size_t len) {
77 uint8_t first_bit_id;
78 uint8_t* first_byte_clear;
79 uint8_t last_bit_id;
80 uint8_t* last_byte_clear;
81 uint8_t first_byte_mask, last_byte_mask;
82 _bmp_getrangeinfo(buf, start, len, first_bit_id, first_byte_clear,
83 last_bit_id, last_byte_clear);
84
85 first_byte_mask = (uint8_t) (0xFF << (8 - first_bit_id));
86 last_byte_mask = (uint8_t) (0xFF >> last_bit_id);
87
88 /* Clear the bits. */
89 if (first_byte_clear == last_byte_clear) {
90 *first_byte_clear &= (first_byte_mask | last_byte_mask);
91 } else {
92 *first_byte_clear &= first_byte_mask;
93 memset(first_byte_clear + 1, 0x00, (size_t) (last_byte_clear - first_byte_clear - 1));
94 if (last_byte_mask != 0xFF) {
95 *last_byte_clear &= last_byte_mask;
96 }
97 }
98 }
99
bmp_countset(uint8_t * buf,size_t buflen,size_t start,size_t limit)100 size_t bmp_countset(uint8_t* buf, size_t buflen, size_t start, size_t limit) {
101 uint8_t first_bit_id;
102 uint8_t first_byte;
103 uint8_t ideal_first_byte;
104 size_t numset;
105 uint8_t curr_byte;
106 size_t curr_index = start >> 3;
107 first_bit_id = start & 0x7;
108 first_byte = *(buf + curr_index);
109
110 numset = 8 - first_bit_id; // initialize optimistically, assuming that the first byte will have all 1's in the part we care about
111 ideal_first_byte = (uint8_t) (0xFF >> first_bit_id);
112 first_byte &= ideal_first_byte;
113 if (first_byte == ideal_first_byte) {
114 // All bits in the first byte starting at first_bit_id are set
115 for (curr_index = curr_index + 1; curr_index < buflen && numset < limit; curr_index++) {
116 curr_byte = buf[curr_index];
117 if (curr_byte == (uint8_t) 0xFF) {
118 numset += 8;
119 } else {
120 while (curr_byte & (uint8_t) 0x80) { // we could add a numset < limit check here, but it probably isn't worth it
121 curr_byte <<= 1;
122 numset++;
123 }
124 break;
125 }
126 }
127 } else {
128 // The streak ends within the first byte
129 do {
130 first_byte >>= 1;
131 ideal_first_byte >>= 1;
132 numset--;
133 } while (first_byte != ideal_first_byte);
134 }
135 return numset;
136 }
137
bmp_read_bit(uint8_t * buf,size_t i)138 static inline uint8_t bmp_read_bit(uint8_t* buf, size_t i) {
139 size_t byte_index = i >> 3;
140 size_t bit_index = i & 0x7; // Amount to left shift to get bit in MSB
141 return ((uint8_t) (buf[byte_index] << bit_index)) >> 7;
142 }
143
bmp_write_bit(uint8_t * buf,size_t i,uint8_t bit)144 static inline void bmp_write_bit(uint8_t* buf, size_t i, uint8_t bit) {
145 size_t byte_index = i >> 3;
146 size_t bit_index = i & 0x7; // Amount to left shift to get bit in MSB
147 size_t bit_shift = 7 - bit_index; // Amount to right shift to get bit in LSB
148 buf[byte_index] = (buf[byte_index] & ~(1 << bit_shift)) | (bit << bit_shift);
149 }
150
bmp_read_byte(uint8_t * buf,size_t i)151 static inline uint8_t bmp_read_byte(uint8_t* buf, size_t i) {
152 size_t byte_index = i >> 3;
153 size_t bit_index = i & 0x7; // Amount to left shift to get bit in MSB
154 if (bit_index == 0) {
155 return buf[byte_index];
156 }
157 return (buf[byte_index] << bit_index) | (buf[byte_index + 1] >> (8 - bit_index));
158 }
159
bmp_write_byte(uint8_t * buf,size_t i,uint8_t byte)160 static inline void bmp_write_byte(uint8_t* buf, size_t i, uint8_t byte) {
161 size_t byte_index = i >> 3;
162 size_t bit_index = i & 0x7; // Amount to left shift to get bit in MSB
163 if (bit_index == 0) {
164 buf[byte_index] = byte;
165 return;
166 }
167 buf[byte_index] = (buf[byte_index] & (0xFF << (8 - bit_index))) | (byte >> bit_index);
168 buf[byte_index + 1] = (buf[byte_index + 1] & (0xFF >> bit_index)) | (byte << (8 - bit_index));
169 }
170
bmp_swap(uint8_t * buf,size_t start_1,size_t start_2,size_t len)171 void bmp_swap(uint8_t* buf, size_t start_1, size_t start_2, size_t len) {
172 while ((len & 0x7) != 0) {
173 uint8_t bit_1 = bmp_read_bit(buf, start_1);
174 uint8_t bit_2 = bmp_read_bit(buf, start_2);
175 if (bit_1 != bit_2) {
176 bmp_write_bit(buf, start_1, bit_2);
177 bmp_write_bit(buf, start_2, bit_1);
178 }
179
180 start_1++;
181 start_2++;
182 len--;
183 }
184
185 while (len != 0) {
186 uint8_t byte_1 = bmp_read_byte(buf, start_1);
187 uint8_t byte_2 = bmp_read_byte(buf, start_2);
188 if (byte_1 != byte_2) {
189 bmp_write_byte(buf, start_1, byte_2);
190 bmp_write_byte(buf, start_2, byte_1);
191 }
192
193 start_1 += 8;
194 start_2 += 8;
195 len -= 8;
196 }
197 }
198
bmp_isempty(uint8_t * buf,size_t buflen)199 int bmp_isempty(uint8_t* buf, size_t buflen) {
200 uint8_t* bufend = buf + buflen;
201 while (buf < bufend) {
202 if (*(buf++)) {
203 return 0;
204 }
205 }
206 return 1;
207 }
208
209 /*
210 * This function is unused, but I'm leaving it in the code as a comment in case
211 * it becomes useful for debugging later on.
212 */
213 #if 0
214 void bmp_print(uint8_t* buf, size_t buflen) {
215 size_t i;
216 for (i = 0; i < buflen; i++) {
217 printf("%02X", buf[i]);
218 }
219 printf("\n");
220 }
221 #endif
222