ORIGINAL
Loading...
Searching...
No Matches
bitSet.h
Go to the documentation of this file.
1#ifndef BITSET_H
2#define BITSET_H
3
4#include "array.h"
5#include "couple.h"
6#include "iterationStream.h"
7
8
9namespace original {
16
28 template<typename ALLOC = allocator<bool>>
29 class bitSet final : public baseArray<bool, ALLOC>, public iterationStream<bool, bitSet<ALLOC>>{
33 using underlying_type = u_integer;
34
40 using rebind_alloc_underlying = typename ALLOC::template rebind_alloc<underlying_type>;
41
42 static constexpr integer BLOCK_MAX_SIZE = sizeof(underlying_type) * 8;
43
49
50 u_integer size_;
51
52
59 void bitsetInit(u_integer size);
60
67 [[nodiscard]] static bool getBitFromBlock(underlying_type block_value, integer bit);
68
75 [[nodiscard]] static underlying_type setBitFromBlock(underlying_type block_value, integer bit);
76
83 [[nodiscard]] static underlying_type clearBitFromBlock(underlying_type block_value, integer bit);
84
91 [[nodiscard]] static underlying_type clearHigherBitsFromBlock(underlying_type block_value, integer bit);
92
96 void clearRedundantBits();
97
104 [[nodiscard]] bool getBit(integer bit, integer block) const;
105
111 void setBit(integer bit, integer block);
112
118 void clearBit(integer bit, integer block);
119
126 void writeBit(integer bit, integer block, bool value);
127
133 static couple<u_integer, integer> toInnerIdx(integer index);
134
141 static integer toOuterIdx(u_integer cur_block, integer cur_bit);
142
143 public:
144
152 class Iterator final : public baseIterator<bool> {
153 mutable integer cur_bit;
154 mutable integer cur_block;
155 mutable underlying_type* block_;
156 const bitSet* container_;
157
165 explicit Iterator(integer bit, integer block, underlying_type* block_p, const bitSet* container);
166
172 bool equalPtr(const iterator *other) const override;
173
174 public:
175 friend class bitSet;
176
181 Iterator* clone() const override;
182
187 [[nodiscard]] bool hasNext() const override;
188
193 [[nodiscard]] bool hasPrev() const override;
194
200 bool atPrev(const iterator *other) const override;
201
207 bool atNext(const iterator *other) const override;
208
212 void next() const override;
213
217 void prev() const override;
218
223 Iterator* getPrev() const override;
224
229 Iterator* getNext() const override;
230
235 void operator+=(integer steps) const override;
236
241 void operator-=(integer steps) const override;
242
248 integer operator-(const iterator& other) const override;
249
254 bool& get() override;
255
260 [[nodiscard]] std::string className() const override;
261
266 [[nodiscard]] bool get() const override;
267
272 void set(const bool &data) override;
273
278 [[nodiscard]] bool isValid() const override;
279 };
280
288 explicit bitSet(u_integer size, ALLOC allocator = ALLOC{});
289
294 bitSet(const std::initializer_list<bool>& lst);
295
302 bitSet(const bitSet& other);
303
311 bitSet& operator=(const bitSet& other);
312
320 bitSet(bitSet&& other) noexcept;
321
330 bitSet& operator=(bitSet&& other) noexcept;
331
336 [[nodiscard]] u_integer count() const;
337
343 [[nodiscard]] bitSet resize(u_integer new_size) const;
344
349 [[nodiscard]] u_integer size() const override;
350
355 [[nodiscard]] Iterator* begins() const override;
356
361 [[nodiscard]] Iterator* ends() const override;
362
368 [[nodiscard]] bool get(integer index) const override;
369
375 bool& operator[](integer index) override;
376
382 void set(integer index, const bool &e) override;
383
389 [[nodiscard]] u_integer indexOf(const bool &e) const override;
390
391 ~bitSet() override = default;
392
398 bitSet& operator&=(const bitSet& other);
399
405 bitSet& operator|=(const bitSet& other);
406
412 bitSet& operator^=(const bitSet& other);
413
418 [[nodiscard]] std::string className() const override;
419
420
421 template<typename Callback = transform<bool>>
422 void forEach(Callback operation = Callback{}) = delete;
423
430 template<typename ALLOC_>
432
439 template<typename ALLOC_>
441
448 template<typename ALLOC_>
450
456 template<typename ALLOC_>
458 };
459
460 template<typename ALLOC_>
462
463 template<typename ALLOC_>
465
466 template<typename ALLOC_>
468
469 template<typename ALLOC_>
471}
472
473 template<typename ALLOC>
474 auto original::bitSet<ALLOC>::bitsetInit(const u_integer size) -> void
475 {
476 this->map = array<underlying_type, rebind_alloc_underlying>((size + BLOCK_MAX_SIZE - 1) / BLOCK_MAX_SIZE, rebind_alloc_underlying{});
477 this->size_ = size;
478 }
479
480 template<typename ALLOC>
481 auto original::bitSet<ALLOC>::getBitFromBlock(const underlying_type block_value, const integer bit) -> bool {
482 return block_value & static_cast<underlying_type>(1) << bit;
483 }
484
485 template<typename ALLOC>
486 auto original::bitSet<ALLOC>::setBitFromBlock(const underlying_type block_value, const integer bit) -> underlying_type {
487 return block_value | static_cast<underlying_type>(1) << bit;
488 }
489
490 template<typename ALLOC>
491 auto original::bitSet<ALLOC>::clearBitFromBlock(const underlying_type block_value, const integer bit) -> underlying_type {
492 return block_value & ~(static_cast<underlying_type>(1) << bit);
493 }
494
495 template<typename ALLOC>
496 auto original::bitSet<ALLOC>::clearHigherBitsFromBlock(const underlying_type block_value, const integer bit) -> underlying_type
497 {
498 return block_value & (static_cast<underlying_type>(1) << (bit + 1)) - static_cast<underlying_type>(1);
499 }
500
501 template<typename ALLOC>
502 auto original::bitSet<ALLOC>::clearRedundantBits() -> void
503 {
504 this->map.set(-1, clearHigherBitsFromBlock(this->map.get(-1), toInnerIdx(this->size() - 1).second()));
505 }
506
507 template<typename ALLOC>
508 auto original::bitSet<ALLOC>::getBit(const integer bit, const integer block) const -> bool {
509 return getBitFromBlock(this->map.get(block), bit);
510 }
511
512 template<typename ALLOC>
513 auto original::bitSet<ALLOC>::setBit(const integer bit, const integer block) -> void {
514 this->map.set(block, setBitFromBlock(this->map.get(block), bit));
515 }
516
517 template<typename ALLOC>
518 auto original::bitSet<ALLOC>::clearBit(const integer bit, const integer block) -> void {
519 this->map.set(block, clearBitFromBlock(this->map.get(block), bit));
520 }
521
522 template<typename ALLOC>
523 auto original::bitSet<ALLOC>::writeBit(const integer bit, const integer block, const bool value) -> void {
524 value ? this->setBit(bit, block) : this->clearBit(bit, block);
525 }
526
527 template<typename ALLOC>
528 auto original::bitSet<ALLOC>::toInnerIdx(const integer index) -> couple<u_integer, integer> {
529 return {static_cast<u_integer>(index / BLOCK_MAX_SIZE), index % BLOCK_MAX_SIZE};
530 }
531
532 template<typename ALLOC>
533 auto original::bitSet<ALLOC>::toOuterIdx(const u_integer cur_block, const integer cur_bit) -> integer
534 {
535 return cur_block * BLOCK_MAX_SIZE + cur_bit;
536 }
537
538 template<typename ALLOC>
539 original::bitSet<ALLOC>::Iterator::Iterator(const integer bit, const integer block, underlying_type* block_p, const bitSet* container)
540 : cur_bit(bit), cur_block(block), block_(block_p), container_(container) {}
541
542 template<typename ALLOC>
543 auto original::bitSet<ALLOC>::Iterator::equalPtr(const iterator *other) const -> bool {
544 auto* other_it = dynamic_cast<const Iterator*>(other);
545 return other_it != nullptr
546 && this->cur_bit == other_it->cur_bit
547 && this->cur_block == other_it->cur_block;
548 }
549
550 template<typename ALLOC>
552 return new Iterator(*this);
553 }
554
555 template<typename ALLOC>
557 return toOuterIdx(this->cur_block, this->cur_bit) < this->container_->size() - 1;
558 }
559
560 template<typename ALLOC>
562 return toOuterIdx(this->cur_block, this->cur_bit) > 0;
563 }
564
565 template<typename ALLOC>
566 auto original::bitSet<ALLOC>::Iterator::atPrev(const iterator *other) const -> bool {
567 auto* other_it = dynamic_cast<const Iterator*>(other);
568 if (other_it == nullptr)
569 return false;
570 return this->operator-(*other_it) == -1;
571 }
572
573 template<typename ALLOC>
574 auto original::bitSet<ALLOC>::Iterator::atNext(const iterator *other) const -> bool {
575 auto* other_it = dynamic_cast<const Iterator*>(other);
576 if (other_it == nullptr)
577 return false;
578 return this->operator-(*other_it) == 1;
579 }
580
581 template<typename ALLOC>
583 this->operator+=(1);
584 }
585
586 template<typename ALLOC>
588 this->operator-=(1);
589 }
590
591 template<typename ALLOC>
593 if (!this->isValid()) throw outOfBoundError();
594 auto* it = this->clone();
595 it->prev();
596 return it;
597 }
598
599 template<typename ALLOC>
601 if (!this->isValid()) throw outOfBoundError();
602 auto* it = this->clone();
603 it->next();
604 return it;
605 }
606
607 template<typename ALLOC>
609 {
610 auto new_idx = toInnerIdx(toOuterIdx(this->cur_block, this->cur_bit) + steps);
611 this->cur_block = new_idx.first();
612 this->cur_bit = new_idx.second();
613 }
614
615 template<typename ALLOC>
617 {
618 auto new_idx = toInnerIdx(toOuterIdx(this->cur_block, this->cur_bit) - steps);
619 this->cur_block = new_idx.first();
620 this->cur_bit = new_idx.second();
621 }
622
623 template<typename ALLOC>
625 auto* other_it = dynamic_cast<const Iterator*>(&other);
626 if (other_it == nullptr)
627 return this > &other ?
628 std::numeric_limits<integer>::max() :
629 std::numeric_limits<integer>::min();
630 if (this->container_ != other_it->container_)
631 return this->container_ > other_it->container_ ?
632 std::numeric_limits<integer>::max() :
633 std::numeric_limits<integer>::min();
634
635 return toOuterIdx(this->cur_block, this->cur_bit) - toOuterIdx(other_it->cur_block, other_it->cur_bit);
636 }
637
638 template<typename ALLOC>
642
643 template<typename ALLOC>
645 return "bitSet::Iterator";
646 }
647
648 template<typename ALLOC>
650 {
651 if (!this->isValid()) throw outOfBoundError();
652 return getBitFromBlock(*this->block_, this->cur_bit);
653 }
654
655 template<typename ALLOC>
656 auto original::bitSet<ALLOC>::Iterator::set(const bool &data) -> void {
657 if (!this->isValid()) throw outOfBoundError();
658 *this->block_ = data ?
659 setBitFromBlock(*this->block_, this->cur_bit) : clearBitFromBlock(*this->block_, this->cur_bit);
660 }
661
662 template<typename ALLOC>
664 const auto outer = toOuterIdx(this->cur_block, this->cur_bit);
665 return outer >= 0 && outer < this->container_->size();
666 }
667
668 template<typename ALLOC>
670 : baseArray<bool, ALLOC>(std::move(allocator)), size_() {
671 this->bitsetInit(size);
672 }
673
674 template<typename ALLOC>
675 original::bitSet<ALLOC>::bitSet(const std::initializer_list<bool>& lst) : bitSet(lst.size()) {
676 u_integer i = 0;
677 for (const auto& e : lst) {
678 auto idx = toInnerIdx(i);
679 this->writeBit(idx.second(), idx.first(), e);
680 i += 1;
681 }
682 }
683
684 template<typename ALLOC>
686 this->operator=(other);
687 }
688
689 template<typename ALLOC>
691 if (this == &other) return *this;
692 this->map = other.map;
693 this->size_ = other.size_;
694 if constexpr (ALLOC::propagate_on_container_copy_assignment::value){
695 this->allocator = other.allocator;
696 }
697 return *this;
698 }
699
700 template<typename ALLOC>
702 {
703 this->operator=(std::move(other));
704 }
705
706 template<typename ALLOC>
708 {
709 if (this == &other)
710 return *this;
711
712 this->map = std::move(other.map);
713 this->size_ = other.size_;
714 if constexpr (ALLOC::propagate_on_container_move_assignment::value){
715 this->allocator = other.allocator;
716 }
717 other.bitsetInit(0);
718 return *this;
719 }
720
721 template<typename ALLOC>
723 u_integer count = 0;
724 for (const auto& e : this->map) {
725 auto n = e;
726 while (n) {
727 n &= n - 1;
728 count += 1;
729 }
730 }
731 return count;
732 }
733
734 template<typename ALLOC>
735 auto original::bitSet<ALLOC>::resize(const u_integer new_size) const -> bitSet {
736 if (this->size() == new_size) {
737 return *this;
738 }
739
740 auto nb = bitSet(new_size);
741 const u_integer blocks_min = min(nb.map.size(),
742 this->map.size());
743 for (u_integer i = 0; i < blocks_min; i++) {
744 nb.map.set(i, this->map.get(i));
745 }
746 nb.clearRedundantBits();
747 return nb;
748 }
749
750 template<typename ALLOC>
752 {
753 return this->size_;
754 }
755
756 template<typename ALLOC>
758 return new Iterator(0, 0, &this->map.data(), this);
759 }
760
761 template<typename ALLOC>
763 return new Iterator(toInnerIdx(this->size() - 1).second(), this->map.size() - 1,
764 &this->map.data() + this->map.size() - 1, this);
765 }
766
767 template<typename ALLOC>
768 auto original::bitSet<ALLOC>::get(integer index) const -> bool {
769 if (this->indexOutOfBound(index)) throw outOfBoundError();
770 index = this->parseNegIndex(index);
771 auto idx = toInnerIdx(index);
772 return this->getBit(idx.second(), idx.first());
773 }
774
775 template<typename ALLOC>
779
780 template<typename ALLOC>
781 auto original::bitSet<ALLOC>::set(integer index, const bool &e) -> void {
782 if (this->indexOutOfBound(index)) throw outOfBoundError();
783 index = this->parseNegIndex(index);
784 auto idx = toInnerIdx(index);
785 this->writeBit(idx.second(), idx.first(), e);
786 }
787
788 template<typename ALLOC>
789 auto original::bitSet<ALLOC>::indexOf(const bool &e) const -> u_integer {
790 for (u_integer i = 0; i < this->size(); i++) {
791 if (auto idx = toInnerIdx(i);
792 e == this->getBit(idx.second(), idx.first())) {
793 return i;
794 }
795 }
796 return this->size();
797 }
798
799 template<typename ALLOC>
801 if (this->size() != other.size()) {
802 const auto resized = other.resize(this->size());
803 for (u_integer i = 0; i < this->map.size(); i++) {
804 this->map.set(i, this->map.get(i) & resized.map.get(i));
805 }
806 }else {
807 for (u_integer i = 0; i < this->map.size(); i++) {
808 this->map.set(i, this->map.get(i) & other.map.get(i));
809 }
810 }
811 return *this;
812 }
813
814 template<typename ALLOC>
816 if (this->size() != other.size()) {
817 const auto resized = other.resize(this->size());
818 for (u_integer i = 0; i < this->map.size(); i++) {
819 this->map.set(i, this->map.get(i) | resized.map.get(i));
820 }
821 }else {
822 for (u_integer i = 0; i < this->map.size(); i++) {
823 this->map.set(i, this->map.get(i) | other.map.get(i));
824 }
825 }
826 return *this;
827 }
828
829 template<typename ALLOC>
831 if (this->size() != other.size()) {
832 const auto resized = other.resize(this->size());
833 for (u_integer i = 0; i < this->map.size(); i++) {
834 this->map.set(i, this->map.get(i) ^ resized.map.get(i));
835 }
836 }else {
837 for (u_integer i = 0; i < this->map.size(); i++) {
838 this->map.set(i, this->map.get(i) ^ other.map.get(i));
839 }
840 }
841 return *this;
842 }
843
844 template<typename ALLOC>
845 auto original::bitSet<ALLOC>::className() const -> std::string {
846 return "bitSet";
847 }
848
849 template<typename ALLOC_>
850 auto original::operator&(const bitSet<ALLOC_> &lbs, const bitSet<ALLOC_> &rbs) -> bitSet<ALLOC_> {
851 bitSet bs(lbs);
852 return bs &= rbs;
853 }
854
855 template<typename ALLOC_>
856 auto original::operator|(const bitSet<ALLOC_> &lbs, const bitSet<ALLOC_> &rbs) -> bitSet<ALLOC_> {
857 bitSet bs(lbs);
858 return bs |= rbs;
859 }
860
861 template<typename ALLOC_>
862 auto original::operator^(const bitSet<ALLOC_> &lbs, const bitSet<ALLOC_> &rbs) -> bitSet<ALLOC_> {
863 bitSet bs(lbs);
864 return bs ^= rbs;
865 }
866
867 template<typename ALLOC_>
869 bitSet nbs(bs);
870 for (u_integer i = 0; i < nbs.map.size(); i++) {
871 nbs.map.set(i, ~nbs.map.get(i));
872 }
873 nbs.clearRedundantBits();
874 return nbs;
875 }
876
877#endif //BITSET_H
Provides the array class for a fixed-size container with random access.
Default memory allocator using allocators utilities.
Definition allocator.h:154
A fixed-size array container with random access.
Definition array.h:41
void set(integer index, const TYPE &e) override
Sets the value of an element at the specified index.
Definition array.h:411
TYPE get(integer index) const override
Retrieves an element at a specified index.
Definition array.h:393
TYPE & data() const
Returns a reference to the first element of the array.
Definition array.h:388
u_integer size() const override
Returns the size of the array.
Definition array.h:382
Base class for fixed-size serial containers.
Definition baseArray.h:43
A base class for basic iterators.
Definition iterator.h:259
An iterator for traversing the bits in a bitSet.
Definition bitSet.h:152
bool hasPrev() const override
Checks if there is a previous element.
Definition bitSet.h:561
bool hasNext() const override
Checks if there is a next element.
Definition bitSet.h:556
Iterator * getPrev() const override
Gets the previous iterator.
Definition bitSet.h:592
bool atNext(const iterator *other) const override
Checks if the iterator is at the next element.
Definition bitSet.h:574
bool & get() override
Gets the value of the current bit.
Definition bitSet.h:639
void next() const override
Moves the iterator to the next element.
Definition bitSet.h:582
Iterator * clone() const override
Clones the iterator.
Definition bitSet.h:551
bool atPrev(const iterator *other) const override
Checks if the iterator is at the previous element.
Definition bitSet.h:566
std::string className() const override
Returns the class name of this iterator.
Definition bitSet.h:644
void operator+=(integer steps) const override
Advances the iterator by the given number of steps.
Definition bitSet.h:608
integer operator-(const iterator &other) const override
Computes the distance between two iterators.
Definition bitSet.h:624
void operator-=(integer steps) const override
Moves the iterator backward by the given number of steps.
Definition bitSet.h:616
void set(const bool &data) override
Sets the value of the current bit.
Definition bitSet.h:656
void prev() const override
Moves the iterator to the previous element.
Definition bitSet.h:587
bool isValid() const override
Checks if the iterator is valid.
Definition bitSet.h:663
Iterator * getNext() const override
Gets the next iterator.
Definition bitSet.h:600
A class representing a set of bits, offering functionality to manipulate and query individual bits.
Definition bitSet.h:29
Iterator * begins() const override
Gets the iterator to the beginning of the bitSet.
Definition bitSet.h:757
friend bitSet< ALLOC_ > operator^(const bitSet< ALLOC_ > &lbs, const bitSet< ALLOC_ > &rbs)
Performs a bitwise XOR operation between two bitSets.
bitSet & operator|=(const bitSet &other)
Performs a bitwise OR operation between two bitSets.
Definition bitSet.h:815
u_integer indexOf(const bool &e) const override
Finds the index of the first occurrence of a specific value.
Definition bitSet.h:789
bitSet & operator&=(const bitSet &other)
Performs a bitwise AND operation between two bitSets.
Definition bitSet.h:800
bitSet(u_integer size, ALLOC allocator=ALLOC{})
Constructs a bitSet with the given size.
Definition bitSet.h:669
Iterator * ends() const override
Gets the iterator to the end of the bitSet.
Definition bitSet.h:762
bool & operator[](integer index) override
Gets the reference of a specific bit by index.
Definition bitSet.h:776
void set(integer index, const bool &e) override
Sets the value of a specific bit by index.
Definition bitSet.h:781
bitSet & operator^=(const bitSet &other)
Performs a bitwise XOR operation between two bitSets.
Definition bitSet.h:830
u_integer size() const override
Gets the size of the bitSet.
Definition bitSet.h:751
bitSet resize(u_integer new_size) const
Resizes the bitSet to the given size.
Definition bitSet.h:735
bool get(integer index) const override
Gets the value of a specific bit by index.
Definition bitSet.h:768
friend bitSet< ALLOC_ > operator&(const bitSet< ALLOC_ > &lbs, const bitSet< ALLOC_ > &rbs)
Performs a bitwise AND operation between two bitSets.
u_integer count() const
Counts the number of bits set to true.
Definition bitSet.h:722
friend bitSet< ALLOC_ > operator~(const bitSet< ALLOC_ > &bs)
Performs a bitwise NOT operation on a bitSet.
friend bitSet< ALLOC_ > operator|(const bitSet< ALLOC_ > &lbs, const bitSet< ALLOC_ > &rbs)
Performs a bitwise OR operation between two bitSets.
std::string className() const override
Gets the class name for the bitSet.
Definition bitSet.h:845
bitSet & operator=(const bitSet &other)
Copy assignment operator.
Definition bitSet.h:690
Abstract base class for containers.
Definition container.h:28
Container for two heterogeneous elements.
Definition couple.h:34
A stream class that allows iteration, comparison, and printing.
Definition iterationStream.h:33
Base iterator interface that supports common operations for iteration.
Definition iterator.h:35
Exception for container index out-of-range errors.
Definition error.h:84
bool indexOutOfBound(integer index) const
Checks if the provided index is out of bounds.
Definition serial.h:133
integer parseNegIndex(integer index) const
Converts negative indices into valid positive indices.
Definition serial.h:140
Exception for unimplemented method calls.
Definition error.h:123
Generic pair container implementation.
Provides functionality for an iteration stream.
Main namespace for the project Original.
Definition algorithms.h:21
TYPE min(TYPE a, TYPE b)
Returns the smaller of two given values.
std::uint32_t u_integer
32-bit unsigned integer type for sizes/indexes
Definition config.h:17
auto operator-(const iterator< T > &it, integer steps) -> iterator< T > *
Subtracts a number of steps from the iterator's current position and returns a new iterator.
std::int64_t integer
64-bit signed integer type for arithmetic operations
Definition config.h:15
bitSet< ALLOC_ > operator^(const bitSet< ALLOC_ > &lbs, const bitSet< ALLOC_ > &rbs)
bitSet< ALLOC_ > operator~(const bitSet< ALLOC_ > &bs)
bitSet< ALLOC_ > operator&(const bitSet< ALLOC_ > &lbs, const bitSet< ALLOC_ > &rbs)
bitSet< ALLOC_ > operator|(const bitSet< ALLOC_ > &lbs, const bitSet< ALLOC_ > &rbs)