Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 89 additions & 75 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,73 +1,107 @@
# -containers-
# s21_containers

Групповой проект для реализации stl c++ контейнеров.
Учебная C++17-библиотека STL-like контейнеров, реализованная с нуля в рамках School 21. Проект показывает работу с шаблонами, итераторами, управлением памятью, красно-черным деревом, unit-тестами и CI-проверками.

На шестой день отец программирования подумал о контейнерах и решил, что они хороши...
## Что реализовано

Эта библиотека была разработана с нуля выходцами из языка C, но, к сожалению, не за 6 дней, а за месяц и вкдючает следующие контейнеры: `list` (список), `map` (словарь), `queue` (очередь), `set` (множество), `stack` (стек) и `vector` (вектор).
| Контейнер | Реализация | Что проверяется |
| --- | --- | --- |
| `s21::vector` | динамический массив | доступ по индексу, capacity, insert/erase, итераторы |
| `s21::list` | двусвязный список | вставка/удаление, splice/merge/sort, двунаправленные итераторы |
| `s21::map` | ассоциативный контейнер на красно-черном дереве | вставка, поиск, доступ по ключу, балансировка |
| `s21::set` | множество на красно-черном дереве | уникальность ключей, поиск, insert/erase |
| `s21::stack` | LIFO-адаптер | push/pop/top, размер, пустое состояние |
| `s21::queue` | FIFO-адаптер | push/pop/front/back, размер, пустое состояние |

![palpatin](./materials/imgs/palpatin.png)
Код живет в `src/`, публичная точка подключения - [`src/s21_containers.h`](src/s21_containers.h).

## Информационное вступление
## Быстрый запуск

Контейнеры - это как коробки, в которые вы складываете свои игрушки, но в мире C++. Вот вам аналогия: представьте, что у вас есть коробки для хранения всего на свете. Но эти коробки разные: одни для книжек (вектор), другие для уникальных коллекционных фигурок (множество), а третьи для быстрого доступа к конфетам по имени (словарь). Каждый контейнер обладает уникальными суперсилами и идеально подходит для разных задач.
```bash
cd src
make build
make test
```

### Коробочные суперы
Полный локальный quality gate:

![deeper](./materials/imgs/deeper.png)
```bash
cd src
make style-check
make gcov_report
make valgrind
```

## Проверки качества

- `GTest` покрывает поведение контейнеров и итераторов.
- `clang-format` проверяет стиль по Google Style.
- `gcov_report` собирает покрытие и падает, если lines/functions coverage ниже 85%.
- `valgrind` проверяет утечки и ошибки работы с памятью.
- GitHub Actions запускает build, style-check, unit tests, coverage report и Valgrind.

## Структура проекта

```text
src/
s21_containers.h единая точка подключения
vector/s21_vector.h динамический массив
list/s21_list.h двусвязный список
map/s21_map.h map API
set/s21_set.h set API
rb-tree/s21_tree.h красно-черное дерево для map/set
stack/s21_stack.h stack adapter
queue/s21_queue.h queue adapter
unit_tests/ GTest-набор
Makefile build/test/coverage/valgrind/style targets
```

- **List**: Настоящий акробат, позволяет легко вставлять и удалять элементы в любом месте. В нашем случае - цирковой артист, который держит баланс в любой ситуации.
- **Map**: Великий хранитель пар "ключ-значение". Как библиотекарь, который всегда знает, где лежит нужная книга.
- **Queue**: Организованный как очередь за хот-догами на стадионе - обслуживает первого пришедшего.
- **Set**: Как элитный клуб - здесь только уникальные элементы. Никаких повторов, только эксклюзив!
- **Stack**: Магическая шляпа фокусника - достаешь то, что положил последним.
- **Vector**: Массив на стероидах - быстрый доступ к любому элементу и динамическое расширение по мере необходимости.
## Инженерный фокус

### Итераторы
- Не копировать STL-реализации, а воспроизвести контракт контейнеров через собственные структуры данных.
- Держать API близким к стандартным контейнерам C++, чтобы тесты можно было сопоставлять с ожидаемым STL-поведением.
- Проверять не только happy path, но и граничные случаи: пустые контейнеры, iterator boundary, erase/insert, copy/move behavior.
- Для `map` и `set` использовать сбалансированное дерево, а не линейный поиск.
- Собирать проект одной командой и держать CI как обязательный safety net.

## Ограничения

Итераторы - это маленькие помощники, которые помогут вам обойти все ваши контейнеры. Они как указатели на место в книге, которые показывают вам, где находится нужный элемент. Вы можете перемещать их вперед, назад и даже сравнивать друг с другом.
Это учебная библиотека, а не production-замена STL. Она полезна как демонстрация алгоритмов, структуры памяти и дисциплины тестирования, но в прикладных C++ сервисах стандартная библиотека остается предпочтительным выбором.

Итераторы поддерживают следующие трюки:
## Исторический контекст

