NDEVR
API Documentation
BoolBuffer.hpp
1/*--------------------------------------------------------------------------------------------
2Copyright (c) 2019, NDEVR LLC
3tyler.parke@ndevr.org
4 __ __ ____ _____ __ __ _______
5 | \ | | | __ \ | ___|\ \ / / | __ \
6 | \ | | | | \ \ | |___ \ \ / / | |__) |
7 | . \| | | |__/ / | |___ \ V / | _ /
8 | |\ |_|_____/__|_____|___\_/____| | \ \
9 |__| \__________________________________| \__\
10
11Subject to the terms of the Enterprise+ Agreement, NDEVR hereby grants
12Licensee a limited, non-exclusive, non-transferable, royalty-free license
13(without the right to sublicense) to use the API solely for the purpose of
14Licensee's internal development efforts to develop applications for which
15the API was provided.
16
17The above copyright notice and this permission notice shall be included in all
18copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
21INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
22PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
23FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25DEALINGS IN THE SOFTWARE.
26
27Library: Base
28File: BoolBuffer
29Included in API: True
30Author(s): Tyler Parke
31 *-----------------------------------------------------------------------------------------**/
32#pragma once
33#include <NDEVR/ObjectAllocator.h>
34#include <NDEVR/BitReference.h>
35#include <NDEVR/BitIterator.h>
36namespace NDEVR
37{
38 #define bitset_wrd(pos) ((pos) >> 3)
39 #define bitset_idx(pos) ((pos) & 7)
40 #define bitmaskt(nbits,type) ((nbits) ? ~(type)0 >> (sizeof(type)*8-(nbits)): (type)0)
41 #define bitmask(nbits) cast<uint01>(bitmaskt(nbits,uint32_t))
42
47 template<class t_index_type>
48 class BufferAllocator<bool, 0, true, t_index_type, false>
49 {
50 public:
52 using index_type = t_index_type;
53
54 explicit BufferAllocator()
55 : m_buffer(nullptr)
56 , m_filled_size(0)
58 {}
59
60 BufferAllocator(BufferAllocator&& allocator) noexcept
61 : m_buffer(nullptr)
62 , m_filled_size(0)
64 {
65 std::swap(allocator.m_buffer, m_buffer);
66 std::swap(allocator.m_filled_size, m_filled_size);
67 std::swap(allocator.m_allocated_size, m_allocated_size);
68 }
70 {
71 if (m_allocated_size != 0)
72 free(m_buffer);
73 }
74 template<bool t_managed>
75 void createSpace(t_index_type size)
76 {
77 m_filled_size += size;
79 }
80 template<bool t_managed>
81 void createSpace(t_index_type location, t_index_type size)
82 {
84 bitmove(begin() + location + size, begin() + location, m_filled_size - (size + location));
85 }
86 void addLast()
87 {
89 }
90 void removeLast()
91 {
92 m_filled_size--;
93 }
94 void addIndex()
95 {
97 }
98 void addIndex(t_index_type location)
99 {
100 lib_assert(location <= m_filled_size, "Out of bounds add all");
102 bitmove(begin() + location + 1, begin() + location, (m_filled_size - location - 1));
103 }
104 void removeIndex(t_index_type location)
105 {
106 lib_assert(location <= m_filled_size, "Out of bounds add all");
107 bitmove(begin() + location, begin() + location + 1, (m_filled_size - location));
108 m_filled_size--;
109 }
110 sint04 compare(const BufferAllocator& allocator) const
111 {
112 t_index_type min_size = bitset_wrd(getMin(allocator.filledSize(), filledSize()));
113 sint04 cmp_value = cast<sint04>(memcmp(m_buffer, allocator.m_buffer, min_size));
114 return cmp_value;
115 }
116 sint04 compare(const BufferAllocator& allocator, t_index_type start, t_index_type end) const
117 {
118 sint04 cmp_value = memcmp(&(m_buffer[start]), &(allocator.m_buffer[start]), getMin(allocator.filledSize(), filledSize(), end));
119 return cmp_value;
120 }
121 void swap(t_index_type index_a, t_index_type index_b)
122 {
123 std::swap(m_buffer[index_a], m_buffer[index_b]);
124 }
125 void clear()
126 {
127 m_filled_size = 0;
128 }
129 void setSize(t_index_type size)
130 {
131 m_filled_size = size;
133 }
134 BitReference get(t_index_type index)
135 {
136 lib_assert(index < m_filled_size, "Array out of bounds");
137 return BitReference(m_buffer[bitset_wrd(index)], bitset_idx(index));
138 }
139 bool get(t_index_type index) const
140 {
141 lib_assert(index < m_filled_size, "Array out of bounds");
142 return m_buffer[bitset_wrd(index)][bitset_idx(index)];
143 }
145 {
146 return BitIterator(m_buffer, 0);
147 }
148 const ConstBitIterator begin() const
149 {
150 return ConstBitIterator(m_buffer, 0);
151 }
152 BitIterator begin(t_index_type index) const
153 {
154 return BitIterator(m_buffer, cast<sint04>(index));
155 }
156
157 t_index_type capacity() const
158 {
159 return m_allocated_size;
160 }
162 {
163 return BitIterator(m_buffer, m_filled_size);
164 }
165 ConstBitIterator end() const
166 {
167 return ConstBitIterator(m_buffer, m_filled_size);
168 }
169 BitIterator end(t_index_type index)
170 {
171 return BitIterator(m_buffer, m_filled_size - index);
172 }
173
174 BitFlag* ptr()
175 {
176 return m_buffer;
177 }
178
179 const BitFlag* ptr() const
180 {
181 return m_buffer;
182 }
183 t_index_type memSize() const
184 {
185 if (m_filled_size == 0)
186 return 0;
187 return bitset_wrd(m_filled_size - 1) + 1;
188 }
189 void setAll(const bool& object, t_index_type offset, t_index_type size)
190 {
191 if (size == 0)
192 return;
193
194 t_index_type first_word = bitset_wrd(offset);
195 t_index_type last_word = bitset_wrd(offset + size - 1);
196 t_index_type foffset = bitset_idx(offset);
197 t_index_type loffset = bitset_idx(offset + size - 1);
198
199 if (first_word == last_word)
200 {
201 uint01 mask = bitmask(size) << foffset;
202 if(object)
203 m_buffer[first_word] |= BitFlag(mask);
204 else
205 m_buffer[first_word] &= BitFlag(~mask);
206 }
207 else
208 {
209 // Set first word
210 if (object)
211 m_buffer[first_word] |= BitFlag(~bitmask(foffset));
212 else
213 m_buffer[first_word] &= BitFlag(bitmask(foffset));
214 memset(m_buffer + first_word + 1, object ? 0xFF : 0, last_word - (first_word + 1));
215
216 if (object)
217 m_buffer[last_word] |= BitFlag(bitmask(loffset + 1));
218 else
219 m_buffer[last_word] &= BitFlag(~bitmask(loffset + 1));
220 }
221#ifdef _DEBUG
222 for (uint04 i = 0; i < size; i++)
223 lib_assert(get(i + offset) == object, "Bad optimized set");
224#endif
225 }
226 template<bool is_primitive>
227 void setAll(const bool* src, t_index_type offset, t_index_type size)
228 {
229 for (t_index_type i = 0; i < size; i++)
230 {
231 get(i + offset) = src[i];
232 }
233 }
234
235 template<bool is_primitive>
236 void setAll(const BufferAllocator& allocator, t_index_type offset, t_index_type other_offset, t_index_type size)
237 {
238 if(bitset_idx(offset) == 0 && bitset_idx(other_offset) == 0)//if we are memory aligned
239 {
240 t_index_type new_size = bitset_wrd(size);
241 t_index_type new_offset = bitset_wrd(offset);
242 t_index_type new_other_offset = bitset_wrd(other_offset);
243 memmove(m_buffer + new_offset, allocator.m_buffer + new_other_offset, new_size);
244 for (t_index_type i = 8 * new_size; i < size; i++)
245 {
246 get(i + offset) = allocator.get(i + other_offset);
247 }
248 }
249 for (t_index_type i = 0; i < size; i++)
250 {
251 get(i + offset) = allocator.get(i + other_offset);
252 }
253 }
254 template<class t_other_allocator>
255 void setAllFromSource(const t_other_allocator& allocator, t_index_type offset, t_index_type other_offset, t_index_type size)
256 {
257 for (t_index_type i = 0; i < size; i++)
258 get(i + offset) = allocator.get(i + other_offset);
259 }
260 template<bool is_primitive>
261 void setAll(ConstBitIterator iterator, uint04 offset, uint04 size)
262 {
263 BitReference ref = get(offset);
264 for (t_index_type i = 0; i < size; i++)
265 {
266 get(i + offset) = iterator;
267 iterator++;
268 }
269 }
270 template<bool t_managed>
271 inline void allocationSizeCheck()
272 {
273 if ((t_managed && m_filled_size > m_allocated_size) || m_filled_size == m_allocated_size + 1)//We only 1, assume more to come shortly and allocate more space than required
274 {
275 lib_assert(cast<uint08>((t_managed ? m_filled_size : m_allocated_size) * 3) / 2 < cast<uint08>(Constant<uint04>::Max), "Buffer overflow");
276 resizeSpace(cast<t_index_type>(cast<uint08>((t_managed ? m_filled_size : m_allocated_size) * 3) / 2) + 1);
277 }
278 else if (m_filled_size > m_allocated_size) //We added more than 1, increase buffer only once for compaction
279 {
280 resizeSpace(m_filled_size);
281 }
282 }
283 void removeAllIndex(t_index_type start, t_index_type end)
284 {
285 if (end == m_filled_size)
286 {
287 m_filled_size = start;
288 }
289 else
290 {
291 bitmove(begin() + start, begin() + end, (m_filled_size - end));
292 m_filled_size -= (end - start);
293 }
294 }
295
296 t_index_type filledSize() const
297 {
298 return m_filled_size;
299 }
300 t_index_type count(const bool& value) const
301 {
302 uint04 count = 0;
303 for (uint04 i = 0; i < m_filled_size; i++)
304 {
305 if (get(i) == value)
306 ++count;
307 }
308 return count;
309 //return value ? numSet() : filledSize() - numSet();
310 }
311 template<class t_comparable_type>
312 bool contains(const t_comparable_type& value, t_index_type start, t_index_type size) const
313 {
314 bool bool_val = value;
315 t_index_type end = start + size;
316 // First partial byte (unaligned prefix)
317 t_index_type byte_start = (start + 7) & ~7;
318 for (t_index_type i = start; i < byte_start && i < end; ++i)
319 {
320 if (get(i) == bool_val)
321 return true;
322 }
323
324 // Last partial byte (unaligned suffix)
325 t_index_type byte_end = end & ~7;
326 for (t_index_type i = byte_end; i < end; ++i)
327 {
328 if (get(i) == bool_val)
329 return true;
330 }
331 // Full byte-aligned segment
332 t_index_type byte_begin = byte_start / 8;
333 t_index_type byte_finish = byte_end / 8;
334 constexpr BitFlag off(false);
335 constexpr BitFlag on(true);
336 if (bool_val)
337 {
338 for (t_index_type i = byte_begin; i < byte_finish; ++i)
339 {
340 if (m_buffer[i] != off)
341 return true;
342 }
343 }
344 else
345 {
346 for (t_index_type i = byte_begin; i < byte_finish; ++i)
347 {
348 if (m_buffer[i] != on)
349 return true;
350 }
351 }
352 return false;
353 }
354 inline BufferAllocator& operator=(BufferAllocator&& value) noexcept
355 {
356 std::swap(value.m_buffer, m_buffer);
357 std::swap(value.m_filled_size, m_filled_size);
358 std::swap(value.m_allocated_size, m_allocated_size);
359 return *this;
360 }
361
362 inline void resizeSpace(t_index_type new_size)
363 {
364 t_index_type byte_size = new_size == 0 ? 0 : bitset_wrd(new_size - 1) + 1;
365 if (new_size == 0)
366 {
367 if (m_allocated_size != 0)
368 free(m_buffer);
369 m_buffer = nullptr;
370 }
371 else
372 {
373 if (m_allocated_size == 0)
374 m_buffer = cast<BitFlag*>(malloc(byte_size));
375 else
376 m_buffer = cast<BitFlag*>(realloc(m_buffer, byte_size));
377 lib_assert(m_buffer != nullptr, "Unable to allocate buffer");
378 }
379 m_allocated_size = 8 * byte_size;
380 }
381
382 public:
383 t_index_type numSet() const
384 {
385 static const t_index_type BitsSetTable256[256] =
386 {
387 # define NDV_B2(n) n, n+1, n+1, n+2
388 # define NDV_B4(n) NDV_B2(n), NDV_B2(n+1), NDV_B2(n+1), NDV_B2(n+2)
389 # define NDV_B6(n) NDV_B4(n), NDV_B4(n+1), NDV_B4(n+1), NDV_B4(n+2)
390 NDV_B6(0), NDV_B6(1), NDV_B6(1), NDV_B6(2)
391 };
392 t_index_type flag_size = bitset_wrd(filledSize());
393 t_index_type num_set = 0;
394 uint01* mask = new uint01(1 << (filledSize() + 1)) - 1;
395 flag_size = flag_size ^ ((flag_size ^ filledSize()) & *mask);
396 BitFlag k(~*mask);
397 for (t_index_type i = 0; i < flag_size; i++)
398 {
399 num_set += BitsSetTable256[m_buffer[i]];
400 }
401 const uint01 size_mod_8 = bitset_idx(filledSize());
402 if (size_mod_8 != 0)
403 {
404 for (t_index_type i = 0; i < size_mod_8; i++)
405 {
406 num_set += m_buffer[flag_size][i] ? 1 : 0;
407 }
408 }
409 return num_set;
410 }
411
412 protected:
413 static void bitmove(BitIterator dst, BitIterator src, t_index_type size)
414 {
415 if (dst == src)
416 {
417 return;
418 }
419 if (dst < src)//prevent overlap
420 {
421 for (t_index_type i = 0; i < size; i++)
422 {
423 *dst = *src;
424 ++dst;
425 ++src;
426 }
427 }
428 else
429 {
430 for (t_index_type i = size - 1; IsValid(i); i--)
431 {
432 *(dst + i) = *(src + i);
433 }
434 }
435 }
436 void setFlag(const t_index_type index, const bool value)
437 {
438 m_buffer[bitset_wrd(index)](index & 7, value);
439 }
440
441 public:
442 void invert()
443 {
444 const t_index_type byte_size = memSize();
445 for (t_index_type i = 0; i < byte_size; i++)
446 {
447 m_buffer[i] = ~m_buffer[i];
448 }
449 }
450 void inverseAndEquals(const BufferAllocator<bool, 0, true, t_index_type>& buffer)
451 {
452 lib_assert(memSize() == buffer.memSize(), "Cannot ^= two buffers of different length");
453 const t_index_type byte_size = memSize();
454 for (t_index_type i = 0; i < byte_size; i++)
455 m_buffer[i] &= (~buffer.m_buffer[i]);
456 }
457 void operator^=(const BufferAllocator<bool, 0, true, t_index_type>& buffer)
458 {
459 lib_assert(memSize() == buffer.memSize(), "Cannot ^= two buffers of different length");
460 const t_index_type byte_size = memSize();
461 for (t_index_type i = 0; i < byte_size; i++)
462 m_buffer[i] ^= buffer.m_buffer[i];
463 }
464 void operator|=(const BufferAllocator<bool, 0, true, t_index_type>& buffer)
465 {
466 lib_assert(memSize() == buffer.memSize(), "Cannot |= two buffers of different length");
467 const t_index_type byte_size = memSize();
468 for (t_index_type i = 0; i < byte_size; i++)
469 m_buffer[i] |= buffer.m_buffer[i];
470 }
471 void operator&=(const BufferAllocator<bool, 0, true, t_index_type>& buffer)
472 {
473 lib_assert(memSize() == buffer.memSize(), "Cannot &= two buffers of different length");
474 const t_index_type byte_size = memSize();
475 for (t_index_type i = 0; i < byte_size; i++)
476 m_buffer[i] &= buffer.m_buffer[i];
477 }
478 protected:
479 BitFlag* m_buffer;
480 t_index_type m_filled_size;
481 t_index_type m_allocated_size;
482 };
483#undef bitset_wrd
484#undef bitset_idx
485#undef bitmaskt
486#undef bitmask
487}
488
A bitset that stores 8 bits (elements with only two possible values: 0 or 1, true or false,...
Definition BitFlag.hpp:55
Simple bit iterator, typically used for parsing Buffer of bools in loops.
A convenience class used with Buffers or Vectors of bools for referencing or acting on a single bit.
constexpr BufferAllocator() noexcept
Default constructor.
constexpr decltype(auto) ptr() noexcept
Returns a pointer to the underlying buffer, with optional alignment hint.
void setAllFromSource(const t_other_allocator &allocator, t_index_type offset, t_index_type other_offset, t_index_type size) noexcept
Copies elements from a generic source allocator into this buffer using element-wise assignment.
constexpr t_index_type count(const t_type &value) const noexcept
Counts the number of occurrences of a value in the buffer.
void resizeSpace(t_index_type new_size) noexcept
Resizes the allocated memory to the specified number of elements.
sint04 compare(const BufferAllocator &allocator) const noexcept
Performs a byte-level comparison of this buffer with another.
void removeIndex(t_index_type location) noexcept
Removes an element at the specified location by shifting subsequent elements backward.
constexpr decltype(auto) end() noexcept
Returns a pointer to one past the last filled element.
void removeLast() noexcept
Removes the last element from the buffer by decrementing the filled size.
BufferAllocator & operator=(BufferAllocator &&value) noexcept
Move assignment operator.
constexpr t_index_type capacity() const noexcept
Returns the total allocated capacity of the buffer in elements.
t_index_type m_filled_size
The number of elements currently stored in the buffer.
t_type & get(t_index_type index) noexcept
Gets a mutable reference to the element at the given index.
void swap(t_index_type index_a, t_index_type index_b) noexcept
Swaps two elements in the buffer by index.
void setSize(t_index_type size) noexcept
Sets the filled size of the buffer, allocating more space if necessary.
t_type * m_buffer
The buffer that stores the actual data.
constexpr t_index_type filledSize() const noexcept
Returns the number of elements currently stored in the buffer.
~BufferAllocator() noexcept
Destructor.
constexpr decltype(auto) begin() noexcept
Returns a pointer to the beginning of the buffer.
void removeAllIndex(t_index_type start, t_index_type end) noexcept
Removes a contiguous range of elements from the buffer.
void setAll(const t_type &object, t_index_type offset, t_index_type size) noexcept
Fills a range of elements in the buffer with a single value.
constexpr void createSpace(t_index_type size) noexcept
Creates additional space at the end of the buffer, optionally auto-managing capacity.
constexpr void addIndex() noexcept
Appends one uninitialized element at the end of the buffer without managed growth.
constexpr size_t memSize() const noexcept
Returns the total memory size of the filled portion of the buffer in bytes.
constexpr void allocationSizeCheck(t_index_type new_size) noexcept
Checks if the buffer needs to grow and allocates accordingly.
void clear() noexcept
Clears the buffer by resetting the filled size to zero without freeing memory.
t_index_type m_allocated_size
The total allocated capacity in elements.
void addLast() noexcept
Appends one uninitialized element to the end of the buffer without managed growth.
constexpr bool contains(const t_comparable_type &value, t_index_type start, t_index_type size) const noexcept
Checks whether the buffer contains a given value within the specified range.
Simple bit iterator, typically used for parsing Buffer of bools in loops.
Allows for specific, custom logic for allocating an object.
The primary namespace for the NDEVR SDK.
@ BitFlag
Per-vertex bit flags (selected, hidden, etc.).
constexpr t_type getMin(const t_type &left, const t_type &right)
Finds the minimum of the given arguments based on the < operator Author: Tyler Parke Date: 2017-11-05...
static constexpr bool IsValid(const Angle< t_type > &value)
Checks whether the given Angle holds a valid value.
Definition Angle.h:398
uint32_t uint04
-Defines an alias representing a 4 byte, unsigned integer -Can represent exact integer values 0 throu...
int32_t sint04
-Defines an alias representing a 4 byte, signed integer.
uint8_t uint01
-Defines an alias representing a 1 byte, unsigned integer -Can represent exact integer values 0 throu...
constexpr t_to cast(const Angle< t_from > &value)
Casts an Angle from one backing type to another.
Definition Angle.h:408