В этом задании необходимо реализовать структуру данных, представляющую собой последовательность бит, с поддержкой итерирования по ним, а также побитовых операций.
- Размер известен в момент конструирования и далее не меняется (кроме как через присваивающие операторы и сдвиги).
- Компактность: количество памяти, используемое под
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
и ConstReference
.
BitSet()
— пустая последовательность битов;BitSet(std::size_t size, bool value)
—size
битов, каждый из которых равенvalue
;BitSet(const BitSet& other)
— конструктор копирования;BitSet(std::string_view str)
— на основе строки, состоящей из символов'0'
и'1'
;BitSet(const ConstView& other)
— копия переданногоview
;BitSet(ConstIterator start, ConstIterator end)
— копия последовательности битов заданной двумя итераторами.
operator=(const BitSet& other)
— оператор копирующего присваивания;operator=(std::string_view other)
— см. аналогичный конструктор;operator=(const ConstView& other)
— см. аналогичный конструктор.
Здесь и далее для побитовых операций над двумя BitSet
-ами (а также View
, см. далее) поведение определено лишь при равенстве их размеров (поддержка операций над операндами различной длины не нужна).
operator&=(const ConstView& other)
— применить к каждому биту побитовое "и", где в качестве второго операнда служит соответствующий бит изother
;operator|=(const ConstView& other)
— аналогичноoperator&=
, но с побитовым "или";operator^=(const ConstView& 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
.
Reference operator[](std::size_t index)
— возвращает прокси-объект на бит с индексомindex
(отсчитывая от старшего);begin()
,end()
— итераторы на первый бит и на бит после последнего соответственно;bool all()
— правда ли, что все биты равны1
;bool any()
— правда ли, что хотя бы один бит равен1
;std::size_t count()
— количество битов, равных1
;operator==
,operator!=
— сравнение на равенство.
Обратите внимание, что операции all
и any
должны поддерживать short circuit evaluation, то есть нужно разбирать не все биты, а только необходимый для ответа префикс.
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
, возвращает исходный поток.
to_string
и operator<<
должны выводить непосредственно битовое представление без каких-либо префиксов или особого форматирования:
std::string_view bs_str = "0101";
ct::BitSet bs(bs_str);
std::string str = ct::to_string(bs);
// str == "0101";
std::cout << bs << std::endl;
// prints to standard output:
// 0101
- Копирующий конструктор;
- Конструктор от двух итераторов;
- Оператор копирующего присваивания;
- Неявное конструирование из ссылки на
BitSet
.
Все те же методы, что и у BitSet
, если они имеют смысл:
operator[]
;begin
,end
;all
,any
,count
;size
,empty
;swap
;subview
.
Модифицирующие операции над битами в неконстантном случае:
set
,reset
,flip
;- операторы
&=
,|=
,^=
.
А также связанные свободные функции:
operator==
,operator!=
;swap
;- операторы битовых операций:
&
,|
,^
,~
,<<
,>>
; - форматирующие функции:
to_string
,operator<<
.
Обратите внимание, что операторы сравнения должны поддерживать как сравнение двух BitSet
или двух View
между собой, так и сравнение BitSet
с View
.
Присутствуют как в BitSet
, так и в views:
Value
Reference
ConstReference
Iterator
ConstIterator
View
ConstView
Word
— тип, использующийся для разрядов (не менее 32 бит)
- При массовом применении операций работа с отдельными битами может оказаться неэффективной, вместо этого лучше оперировать сразу разрядами (Word);
- Разбивайте решение на файлы;
- По возможности (если это не шаблонный код) выносите реализации из хэдера;
- Выносите часто использующиеся конструкции в именованные сущности;
- Подумайте о том, как можно минимизировать количество повторяющегося кода;
- Не пренебрегайте спецификаторами доступа.