- `*iter`: Получить элемент, на который указывает итератор.
- `++iter`: Перейти к следующему элементу.
- `--iter`: Вернуться к предыдущему элементу.
- `iter1 == iter2`: Проверить, указывают ли итераторы на один и тот же элемент.
- `iter1 != iter2`: Убедиться, что итераторы указывают на разные элементы.
Групповой проект из School 21 был сделан как упражнение по низкоуровневому C++ после C-интенсива. Ниже оставлен исходный более неформальный тон проекта как часть учебной истории.

![palpatin](./materials/imgs/palpatin.png)

### Шаблоны
### Контейнеры простыми словами

Наши контейнеры написаны с использованием шаблонов, чтобы вы могли хранить любые типы данных, будь то целые числа, строки или даже ваши собственные классы. Просто представьте, что наши контейнеры - это волшебные сундуки, которые принимают любую форму, в зависимости от того, что вы в них кладете.
Контейнеры - это структуры, в которых программа хранит данные и выбирает компромисс между скоростью доступа, вставкой, удалением и упорядочиванием.

### Детали реализации
- **List**: двусвязный список для быстрых вставок и удалений при известной позиции.
- **Map**: пары `ключ-значение`, где поиск и вставка работают через дерево.
- **Queue**: очередь FIFO, где первым выходит элемент, добавленный раньше остальных.
- **Set**: множество уникальных ключей.
- **Stack**: стек LIFO, где первым выходит последний добавленный элемент.
- **Vector**: динамический массив с быстрым доступом по индексу.

- **Язык программирования**: C++17.
- **Компилятор**: gcc.
- **Организация кода**: Все драгоценные исходники спрятаны в папке `src`.
- **Стиль кода**: Чистый и красивый, как по учебнику Google Style.
- **Использование итераторов**: Это обязательно, потому что зачем же иначе писать контейнеры?
- **Шаблонные классы**: Все классы - мастера перевоплощения (шаблонные).
- **Пространство имен**: `s21` - наше гордое имя.
- **Unit-тестирование**: Каждому контейнеру - свою порцию тестов, все сделано с помощью библиотеки GTest.
- **Запрещено**: Копирование реализаций STL. Мы любим вызовы и оригинальность.
![deeper](./materials/imgs/deeper.png)

## Реализация библиотеки s21_containers.h
### Итераторы

Наша библиотека `s21_containers.h` включает реализацию всех основных контейнеров: `s21_list.h`, `s21_map.h`, `s21_queue.h`, `s21_set.h`, `s21_stack.h`, `s21_vector.h`.
Итераторы позволяют обходить контейнеры и работать с элементами без знания внутренней структуры хранения.

### Основные классы
Поддерживаемые операции:

- **List**: Реализован через структуру двусвязного списка, поддерживает двунаправленные итераторы. Это наш цирковой артист!
- **Map**: Ассоциативный контейнер, использующий красно-черное дерево для хранения пар "ключ-значение". Ловкий библиотекарь, хранящий книги.
- **Queue**: Последовательный контейнер для хранения элементов в порядке их добавления. Очередь за хот-догами!
- **Set**: Множество уникальных элементов, использующее красно-черное дерево. Элитный клуб уникальных элементов.
- **Stack**: Последовательный контейнер, реализующий принцип LIFO. Магическая шляпа фокусника.
- **Vector**: Динамический массив, поддерживающий прямой доступ по индексу. Массив на стероидах!
- `*iter`: получить элемент, на который указывает итератор;
- `++iter`: перейти к следующему элементу;
- `--iter`: вернуться к предыдущему элементу;
- `iter1 == iter2`: проверить, что итераторы указывают на одну позицию;
- `iter1 != iter2`: проверить, что итераторы указывают на разные позиции.

### Реализация красно-черного дерева
### Красно-черное дерево

Для реализации `map` и `set` мы использовали [красно-черное дерево](./src/rb-tree/s21_tree.h), обеспечивающее балансировку и эффективные операции вставки, удаления и поиска. Вот некоторые ключевые моменты:
`map` и `set` используют общую реализацию красно-черного дерева в [`src/rb-tree/s21_tree.h`](src/rb-tree/s21_tree.h). Дерево поддерживает балансировку при вставке и удалении, чтобы операции поиска и обновления не деградировали до линейного обхода.

```cpp
template <class K, class Compare = std::less<K>>
Expand All @@ -84,38 +118,18 @@ class RBTree {
iterator TreeEnd() noexcept;
std::pair<iterator, bool> Insert(const key_type &key);
void TreeClear();

private:
tree_node *head_;
size_t size_;
Compare less_;
bool flag_uniq = true;

tree_node *&root_() const;
bool IsRed(tree_node *node);
tree_node *FixUp(tree_node *node);
tree_node *RotateLeft(tree_node *node);
tree_node *RotateRight(tree_node *node);
tree_node *Insert(tree_node *node, tree_node *Parent, const key_type &key,
std::pair<iterator, bool> &pair_res);
};
```

### Makefile
### Makefile targets

