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 along
17 * with this program. If not, see <http://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#include <dynamic_bitset.h>
28
29#include <core/arraydim.h>
30#include <core/kicad_algo.h>
31#include <kicommon.h>
32
33#if defined( _MSC_VER )
34// ssize_t is a POSIX extension
35// wx usually defines it on windows as a helper
36// windows does have SSIZE_T (capital) for the same purpose
37#include <BaseTsd.h>
38typedef SSIZE_T ssize_t;
39#endif
40
41class KICOMMON_API BASE_SET : public sul::dynamic_bitset<uint64_t>
42{
43public:
45 {
46 public:
47 using iterator_category = std::random_access_iterator_tag;
48 using value_type = bool;
49 using difference_type = std::ptrdiff_t;
50 using pointer = void;
51 using reference = bool;
52
53 iterator( BASE_SET* set, size_t pos ) : m_set( set ), m_pos( pos ) {}
54 bool operator*() const { return m_set->test( m_pos ); }
56 {
57 ++m_pos;
58 return *this;
59 }
61 {
62 return iterator( m_set, m_pos + n );
63 }
64 difference_type operator-( const iterator& other ) const
65 {
66 return static_cast<difference_type>(m_pos) - static_cast<difference_type>(other.m_pos);
67 }
68 auto operator<=>( const iterator& ) const = default;
69
70 private:
72 size_t m_pos;
73 };
74
76 {
77 public:
78 using iterator_category = std::random_access_iterator_tag;
79 using value_type = bool;
80 using difference_type = std::ptrdiff_t;
81 using pointer = void;
82 using reference = bool;
83
84 const_iterator( const BASE_SET* set, size_t pos ) : m_set( set ), m_pos( pos ) {}
85 bool operator*() const { return m_set->test( m_pos ); }
87 {
88 ++m_pos;
89 return *this;
90 }
92 {
93 return const_iterator( m_set, m_pos + n );
94 }
96 {
97 return static_cast<difference_type>(m_pos) - static_cast<difference_type>(other.m_pos);
98 }
99 auto operator<=>( const const_iterator& ) const = default;
100
101 private:
103 size_t m_pos;
104 };
105
106 iterator begin() { return iterator(this, 0); }
107 iterator end() { return iterator(this, size()); }
108 const_iterator begin() const { return const_iterator(this, 0); }
109 const_iterator end() const { return const_iterator(this, size()); }
110
111 BASE_SET( size_t size = 64 ) : sul::dynamic_bitset<uint64_t>( size ) {}
112
113 // Overloads for set, reset, and flip operations
114
115 // Set a bit at the specified position
116 BASE_SET& set(size_t pos)
117 {
118 if( pos >= size() )
119 sul::dynamic_bitset<uint64_t>::resize( pos + 1 );
120
121 sul::dynamic_bitset<uint64_t>::set(pos);
122 return *this;
123 }
124
125 // Set a bit at the specified position to a given value
126 BASE_SET& set(size_t pos, bool value)
127 {
128 if( pos >= size() )
129 sul::dynamic_bitset<uint64_t>::resize( pos + 1 );
130
131 sul::dynamic_bitset<uint64_t>::set(pos, value);
132 return *this;
133 }
134
135 // Set all bits to 1
137 {
138 sul::dynamic_bitset<uint64_t>::set();
139 return *this;
140 }
141
142 // Reset (clear) a bit at the specified position
143 BASE_SET& reset(size_t pos)
144 {
145 if( pos >= size() )
146 sul::dynamic_bitset<uint64_t>::resize( pos + 1 );
147
148 sul::dynamic_bitset<uint64_t>::reset(pos);
149 return *this;
150 }
151
152 // Reset (clear) all bits
154 {
155 sul::dynamic_bitset<uint64_t>::reset();
156 return *this;
157 }
158
159 // Flip a bit at the specified position
160 BASE_SET& flip(size_t pos)
161 {
162 if( pos >= size() )
163 sul::dynamic_bitset<uint64_t>::resize( pos + 1 );
164
165 sul::dynamic_bitset<uint64_t>::flip(pos);
166 return *this;
167 }
168
169 // Flip all bits
171 {
172 sul::dynamic_bitset<uint64_t>::flip();
173 return *this;
174 }
175
176 // Overloads for boolean operators
177
178 // Bitwise NOT operator
180 {
181 BASE_SET result(*this);
182 result.flip();
183 return result;
184 }
185
186 // Compound assignment AND operator
188 {
189 sul::dynamic_bitset<uint64_t>::operator&=(other);
190 return *this;
191 }
192
193 // Compound assignment OR operator
195 {
196 sul::dynamic_bitset<uint64_t>::operator|=(other);
197 return *this;
198 }
199
200 // Compound assignment XOR operator
202 {
203 sul::dynamic_bitset<uint64_t>::operator^=(other);
204 return *this;
205 }
206
207 int compare( const BASE_SET& other ) const
208 {
209 return alg::lexicographical_compare_three_way( begin(), end(), other.begin(), other.end() );
210 }
211
212 // Define less-than operator for comparison
213 bool operator<( const BASE_SET& other ) const
214 {
215 return alg::lexicographical_compare_three_way( begin(), end(), other.begin(),
216 other.end() ) < 0;
217 }
218
222 std::string FmtBin() const
223 {
224 std::string ret;
225
226 int bit_count = size();
227
228 for( int bit=0; bit<bit_count; ++bit )
229 {
230 if( bit )
231 {
232 if( !( bit % 8 ) )
233 ret += '|';
234 else if( !( bit % 4 ) )
235 ret += '_';
236 }
237
238 ret += (*this)[bit] ? '1' : '0';
239 }
240
241 // reverse of string
242 return std::string( ret.rbegin(), ret.rend() );
243 }
244
248 std::string FmtHex() const
249 {
250 std::string ret;
251
252 static const char hex[] = "0123456789abcdef";
253
254 size_t nibble_count = ( size() + 3 ) / 4;
255
256 for( size_t nibble = 0; nibble < nibble_count; ++nibble )
257 {
258 unsigned int ndx = 0;
259
260 // test 4 consecutive bits and set ndx to 0-15
261 for( size_t nibble_bit = 0; nibble_bit < 4; ++nibble_bit )
262 {
263 size_t nibble_pos = nibble_bit + ( nibble * 4 );
264 // make sure it's not extra bits that don't exist in the bitset but need to in the
265 // hex format
266 if( nibble_pos >= size() )
267 break;
268
269 if( ( *this )[nibble_pos] )
270 ndx |= ( 1 << nibble_bit );
271 }
272
273 if( nibble && !( nibble % 8 ) )
274 ret += '_';
275
276 assert( ndx < arrayDim( hex ) );
277
278 ret += hex[ndx];
279 }
280
281 // reverse of string
282 return std::string( ret.rbegin(), ret.rend() );
283 }
284
294 int ParseHex( const std::string& str )
295 {
296 return ParseHex( str.c_str(), str.length() );
297 }
298
308 int ParseHex( const char* aStart, int aCount )
309 {
310 BASE_SET tmp(size());
311
312 const char* rstart = aStart + aCount - 1;
313 const char* rend = aStart - 1;
314
315 const int bitcount = size();
316
317 int nibble_ndx = 0;
318
319 while( rstart > rend )
320 {
321 int cc = *rstart--;
322
323 if( cc == '_' )
324 continue;
325
326 int nibble;
327
328 if( cc >= '0' && cc <= '9' )
329 nibble = cc - '0';
330 else if( cc >= 'a' && cc <= 'f' )
331 nibble = cc - 'a' + 10;
332 else if( cc >= 'A' && cc <= 'F' )
333 nibble = cc - 'A' + 10;
334 else
335 break;
336
337 int bit = nibble_ndx * 4;
338
339 for( int ndx=0; bit<bitcount && ndx<4; ++bit, ++ndx )
340 if( nibble & (1<<ndx) )
341 tmp.set( bit );
342
343 if( bit >= bitcount )
344 break;
345
346 ++nibble_ndx;
347 }
348
349 int byte_count = aStart + aCount - 1 - rstart;
350
351 assert( byte_count >= 0 );
352
353 if( byte_count > 0 )
354 *this = tmp;
355
356 return byte_count;
357 }
358
359 // Custom iterator to iterate over set bits
361 {
362 public:
363 using iterator_category = std::forward_iterator_tag;
364 using value_type = size_t;
365 using difference_type = std::ptrdiff_t;
366 using pointer = const size_t*;
367 using reference = const size_t&;
368
369 set_bits_iterator( const BASE_SET& baseSet, size_t index ) :
370 m_baseSet( baseSet ), m_index( index )
371 {
372 advance_to_next_set_bit();
373 }
374
375 size_t operator*() const { return m_index; }
376
378 {
379 ++m_index;
380 advance_to_next_set_bit();
381 return *this;
382 }
383
384 bool operator!=( const set_bits_iterator& other ) const { return m_index != other.m_index; }
385
386 bool operator==( const set_bits_iterator& other ) const { return m_index == other.m_index; }
387
388 protected:
390 {
391 while( m_index < m_baseSet.size() && !m_baseSet.test( m_index ) )
392 ++m_index;
393 }
394
396 size_t m_index;
397 };
398
399 // Custom reverse iterator to iterate over set bits in reverse order
401 {
402 public:
403 using iterator_category = std::bidirectional_iterator_tag;
404 using value_type = ssize_t;
405 using difference_type = std::ptrdiff_t;
406 using pointer = const ssize_t*;
407 using reference = const ssize_t&;
408
409 set_bits_reverse_iterator( const BASE_SET& baseSet, ssize_t index ) :
410 m_baseSet( baseSet ), m_index( index )
411 {
412 advance_to_previous_set_bit();
413 }
414
415 ssize_t operator*() const { return m_index; }
416
418 {
419 --m_index;
420 advance_to_previous_set_bit();
421 return *this;
422 }
423
424 bool operator!=( const set_bits_reverse_iterator& other ) const
425 {
426 return m_index != other.m_index;
427 }
428
429 bool operator==( const set_bits_reverse_iterator& other ) const
430 {
431 return m_index == other.m_index;
432 }
433
434 protected:
436 {
437 while( m_index >= 0 && !m_baseSet.test( m_index ) )
438 {
439 --m_index;
440 }
441 }
442
444 ssize_t m_index;
445 };
446
447 set_bits_iterator set_bits_begin() const { return set_bits_iterator( *this, 0 ); }
448 set_bits_iterator set_bits_end() const { return set_bits_iterator( *this, size() ); }
449
451 {
452 return set_bits_reverse_iterator( *this, size() - 1 );
453 }
455 {
456 return set_bits_reverse_iterator( *this, -1 );
457 }
458
459};
460
461inline BASE_SET operator&( const BASE_SET& lhs, const BASE_SET& rhs )
462{
463 BASE_SET result = lhs;
464 result &= rhs;
465 return result;
466}
467
468inline BASE_SET operator|( const BASE_SET& lhs, const BASE_SET& rhs )
469{
470 BASE_SET result = lhs;
471 result |= rhs;
472 return result;
473}
474
475inline BASE_SET operator^( const BASE_SET& lhs, const BASE_SET& rhs )
476{
477 BASE_SET result = lhs;
478 result ^= rhs;
479 return result;
480}
481
482namespace std
483{
484template <>
485struct hash<BASE_SET>
486{
487 size_t operator()( const BASE_SET& bs ) const
488 {
489 size_t hashVal = 0;
490
491 for( const auto& bit : bs )
492 hashVal = hashVal * 31 + std::hash<int>()( bit );
493
494 return hashVal;
495 }
496};
497} // namespace std
498
499#endif // BASE_SET_H
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Returns # of elements in an array.
Definition: arraydim.h:31
BASE_SET operator|(const BASE_SET &lhs, const BASE_SET &rhs)
Definition: base_set.h:468
BASE_SET operator^(const BASE_SET &lhs, const BASE_SET &rhs)
Definition: base_set.h:475
BASE_SET operator&(const BASE_SET &lhs, const BASE_SET &rhs)
Definition: base_set.h:461
auto operator<=>(const const_iterator &) const =default
std::random_access_iterator_tag iterator_category
Definition: base_set.h:78
const BASE_SET * m_set
Definition: base_set.h:102
const_iterator operator+(difference_type n) const
Definition: base_set.h:91
const_iterator(const BASE_SET *set, size_t pos)
Definition: base_set.h:84
difference_type operator-(const const_iterator &other) const
Definition: base_set.h:95
bool operator*() const
Definition: base_set.h:85
std::ptrdiff_t difference_type
Definition: base_set.h:80
const_iterator & operator++()
Definition: base_set.h:86
auto operator<=>(const iterator &) const =default
iterator & operator++()
Definition: base_set.h:55
difference_type operator-(const iterator &other) const
Definition: base_set.h:64
BASE_SET * m_set
Definition: base_set.h:71
bool operator*() const
Definition: base_set.h:54
iterator(BASE_SET *set, size_t pos)
Definition: base_set.h:53
std::ptrdiff_t difference_type
Definition: base_set.h:49
std::random_access_iterator_tag iterator_category
Definition: base_set.h:47
iterator operator+(difference_type n) const
Definition: base_set.h:60
const size_t * pointer
Definition: base_set.h:366
set_bits_iterator & operator++()
Definition: base_set.h:377
std::forward_iterator_tag iterator_category
Definition: base_set.h:363
bool operator!=(const set_bits_iterator &other) const
Definition: base_set.h:384
bool operator==(const set_bits_iterator &other) const
Definition: base_set.h:386
const BASE_SET & m_baseSet
Definition: base_set.h:395
size_t operator*() const
Definition: base_set.h:375
std::ptrdiff_t difference_type
Definition: base_set.h:365
set_bits_iterator(const BASE_SET &baseSet, size_t index)
Definition: base_set.h:369
const size_t & reference
Definition: base_set.h:367
set_bits_reverse_iterator & operator++()
Definition: base_set.h:417
set_bits_reverse_iterator(const BASE_SET &baseSet, ssize_t index)
Definition: base_set.h:409
bool operator==(const set_bits_reverse_iterator &other) const
Definition: base_set.h:429
std::bidirectional_iterator_tag iterator_category
Definition: base_set.h:403
bool operator!=(const set_bits_reverse_iterator &other) const
Definition: base_set.h:424
std::string FmtBin() const
Return a binary string showing contents of this set.
Definition: base_set.h:222
set_bits_reverse_iterator set_bits_rbegin() const
Definition: base_set.h:450
iterator end()
Definition: base_set.h:107
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:294
BASE_SET & flip()
Definition: base_set.h:170
const_iterator end() const
Definition: base_set.h:109
bool operator<(const BASE_SET &other) const
Definition: base_set.h:213
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:308
set_bits_iterator set_bits_end() const
Definition: base_set.h:448
BASE_SET & reset(size_t pos)
Definition: base_set.h:143
BASE_SET(size_t size=64)
Definition: base_set.h:111
BASE_SET & operator^=(const BASE_SET &other)
Definition: base_set.h:201
BASE_SET & flip(size_t pos)
Definition: base_set.h:160
BASE_SET & set(size_t pos, bool value)
Definition: base_set.h:126
BASE_SET operator~() const
Definition: base_set.h:179
set_bits_reverse_iterator set_bits_rend() const
Definition: base_set.h:454
BASE_SET & set()
Definition: base_set.h:136
BASE_SET & reset()
Definition: base_set.h:153
int compare(const BASE_SET &other) const
Definition: base_set.h:207
iterator begin()
Definition: base_set.h:106
BASE_SET & set(size_t pos)
Definition: base_set.h:116
const_iterator begin() const
Definition: base_set.h:108
set_bits_iterator set_bits_begin() const
Definition: base_set.h:447
std::string FmtHex() const
Return a hex string showing contents of this set.
Definition: base_set.h:248
BASE_SET & operator|=(const BASE_SET &other)
Definition: base_set.h:194
BASE_SET & operator&=(const BASE_SET &other)
Definition: base_set.h:187
#define KICOMMON_API
Definition: kicommon.h:28
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:246
STL namespace.
size_t operator()(const BASE_SET &bs) const
Definition: base_set.h:487