Skip to content

Commit 3b20dbd

Browse files
committed
ready
0 parents  commit 3b20dbd

8 files changed

Lines changed: 565 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
name: CI/CD Pipeline
2+
3+
on:
4+
push:
5+
branches: [ master, develop ]
6+
pull_request:
7+
branches: [ master, master ]
8+
9+
jobs:
10+
build:
11+
runs-on: ${{ matrix.os }}
12+
13+
strategy:
14+
fail-fast: false
15+
matrix:
16+
os: [ubuntu-latest, macos-latest, windows-latest]
17+
build-type: [Release, Debug]
18+
compiler: [gcc, clang]
19+
exclude:
20+
# Windows не использует gcc/clang напрямую в matrix
21+
- os: windows-latest
22+
compiler: gcc
23+
- os: windows-latest
24+
compiler: clang
25+
include:
26+
- os: windows-latest
27+
compiler: msvc
28+
cmake-generator: "Visual Studio 17 2022"
29+
30+
steps:
31+
- name: Checkout code
32+
uses: actions/checkout@v4
33+
34+
- name: Install dependencies (Linux)
35+
if: runner.os == 'Linux'
36+
run: |
37+
sudo apt-get update
38+
sudo apt-get install -y build-essential cmake
39+
40+
- name: Install dependencies (macOS)
41+
if: runner.os == 'macOS'
42+
run: |
43+
brew install cmake
44+
45+
- name: Configure CMake (Unix)
46+
if: runner.os != 'Windows'
47+
run: |
48+
cmake -B build \
49+
-DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \
50+
-DCMAKE_CXX_COMPILER=${{ matrix.compiler }}
51+
52+
- name: Configure CMake (Windows)
53+
if: runner.os == 'Windows'
54+
run: |
55+
cmake -B build -G "${{ matrix.cmake-generator }}"
56+
57+
- name: Build
58+
run: cmake --build build --config ${{ matrix.build-type }}
59+
60+
- name: Run Tests
61+
run: |
62+
cd build
63+
./hash_table_demo
64+
shell: bash
65+
66+
- name: Upload Artifact
67+
uses: actions/upload-artifact@v4
68+
if: matrix.build-type == 'Release'
69+
with:
70+
name: hash_table_demo-${{ runner.os }}-${{ matrix.build-type }}
71+
path: build/hash_table_demo
72+
retention-days: 7
73+
74+
code-quality:
75+
runs-on: ubuntu-latest
76+
77+
steps:
78+
- name: Checkout code
79+
uses: actions/checkout@v4
80+
81+
- name: Install dependencies
82+
run: |
83+
sudo apt-get update
84+
sudo apt-get install -y build-essential cmake clang-format
85+
86+
- name: Check code formatting
87+
run: |
88+
find include src -name "*.h" -o -name "*.cpp" | xargs clang-format --dry-run --Werror || true
89+
90+
- name: Build with sanitizers
91+
run: |
92+
cmake -B build-sanitize \
93+
-DCMAKE_BUILD_TYPE=Debug \
94+
-DCMAKE_CXX_FLAGS="-fsanitize=address,undefined"
95+
cmake --build build-sanitize
96+
cd build-sanitize
97+
./hash_table_demo

.gitignore

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
build/
2+
cmake-build-*/
3+
4+
.idea/
5+
.vscode/
6+
*.swp
7+
*.swo
8+
9+
*.exe
10+
*.out
11+
*.app
12+
13+
CMakeCache.txt
14+
CMakeFiles/
15+
cmake_install.cmake
16+
Makefile
17+
compile_commands.json

