You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

553 lines
15 KiB

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