Мы не забыли про Makefile, чтобы вы могли легко собрать и протестировать библиотеку. Поддерживаемые цели:

- `clean`: Очистка всех временных файлов, потому что чистота - залог здоровья.
- `test`: Запуск всех unit-тестов, чтобы убедиться, что всё работает как часы.
- `gcov_report` и `open_report`: Проверка покрытия функциональности библиотеки тестами. Чтобы не сочинять лишнего.
- `all`: Запускает все цеели с котятами.
| Target | Назначение |
| --- | --- |
| `make build` | собрать `s21_containers.a` |
| `make test` | собрать и запустить GTest |
| `make style-check` | проверить форматирование |
| `make gcov_report` | собрать HTML-отчет покрытия |
| `make valgrind` | проверить runtime через Valgrind |
| `make clean` | удалить временные артефакты |

![make all](./materials/imgs/cats.png)

## Итог

Библиотека `s21_containers` - это наше погружение в мир C++. Она предоставляет вам мощные и гибкие инструменты для работы с данными, а полное покрытие unit-тестами гарантирует надежность и стабильность.


Скачивайте, используйте, вносите свои предложения и улучшения. Пусть ваши контейнеры будут быстрыми, а код - красивым!

15 changes: 11 additions & 4 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ SHELL = /bin/bash
CC = g++
OPTION_FLAGS = -Wall -Werror -Wextra -g
CPP_FLAGS = -std=c++17 -lstdc++
COMPILE_FLAGS = $(filter-out -lstdc++,$(CPP_FLAGS))
GCOV_FLAGS = -fprofile-arcs -ftest-coverage
GTEST_FLAGS = -lgtest -lgtest_main

Expand All @@ -21,15 +22,20 @@ TEST_FILES = $(wildcard $(DIR_TEST)/*.cc)
TEST_OBJ = $(TEST_FILES:.cc=.o)
LIBRARY_NAME = s21_containers.a
COV_DIR = report
SMOKE_SRC = .s21_containers_smoke.cc
SMOKE_OBJ = .s21_containers_smoke.o

# ------------------------------- TASKS ------------------------------------------ #
all: clean cat build test style-check gcov_report valgrind

%.o: %.cc
@$(CC) $(OPTION_FLAGS) $(CPP_FLAGS) $(GCOV_FLAGS) -c $< -o $@
@$(CC) $(OPTION_FLAGS) $(COMPILE_FLAGS) $(GCOV_FLAGS) -c $< -o $@

$(LIBRARY_NAME): $(OBJ_FILES)
@ar rcs $(LIBRARY_NAME) $(OBJ_FILES)
@printf '#include "s21_containers.h"\n' > $(SMOKE_SRC)
@$(CC) $(OPTION_FLAGS) $(COMPILE_FLAGS) -c $(SMOKE_SRC) -o $(SMOKE_OBJ)
@ar rcs $(LIBRARY_NAME) $(OBJ_FILES) $(SMOKE_OBJ)
@rm -f $(SMOKE_SRC) $(SMOKE_OBJ) .s21_containers_smoke*.tmp

build: $(LIBRARY_NAME)

Expand All @@ -43,6 +49,7 @@ cat:

clean:
@rm -rf report $(COV_DIR) ./test $(LIBRARY_NAME) $(TEST_OBJ)
@rm -f $(SMOKE_SRC) $(SMOKE_OBJ) .s21_containers_smoke*.tmp
@rm -f *.o *.a *.out */*.gcda */*.gcno *.info *.txt

style-check:
Expand All @@ -58,8 +65,8 @@ style-i:
gcov_report: test
@./cat.sh "GCOV_REPORT" 20
@echo "Overall coverage rate:"
@lcov --gcov-tool gcov --capture --directory . --output-file Coverage_Report.info --no-external --ignore-errors gcov > coverage_output.txt 2>&1
@genhtml -o $(COV_DIR) Coverage_Report.info >> coverage_output.txt 2>&1
@lcov --gcov-tool gcov --capture --directory . --output-file Coverage_Report.info --no-external --ignore-errors gcov,source,mismatch,inconsistent > coverage_output.txt 2>&1 || { cat coverage_output.txt; exit 1; }
@genhtml -o $(COV_DIR) Coverage_Report.info --ignore-errors source >> coverage_output.txt 2>&1 || { cat coverage_output.txt; exit 1; }
@mkdir -p $(COV_DIR)
@grep -E 'lines......:|functions..:' coverage_output.txt > coverage_summary.txt
@cat coverage_summary.txt
Expand Down
4 changes: 2 additions & 2 deletions src/rb-tree/s21_tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class Iterator {
public:
using key_type = T;
using reference = key_type &;
using const_reference = const reference;
using const_reference = const key_type &;
using pointer = key_type *;
using tree_node = s21::Node<key_type>;
using iterator = Iterator;
Expand Down Expand Up @@ -298,4 +298,4 @@ class RBTree {
};
} // namespace s21
#include "s21_tree.tcc"
#endif // S21_TREE_H_
#endif // S21_TREE_H_
Loading