KiCad PCB EDA Suite
Loading...
Searching...
No Matches
base_set.h
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19#ifndef BASE_SET_H
20#define BASE_SET_H
21
22#include <algorithm>
23#include <iterator>
24#include <limits>
25#include <ostream>
26#include <stdexcept>
27
28// dynamic_bitset pulls in libpopcnt, whose static dispatch helpers go unused in the great
29// majority of the translation units this header reaches.
30#if defined( __GNUC__ ) && !defined( __clang__ )
31#pragma GCC diagnostic push
32#pragma GCC diagnostic ignored "-Wunused-function"
33#endif
34#include <dynamic_bitset.h>
35#if defined( __GNUC__ ) && !defined( __clang__ )
36#pragma GCC diagnostic pop
37#endif
38
39#include <core/arraydim.h>
40#include <core/kicad_algo.h>
41#include <kicommon.h>
42
43#if defined( _MSC_VER )
44// ssize_t is a POSIX extension
45// wx usually defines it on windows as a helper
46// windows does have SSIZE_T (capital) for the same purpose
47#include <BaseTsd.h>
48typedef SSIZE_T ssize_t;
49#endif
50
51class KICOMMON_API BASE_SET : public sul::dynamic_bitset<uint64_t>
52{
53public:
55 {
56 public:
57 using iterator_category = std::random_access_iterator_tag;
58 using value_type = bool;
59 using difference_type = std::ptrdiff_t;
60 using pointer = void;
61 using reference = bool;
62
63 iterator( BASE_SET* set, size_t pos ) : m_set( set ), m_pos( pos ) {}
64 bool operator*() const { return m_set->test( m_pos ); }
66 {
67 ++m_pos;
68 return *this;
69 }
71 {
72 return iterator( m_set, m_pos + n );
73 }
74 difference_type operator-( const iterator& other ) const
75 {
76 return static_cast<difference_type>(m_pos) - static_cast<difference_type>(other.m_pos);
77 }
78 auto operator<=>( const iterator& ) const = default;
79
80 private:
82 size_t m_pos;
83 };
84
86 {
87 public:
88 using iterator_category = std::random_access_iterator_tag;
89 using value_type = bool;
90 using difference_type = std::ptrdiff_t;
91 using pointer = void;
92 using reference = bool;
93
94 const_iterator( const BASE_SET* set, size_t pos ) : m_set( set ), m_pos( pos ) {}
95 bool operator*() const { return m_set->test( m_pos ); }
97 {
98 ++m_pos;
99 return *this;
100 }
102 {
103 return const_iterator( m_set, m_pos + n );
104 }
106 {
107 return static_cast<difference_type>(m_pos) - static_cast<difference_type>(other.m_pos);
108 }
109 auto operator<=>( const const_iterator& ) const = default;
110
111 private:
113 size_t m_pos;
114 };
115
116 iterator begin() { return iterator(this, 0); }
117 iterator end() { return iterator(this, size()); }
118 const_iterator begin() const { return const_iterator(this, 0); }
119 const_iterator end() const { return const_iterator(this, size()); }
120
121 BASE_SET( size_t size = 64 ) : sul::dynamic_bitset<uint64_t>( size ) {}
122
123 // Overloads for set, reset, and flip operations
124
125 // Set a bit at the specified position
126 BASE_SET& set(size_t pos)
127 {
128 if( pos >= size() )
129 sul::dynamic_bitset<uint64_t>::resize( pos + 1 );
130
131 sul::dynamic_bitset<uint64_t>::set(pos);
132 return *this;
133 }
134
135 // Set a bit at the specified position to a given value
136 BASE_SET& set(size_t pos, bool value)
137 {
138 if( pos >= size() )
139 sul::dynamic_bitset<uint64_t>::resize( pos + 1 );
140
141 sul::dynamic_bitset<uint64_t>::set(pos, value);
142 return *this;
143 }
144
145 // Set all bits to 1
147 {
148 sul::dynamic_bitset<uint64_t>::set();
149 return *this;
150 }
151
152 // Reset (clear) a bit at the specified position
153 BASE_SET& reset(size_t pos)
154 {
155 if( pos >= size() )
156 sul::dynamic_bitset<uint64_t>::resize( pos + 1 );
157
158 sul::dynamic_bitset<uint64_t>::reset(pos);
159 return *this;
160 }
161
162 // Reset (clear) all bits
164 {
165 sul::dynamic_bitset<uint64_t>::reset();
166 return *this;
167 }
168
169 // Flip a bit at the specified position
170 BASE_SET& flip(size_t pos)
171 {
172 if( pos >= size() )
173 sul::dynamic_bitset<uint64_t>::resize( pos + 1 );
174
175 sul::dynamic_bitset<uint64_t>::flip(pos);
176 return *this;
177 }
178
179 // Flip all bits
181 {
182 sul::dynamic_bitset<uint64_t>::flip();
183 return *this;
184 }
185
186 // Overloads for boolean operators
187
188 // Bitwise NOT operator
190 {
191 BASE_SET result(*this);
192 result.flip();
193 return result;
194 }
195
196 // Compound assignment AND operator
198 {
199 size_t my_size = size();
200 size_t other_size = other.size();
201
202 if( my_size == other_size )
203 {
204 sul::dynamic_bitset<uint64_t>::operator&=(other);
205 }
206 else if( my_size < other_size )
207 {
208 sul::dynamic_bitset<uint64_t>::resize( other_size );
209 sul::dynamic_bitset<uint64_t>::operator&=( other );
210 }
211 else
212 {
213 BASE_SET tmp( other );
214 tmp.resize( my_size );
215 sul::dynamic_bitset<uint64_t>::operator&=( tmp );
216 }
217
218 return *this;
219 }
220
221 // Compound assignment OR operator
223 {
224 size_t my_size = size();
225 size_t other_size = other.size();
226
227 if( my_size == other_size )
228 {
229 sul::dynamic_bitset<uint64_t>::operator|=(other);
230 }
231 else if( my_size < other_size )
232 {
233 sul::dynamic_bitset<uint64_t>::resize( other_size );
234 sul::dynamic_bitset<uint64_t>::operator|=( other );
235 }
236 else
237 {
238 BASE_SET tmp( other );
239 tmp.resize( my_size );
240 sul::dynamic_bitset<uint64_t>::operator|=( tmp );
241 }
242
243 return *this;
244 }
245
246 // Compound assignment XOR operator
248 {
249 size_t my_size = size();
250 size_t other_size = other.size();
251
252 if( my_size == other_size )
253 {
254 sul::dynamic_bitset<uint64_t>::operator^=(other);
255 }
256 else if( my_size < other_size )
257 {
258 sul::dynamic_bitset<uint64_t>::resize( other_size );
259 sul::dynamic_bitset<uint64_t>::operator^=( other );
260 }
261 else
262 {
263 BASE_SET tmp( other );
264 tmp.resize( my_size );
265 sul::dynamic_bitset<uint64_t>::operator^=( tmp );
266 }
267
268 return *this;
269 }
270
271 int compare( const BASE_SET& other ) const
272 {
273 return alg::lexicographical_compare_three_way( begin(), end(), other.begin(), other.end() );
274 }
275
276 // Define less-than operator for comparison
277 bool operator<( const BASE_SET& other ) const
278 {
280 other.end() ) < 0;
281 }
282
286 std::string FmtBin() const
287 {
288 std::string ret;
289
290 int bit_count = static_cast<int>( size() );
291
292 for( int bit=0; bit<bit_count; ++bit )
293 {
294 if( bit )
295 {
296 if( !( bit % 8 ) )
297 ret += '|';
298 else if( !( bit % 4 ) )
299 ret += '_';
300 }
301
302 ret += (*this)[bit] ? '1' : '0';
303 }
304
305 // reverse of string
306 return std::string( ret.rbegin(), ret.rend() );
307 }
308
312 std::string FmtHex() const
313 {
314 std::string ret;
315
316 static const char hex[] = "0123456789abcdef";
317
318 size_t nibble_count = ( size() + 3 ) / 4;
319
320 for( size_t nibble = 0; nibble < nibble_count; ++nibble )
321 {
322 unsigned int ndx = 0;
323
324 // test 4 consecutive bits and set ndx to 0-15
325 for( size_t nibble_bit = 0; nibble_bit < 4; ++nibble_bit )
326 {
327 size_t nibble_pos = nibble_bit + ( nibble * 4 );
328 // make sure it's not extra bits that don't exist in the bitset but need to in the
329 // hex format
330 if( nibble_pos >= size() )
331 break;
332
333 if( ( *this )[nibble_pos] )
334 ndx |= ( 1 << nibble_bit );
335 }
336
337 if( nibble && !( nibble % 8 ) )
338 ret += '_';
339
340 assert( ndx < arrayDim( hex ) );
341
342 ret += hex[ndx];
343 }
344
345 // reverse of string
346 return std::string( ret.rbegin(), ret.rend() );
347 }
348
358 int ParseHex( const std::string& str )
359 {
360 return ParseHex( str.c_str(), static_cast<int>( str.length() ) );
361 }
362
372 int ParseHex( const char* aStart, int aCount )
373 {
374 BASE_SET tmp(size());
375
376 const char* rstart = aStart + aCount - 1;
377 const char* rend = aStart - 1;
378
379 const int bitcount = static_cast<const int>( size() );
380
381 int nibble_ndx = 0;
382
383 while( rstart > rend )
384 {
385 int cc = *rstart--;
386
387 if( cc == '_' )
388 continue;
389
390 int nibble;
391
392 if( cc >= '0' && cc <= '9' )
393 nibble = cc - '0';
394 else if( cc >= 'a' && cc <= 'f' )
395 nibble = cc - 'a' + 10;
396 else if( cc >= 'A' && cc <= 'F' )
397 nibble = cc - 'A' + 10;
398 else
399 break;
400
401 int bit = nibble_ndx * 4;
402
403 for( int ndx=0; bit<bitcount && ndx<4; ++bit, ++ndx )
404 if( nibble & (1<<ndx) )
405 tmp.set( bit );
406
407 if( bit >= bitcount )
408 break;
409
410 ++nibble_ndx;
411 }
412
413 int byte_count = static_cast<int>( aStart + aCount - 1 - rstart );
414
415 assert( byte_count >= 0 );
416
417 if( byte_count > 0 )
418 *this = tmp;
419
420 return byte_count;
421 }
422
423 // Custom iterator to iterate over set bits
425 {
426 public:
427 using iterator_category = std::forward_iterator_tag;
428 using value_type = size_t;
429 using difference_type = std::ptrdiff_t;
430 using pointer = const size_t*;
431 using reference = const size_t&;
432
433 set_bits_iterator( const BASE_SET& baseSet, size_t index ) :
434 m_baseSet( baseSet ), m_index( index )
435 {
437 }
438
439 size_t operator*() const { return m_index; }
440
442 {
443 ++m_index;
445 return *this;
446 }
447
448 bool operator!=( const set_bits_iterator& other ) const { return m_index != other.m_index; }
449
450 bool operator==( const set_bits_iterator& other ) const { return m_index == other.m_index; }
451
452 protected:
454 {
455 while( m_index < m_baseSet.size() && !m_baseSet.test( m_index ) )
456 ++m_index;
457 }
458
460 size_t m_index;
461 };
462
463 // Custom reverse iterator to iterate over set bits in reverse order
465 {
466 public:
467 using iterator_category = std::bidirectional_iterator_tag;
468 using value_type = ssize_t;
469 using difference_type = std::ptrdiff_t;
470 using pointer = const ssize_t*;
471 using reference = const ssize_t&;
472
473 set_bits_reverse_iterator( const BASE_SET& baseSet, ssize_t index ) :
474 m_baseSet( baseSet ), m_index( index )
475 {
477 }
478
479 ssize_t operator*() const { return m_index; }
480
482 {
483 --m_index;
485 return *this;
486 }
487
488 bool operator!=( const set_bits_reverse_iterator& other ) const
489 {
490 return m_index != other.m_index;
491 }
492
493 bool operator==( const set_bits_reverse_iterator& other ) const
494 {
495 return m_index == other.m_index;
496 }
497
498 protected:
500 {
501 while( m_index >= 0 && !m_baseSet.test( m_index ) )
502 {
503 --m_index;
504 }
505 }
506
508 ssize_t m_index;
509 };
510
511 set_bits_iterator set_bits_begin() const { return set_bits_iterator( *this, 0 ); }
512 set_bits_iterator set_bits_end() const { return set_bits_iterator( *this, size() ); }
513
515 {
516 return set_bits_reverse_iterator( *this, size() - 1 );
517 }
519 {
520 return set_bits_reverse_iterator( *this, -1 );
521 }
522
523};
524
525inline BASE_SET operator&( const BASE_SET& lhs, const BASE_SET& rhs )
526{
527 BASE_SET result = lhs;
528 result &= rhs;
529 return result;
530}
531
532inline BASE_SET operator|( const BASE_SET& lhs, const BASE_SET& rhs )
533{
534 BASE_SET result = lhs;
535 result |= rhs;
536 return result;
537}
538
539inline BASE_SET operator^( const BASE_SET& lhs, const BASE_SET& rhs )
540{
541 BASE_SET result = lhs;
542 result ^= rhs;
543 return result;
544}
545
546namespace std
547{
548template <>
549struct hash<BASE_SET>
550{
551 size_t operator()( const BASE_SET& bs ) const
552 {
553 size_t hashVal = 0;
554
555 for( const auto& bit : bs )
556 hashVal = hashVal * 31 + std::hash<int>()( bit );
557
558 return hashVal;
559 }
560};
561} // namespace std
562
563#endif // BASE_SET_H
int index
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Returns # of elements in an array.
Definition arraydim.h:27
BASE_SET operator|(const BASE_SET &lhs, const BASE_SET &rhs)
Definition base_set.h:532
BASE_SET operator^(const BASE_SET &lhs, const BASE_SET &rhs)
Definition base_set.h:539
BASE_SET operator&(const BASE_SET &lhs, const BASE_SET &rhs)
Definition base_set.h:525
auto operator<=>(const const_iterator &) const =default
std::random_access_iterator_tag iterator_category
Definition base_set.h:88
const BASE_SET * m_set
Definition base_set.h:112
const_iterator operator+(difference_type n) const
Definition base_set.h:101
const_iterator(const BASE_SET *set, size_t pos)
Definition base_set.h:94
difference_type operator-(const const_iterator &other) const
Definition base_set.h:105
bool operator*() const
Definition base_set.h:95
std::ptrdiff_t difference_type
Definition base_set.h:90
const_iterator & operator++()
Definition base_set.h:96
auto operator<=>(const iterator &) const =default
iterator & operator++()
Definition base_set.h:65
difference_type operator-(const iterator &other) const
Definition base_set.h:74
BASE_SET * m_set
Definition base_set.h:81
bool operator*() const
Definition base_set.h:64
iterator(BASE_SET *set, size_t pos)
Definition base_set.h:63
std::ptrdiff_t difference_type
Definition base_set.h:59
std::random_access_iterator_tag iterator_category
Definition base_set.h:57
iterator operator+(difference_type n) const
Definition base_set.h:70
set_bits_iterator & operator++()
Definition base_set.h:441
std::forward_iterator_tag iterator_category
Definition base_set.h:427
bool operator!=(const set_bits_iterator &other) const
Definition base_set.h:448
bool operator==(const set_bits_iterator &other) const
Definition base_set.h:450
const BASE_SET & m_baseSet
Definition base_set.h:459
size_t operator*() const
Definition base_set.h:439
std::ptrdiff_t difference_type
Definition base_set.h:429
set_bits_iterator(const BASE_SET &baseSet, size_t index)
Definition base_set.h:433
const size_t & reference
Definition base_set.h:431
set_bits_reverse_iterator & operator++()
Definition base_set.h:481
set_bits_reverse_iterator(const BASE_SET &baseSet, ssize_t index)
Definition base_set.h:473
bool operator==(const set_bits_reverse_iterator &other) const
Definition base_set.h:493
std::bidirectional_iterator_tag iterator_category
Definition base_set.h:467
bool operator!=(const set_bits_reverse_iterator &other) const
Definition base_set.h:488
std::string FmtBin() const
Return a binary string showing contents of this set.
Definition base_set.h:286
set_bits_reverse_iterator set_bits_rbegin() const
Definition base_set.h:514
iterator end()
Definition base_set.h:117
int ParseHex(const std::string &str)
Convert the output of FmtHex() and replaces this set's values with those given in the input string.
Definition base_set.h:358
BASE_SET & flip()
Definition base_set.h:180
const_iterator end() const
Definition base_set.h:119
bool operator<(const BASE_SET &other) const
Definition base_set.h:277
int ParseHex(const char *aStart, int aCount)
Convert the output of FmtHex() and replaces this set's values with those given in the input string.
Definition base_set.h:372
set_bits_iterator set_bits_end() const
Definition base_set.h:512
BASE_SET & reset(size_t pos)
Definition base_set.h:153
BASE_SET(size_t size=64)
Definition base_set.h:121
BASE_SET & operator^=(const BASE_SET &other)
Definition base_set.h:247
BASE_SET & flip(size_t pos)
Definition base_set.h:170
BASE_SET & set(size_t pos, bool value)
Definition base_set.h:136
BASE_SET operator~() const
Definition base_set.h:189
set_bits_reverse_iterator set_bits_rend() const
Definition base_set.h:518
BASE_SET & set()
Definition base_set.h:146
BASE_SET & reset()
Definition base_set.h:163
int compare(const BASE_SET &other) const
Definition base_set.h:271
iterator begin()
Definition base_set.h:116
BASE_SET & set(size_t pos)
Definition base_set.h:126
const_iterator begin() const
Definition base_set.h:118
set_bits_iterator set_bits_begin() const
Definition base_set.h:511
std::string FmtHex() const
Return a hex string showing contents of this set.
Definition base_set.h:312
BASE_SET & operator|=(const BASE_SET &other)
Definition base_set.h:222
BASE_SET & operator&=(const BASE_SET &other)
Definition base_set.h:197
#define KICOMMON_API
Definition kicommon.h:27
int lexicographical_compare_three_way(Container1Iter aC1_first, Container1Iter aC1_last, Container2Iter aC2_first, Container2Iter aC2_last)
Compares two containers lexicographically.
Definition kicad_algo.h:220
STL namespace.
size_t operator()(const BASE_SET &bs) const
Definition base_set.h:551
VECTOR2I end
wxString result
Test unit parsing edge cases and error handling.