В этом задании необходимо реализовать структуру данных, представляющую собой последовательность бит, с поддержкой итерирования по ним, а также побитовых операций.
- Размер известен в момент конструирования и далее не меняется (кроме как через присваивающие операторы и сдвиги).
- Компактность: количество памяти, используемое под
bitset
, не должно превышатьsize + C
бит, гдеsize
— количество хранимых битов, аC
— какая-то константа, не зависящая отsize
. - Об исключениях и гарантиях, связанных с ними, в этом задании можно не задумываться.
- Поддержка семантики перемещения не требуется.
Помимо непосредственно класса bitset
, вам понадобится реализовать:
В качестве категории стоит выбрать random-access.
Для итераторов не нужно реализовывать operator->
(всё равно он не имеет смысла для bool
). При этом type member pointer
у итератора можно оставить равным void
.
Из-за этих упрощений получившийся итератор, вероятно, не будет строго удовлетворять требованиям LegacyForwardIterator, однако будет удовлетворять требованиям итераторов нового образца (forward_iterator) из C++20.
View — это легковесный объект, который ссылается на какой-то диапазон значений (не владея им), и по которому можно итерироваться. Часто он может быть представлен парой итераторов.
View для битсета интересен тем, что над ним тоже может иметь смысл проводить некоторые операции, в том числе побитовые. Для создания view
используется bitset::subview(offset, count)
или конструкторы view
.
Поскольку биты хранятся упакованно, возникают проблемы с тем, что возвращать из bitset::operator[]
. Несложно понять, что с учётом этого требования это не сможет быть bool &
.
Для решения этой проблемы предлагается в качестве bitset::reference
использовать вспомогательный класс, который поддерживает следующие операции:
bs[i]
— неявно приводится кbool
;bs[i] = false
— оператор присваивания отbool
для изменения бита на заданное значение;bs[i].flip()
— инвертировать значение бита на обратное (для неконстантной ссылки).
Обратите внимание, что поддержка &bs[i]
не требуется, что даёт некоторую свободу для выбора типов для reference
и const_reference
.
bitset()
— пустая последовательность битов;bitset(std::size_t size, bool value)
—size
битов, каждый из которых равенvalue
;bitset(const bitset& other)
— конструктор копирования;bitset(std::string_view str)
— на основе строки, состоящей из символов'0'
и'1'
;bitset(const const_view& other)
— копия переданногоview
;bitset(const_iterator start, const_iterator end)
— копия последовательности битов заданной двумя итераторами.
operator=(const bitset& other)
— оператор копирующего присваивания;operator=(std::string_view other)
— см. аналогичный конструктор;operator=(const const_view& other)
— см. аналогичный конструктор.
operator&=(const const_view& other)
— применить к каждому биту побитовое "и", где в качестве второго операнда служит соответствующий бит изother
;operator|=(const const_view& other)
— аналогичноoperator&=
, но с побитовым "или";operator^=(const const_view& other)
— аналогичноoperator&=
, но с побитовым "xor";operator<<=(std::size_t count)
— битовый сдвиг влево наcount
;operator>>=(std::size_t count)
— битовый сдвиг вправо наcount
;flip()
— инвертировать все биты;set()
— установить все биты в1
;reset()
— установить все биты в0
.
bitset operator&(const bitset& lhs, const bitset& rhs)
— побитовое "и";bitset operator|(const bitset& lhs, const bitset& rhs)
— побитовое "или";bitset operator^(const bitset& lhs, const bitset& rhs)
— побитовый "xor";bitset operator~(const bitset& bs)
— побитовая инверсия;bitset operator<<(const bitset& bs, std::size_t count)
— битовый сдвиг влевоbs
наcount
;bitset operator>>(const bitset& bs, std::size_t count)
— битовый сдвиг вправоbs
наcount
.
Здесь и в предыдущем пункте для побитовых операций над двумя bitset
-ами поведение определено лишь при равенстве их размеров.
reference operator[](std::size_t index)
— возвращает прокси-объект на бит с индексомindex
(отсчитывая от старшего);begin()
,end()
— итераторы на первый бит и на бит после последнего соответственно;bool all()
— правда ли, что все биты равны1
;bool any()
— правда ли, что хотя бы один бит равен1
;std::size_t count()
— количество битов, равных1
;operator==
,operator!=
— сравнение на равенство.
void swap(bitset& other)
— поменять местами состояния текущегоbitset
иother
;std::size_t size()
— текущее количество хранимых битов;bool empty()
— пустой ли этоbitset
;subview(std::size_t offset = 0, std::size_t count = npos)
— получить view:- пустой, если
offset > size()
; - на
[offset, offset + count)
, еслиoffset + count <= size()
; - на
[offset, size())
, еслиoffset + count > size()
.
- пустой, если
void swap(bitset& lhs, bitset& rhs)
— поменять местами состоянияlhs
иrhs
;std::string to_string(const bitset& bs)
— перевод в строку из'0'
и'1'
;std::ostream& operator<<(std::ostream& out, const bitset& bs)
— вывод в поток выводаout
, возвращает исходный поток.
- Копирующий конструктор;
- Конструктор от двух итераторов;
- Оператор копирующего присваивания;
- Неявное конструирование из ссылки на
bitset
.
Все те же методы, что и у bitset
, если они имеют смысл.
Присутствуют как в bitset
, так и в views:
value_type
reference
const_reference
iterator
const_iterator
view
const_view
word_type
— тип, использующийся для разрядов (не менее 32 бит)
- Разбивайте решение на файлы;
- По возможности (если это не шаблонный код) выносите реализации из хэдера;
- Выносите часто использующиеся конструкции в именованные сущности;
- Подумайте о том, как можно минимизировать количество повторяющегося кода;
- Не пренебрегайте спецификаторами доступа.