CMakeLists.txt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
cmake_minimum_required(VERSION 3.15)
2+
project(CppHashTable VERSION 1.0 LANGUAGES CXX)
3+
4+
set(CMAKE_CXX_STANDARD 17)
5+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
6+
set(CMAKE_CXX_EXTENSIONS OFF)
7+
8+
if(CMAKE_BUILD_TYPE STREQUAL "Release")
9+
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
10+
add_compile_options(-O3 -march=native)
11+
elseif(MSVC)
12+
add_compile_options(/O2)
13+
endif()
14+
endif()
15+
16+
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
17+
add_compile_options(-Wall -Wextra -Wpedantic)
18+
elseif(MSVC)
19+
add_compile_options(/W4)
20+
endif()
21+
22+
include_directories(${CMAKE_SOURCE_DIR}/include)
23+
add_executable(hash_table_demo src/main.cpp)
24+
25+
install(TARGETS hash_table_demo DESTINATION bin)

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2024 Ivan Ignatenko
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# C++ Hash Table with Custom Hash Functions
2+
3+
[![CI/CD Pipeline](https://github.com/ignavan39/cpp-hashtable/actions/workflows/ci.yml/badge.svg)](https://github.com/ignavan39/cpp-hashtable/actions/workflows/ci.yml)
4+
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5+
[![C++17](https://img.shields.io/badge/C%2B%2B-17-blue.svg)](https://isocpp.org/)
6+
7+
8+
## Статус сборки
9+
10+
| ОС | Release | Debug |
11+
|---|---|---|
12+
| Ubuntu | ![Ubuntu Release](https://github.com/ignavan39/cpp-hashtable/actions/workflows/ci.yml/badge.svg) | ![Ubuntu Debug](https://github.com/ignavan39/cpp-hashtable/actions/workflows/ci.yml/badge.svg) |
13+
| macOS | ![macOS Release](https://github.com/ignavan39/cpp-hashtable/actions/workflows/ci.yml/badge.svg) | ![macOS Debug](https://github.com/ignavan39/cpp-hashtable/actions/workflows/ci.yml/badge.svg) |
14+
| Windows | ![Windows Release](https://github.com/ignavan39/cpp-hashtable/actions/workflows/ci.yml/badge.svg) | ![Windows Debug](https://github.com/ignavan39/cpp-hashtable/actions/workflows/ci.yml/badge.svg) |
15+
16+
17+
Реализация хеш-таблицы на C++ с собственными алгоритмами хеширования.
18+
19+
## Мотивация
20+
21+
Мне долгое время не давало покоя старая лабораторная работа из универских готов с хэш таблицей
22+
и мне кажется, что в прошлой ее реализции 6 лет назад
23+
https://github.com/ignavan39/hashtable
24+
25+
проект был написан
26+
без особого энтузиазма и полного понимания стандартных алгоритмов хеширования.
27+
28+
Я постарался сделать это проект более удобным и понятным, чтобы не забыть
29+
о стандартных алгоритмах хеширования и понять, как они работают.
30+
еще хочется больше практики в c++
31+
32+
## Алгоритмы хеширования
33+
34+
В проекте реализованы 3 алгоритма:
35+
36+
1. **DJB2** (Daniel J. Bernstein)
37+
- Формула: `hash = hash * 33 + char`
38+
- Быстрый, хорошее распределение для строк
39+
40+
2. **FNV-1a** (Fowler-Noll-Vo)
41+
- Формула: `hash = (hash ^ byte) * prime`
42+
- Отличное распределение, используется во многих системах
43+
44+
3. **Simple Multiplicative**
45+
- Формула: `hash = key * constant`
46+
- Учебный алгоритм, демонстрирует основы
47+
48+
## Сборка
49+
50+
```bash
51+
# Release сборка (оптимизированная)
52+
cmake -B build -DCMAKE_BUILD_TYPE=Release
53+
cmake --build build --parallel
54+
55+
# Debug сборка (с отладочной информацией)
56+
cmake -B build -DCMAKE_BUILD_TYPE=Debug
57+
cmake --build build
58+
```
59+
60+
## Запуск
61+
62+
запуск src чтобы поиграться и проверить работоспособность
63+
64+
```bash
65+
./build/hash_table_demo
66+
```
67+
68+
## Пример использования
69+
70+
```c++
71+
// С хеш-функцией по умолчанию (DJB2)
72+
HashTable<std::string, int> table1;
73+
74+
// С конкретной хеш-функцией
75+
HashTable<std::string, int, FNV1aHash> table2;
76+
```
77+

include/HashFunctions.h

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#ifndef HASH_FUNCTIONS_H
2+
#define HASH_FUNCTIONS_H
3+
4+
#include <string>
5+
#include <cstdint>
6+
#include <type_traits>
7+
8+
9+
struct DJB2Hash {
10+
size_t operator()(const std::string& str) const {
11+
uint64_t hash = 5381;
12+
for (char c : str) {
13+
hash = ((hash << 5) + hash) + static_cast<unsigned char>(c);
14+
}
15+
return static_cast<size_t>(hash);
16+
}
17+
18+
template <typename T>
19+
typename std::enable_if<std::is_integral<T>::value, size_t>::type
20+
operator()(const T& value) const {
21+
uint64_t hash = 5381;
22+
uint64_t num = static_cast<uint64_t>(value);
23+
for (size_t i = 0; i < sizeof(T); ++i) {
24+
hash = ((hash << 5) + hash) + ((num >> (i * 8)) & 0xFF);
25+
}
26+
return static_cast<size_t>(hash);
27+
}
28+
};
29+
30+
struct FNV1aHash {
31+
static constexpr uint64_t FNV_PRIME = 1099511628211ULL;
32+
static constexpr uint64_t FNV_OFFSET = 14695981039346656037ULL;
33+
34+
size_t operator()(const std::string& str) const {
35+
uint64_t hash = FNV_OFFSET;
36+
for (char c : str) {
37+
hash ^= static_cast<unsigned char>(c);
38+
hash *= FNV_PRIME;
39+
}
40+
return static_cast<size_t>(hash);
41+
}
42+
43+
template <typename T>
44+
typename std::enable_if<std::is_integral<T>::value, size_t>::type
45+
operator()(const T& value) const {
46+
uint64_t hash = FNV_OFFSET;
47+
uint64_t num = static_cast<uint64_t>(value);
48+
for (size_t i = 0; i < sizeof(T); ++i) {
49+
hash ^= ((num >> (i * 8)) & 0xFF);
50+
hash *= FNV_PRIME;
51+
}
52+
return static_cast<size_t>(hash);
53+
}
54+
};
55+
56+
struct SimpleHash {
57+
static constexpr size_t MULTIPLIER = 2654435761ULL; // Константа Кнута
58+
59+
template <typename T>
60+
size_t operator()(const T& value) const {
61+
if constexpr (std::is_same<T, std::string>::value) {
62+
size_t sum = 0;
63+
for (char c : value) {
64+
sum += static_cast<unsigned char>(c);
65+
}
66+
return (sum * MULTIPLIER);
67+
} else {
68+
return static_cast<size_t>(value) * MULTIPLIER;
69+
}
70+
}
71+
};
72+
73+
inline size_t compressHash(size_t hash, size_t bucketCount) {
74+
return hash % bucketCount;
75+
}
76+
77+
#endif // HASH_FUNCTIONS_H

0 commit comments

Comments
 (0)