From 60a261f18cf49982324fb3fbf441166951813a89 Mon Sep 17 00:00:00 2001 From: "Timur A. Fatkhullin" Date: Wed, 17 Jun 2026 01:45:40 +0300 Subject: [PATCH] start ... --- .gitignore | 75 ++++++++++++++++++ CMakeLists.txt | 24 ++++++ examples/str_exam.cpp | 29 +++++++ include/snipplib/concepts/snplib_concepts.h | 28 +++++++ include/snipplib/hmap/snplib_hmap.h | 67 ++++++++++++++++ include/snipplib/utils/snplib_hash.h | 86 +++++++++++++++++++++ include/snipplib/utils/snplib_string.h | 77 ++++++++++++++++++ include/snipplib/utils/snplib_utils.h | 2 + snipplib.cpp | 5 ++ 9 files changed, 393 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 examples/str_exam.cpp create mode 100644 include/snipplib/concepts/snplib_concepts.h create mode 100644 include/snipplib/hmap/snplib_hmap.h create mode 100644 include/snipplib/utils/snplib_hash.h create mode 100644 include/snipplib/utils/snplib_string.h create mode 100644 include/snipplib/utils/snplib_utils.h create mode 100644 snipplib.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d0b2fe7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,75 @@ +# This file is used to ignore files which are generated +# ---------------------------------------------------------------------------- + +*~ +*.autosave +*.a +*.core +*.moc +*.o +*.obj +*.orig +*.rej +*.so +*.so.* +*_pch.h.cpp +*_resource.rc +*.qm +.#* +*.*# +core +!core/ +tags +.DS_Store +.directory +*.debug +Makefile* +*.prl +*.app +moc_*.cpp +ui_*.h +qrc_*.cpp +Thumbs.db +*.res +*.rc +/.qmake.cache +/.qmake.stash + +# qtcreator generated files +*.pro.user* +CMakeLists.txt.user* + +# xemacs temporary files +*.flc + +# Vim temporary files +.*.swp + +# Visual Studio generated files +*.ib_pdb_index +*.idb +*.ilk +*.pdb +*.sln +*.suo +*.vcproj +*vcproj.*.*.user +*.ncb +*.sdf +*.opensdf +*.vcxproj +*vcxproj.* + +# MinGW generated files +*.Debug +*.Release + +# Python byte code +*.pyc + +# Binaries +# -------- +*.dll +*.exe + +build/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..4bb84a1 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 3.10.0) +project(snipplib VERSION 0.1.0 LANGUAGES CXX) + +option(BUILD_EXAMPLES "Build examples" ON) + + +set(LIB_HEADERS include/snipplib/concepts/snplib_concepts.h + include/snipplib/utils/snplib_hash.h + include/snipplib/utils/snplib_utils.h + include/snipplib/hmap/snplib_hmap.h) + +add_library(${PROJECT_NAME} INTERFACE ${LIB_HEADERS}) +target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_23) +target_include_directories( + ${PROJECT_NAME} + INTERFACE + "$" + "$" +) + + +set(EXAM_STRING str_exam) +add_executable(${EXAM_STRING} examples/str_exam.cpp) +target_link_libraries(${EXAM_STRING} ${PROJECT_NAME}) \ No newline at end of file diff --git a/examples/str_exam.cpp b/examples/str_exam.cpp new file mode 100644 index 0000000..e1b73d1 --- /dev/null +++ b/examples/str_exam.cpp @@ -0,0 +1,29 @@ +#include +// #include "../utils/snplib_string.h" +// #include "../include/snipplib/snplib_string.h" +#include + +using namespace snplib; +int main() +{ + std::string si = " dewf wek e lwekjflkj "; + + auto s = snplib_trim_spaces(si); + + std::println("s = '{}'", s); + + auto sv = snplib_trim_spaces_as_view(si, TrimType::TRIM_LEFT); + + std::println("sv(TrimType::TRIM_LEFT) = '{}'", sv); + + sv = snplib_trim_spaces_as_view(si, TrimType::TRIM_RIGHT); + + std::println("sv(TrimType::TRIM_RIGHT) = '{}'", sv); + + sv = snplib_trim_spaces_as_view(si, TrimType::TRIM_BOTH); + + std::println("sv(TrimType::TRIM_BOTH) = '{}'", sv); + + + return 0; +} \ No newline at end of file diff --git a/include/snipplib/concepts/snplib_concepts.h b/include/snipplib/concepts/snplib_concepts.h new file mode 100644 index 0000000..aae0eab --- /dev/null +++ b/include/snipplib/concepts/snplib_concepts.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +namespace snplib { + +// type T is hashable +template +concept snplib_hashable_c = requires(T t) { + { std::hash(t) } -> std::convertible_to; +}; + +template +concept snplib_char_range_c = std::ranges::range && std::same_as, CharT>; + +template +concept snplib_input_char_range_c = std::ranges::input_range && std::same_as, CharT>; + +template +concept snplib_output_char_range_c = std::ranges::output_range; + +template +concept snplib_char_view_c = std::ranges::view && std::same_as, CharT>; + + + +} // end of snplib namespace \ No newline at end of file diff --git a/include/snipplib/hmap/snplib_hmap.h b/include/snipplib/hmap/snplib_hmap.h new file mode 100644 index 0000000..856c0f1 --- /dev/null +++ b/include/snipplib/hmap/snplib_hmap.h @@ -0,0 +1,67 @@ +#pragma once + +#include "../concepts/snplib_concepts.h" +#include "../utils/snplib_hash.h" + +namespace snplib { + + +template +class HeterogenMap { +protected: + // actuall map key type + typedef std::pair key_t; + + struct KeyHash { + static size_t operator()(key_t key) { + size_t hash = 0; + + snplib_hash_combine(hash, key.first, , key.second); + + return hash; + } + } + + template + inline static std::unordered_map _umap{}; + + std::vector> _clearFunc{}; + +public: + enum Error : {ERROR_OK, ERROR_NO_ELEM}; + + HeterogenMap() = default; + + ~HeterogenMap() { + for (auto &func: _clearFunc) { + func(); + } + } + + template + size_t push(KeyT const& key, VT&& value) { + auto it = _umap>.emplace(std::make_pair(this, key), std::forward(value)); + + if (it.second){ + _clearFunc.empace_back([it=it.first]() { _umap>.erase(it); }); + } // here the element already exists (just update its value) + + return _clearFunc.size(); + } + + template + size_t emplace(KeyT const&, CtorArgTs&& ...args) { + return push(key, VT(std::forward(args)...)); + } + + template + std::expected get(KeyT const& key) const { + if (auto it = _umap.find(std::make_pair(this, key)); it != _umap.end()) { + return it->second; + } + + return std::unexpected(Error::ERROR_NO_ELEM); + } +}; + +} // end of namespace snplib \ No newline at end of file diff --git a/include/snipplib/utils/snplib_hash.h b/include/snipplib/utils/snplib_hash.h new file mode 100644 index 0000000..804a9c4 --- /dev/null +++ b/include/snipplib/utils/snplib_hash.h @@ -0,0 +1,86 @@ +#pragma once + +#include "../concepts/snplib_concepts.h" +#include + +namespace snplib { + +template +static constexpr size_t FNV1aHash(const R& r) +{ + static_assert(sizeof(size_t) == 8 || sizeof(size_t) == 4, "ONLY FOR 32 or 64-bit size_t!!!"); + + size_t hash = 0, prime = 0; + if constexpr (sizeof(size_t) == 8) { // 64-bit + prime = 1099511628211UL; + hash = 14695981039346656037UL; + } else if constexpr (sizeof(size_t) == 4) { // 32-bit + prime = 16777619; + hash = 2166136261; + } + + for (const char& ch : r) { + hash ^= ch; + hash *= prime; + } + + return hash; +} + +static constexpr size_t FNV1aHash(std::forward_iterator auto begin, std::sentinel_for auto end) + requires std::same_as>, char> +{ + static_assert(sizeof(size_t) == 8 || sizeof(size_t) == 4, "ONLY FOR 32 or 64-bit size_t!!!"); + + size_t hash = 0, prime = 0; + if constexpr (sizeof(size_t) == 8) { // 64-bit + prime = 1099511628211UL; + hash = 14695981039346656037UL; + } else if constexpr (sizeof(size_t) == 4) { // 32-bit + prime = 16777619; + hash = 2166136261; + } + + for (auto it = begin; it != end; ++it) { + hash ^= *it; + hash *= prime; + } + + return hash; +} + + +// Boost implementation of hash combining +template +static constexpr void snplib_hash_combine(std::size_t& seed, const T& v, Ts&& ... vs) { + static constexpr auto digits = std::numeric_limits::digits; + static_assert(digits == 64 || digits == 32, "Unsupported 'size_t' type size!"); + + if constexpr (digits == 64) { + std::size_t x = seed + 0x9e3779b9 + std::hash()(v); + const std::size_t m = 0xe9846af9b1a615d; + x ^= x >> 32; + x *= m; + x ^= x >> 32; + x *= m; + x ^= x >> 28; + seed = x; + } + else { // 32-bits + std::size_t x = seed + 0x9e3779b9 + std::hash()(v); + const std::size_t m1 = 0x21f0aaad; + const std::size_t m2 = 0x735a2d97; + x ^= x >> 16; + x *= m1; + x ^= x >> 15; + x *= m2; + x ^= x >> 15; + seed = x; + } + + if constexpr (sizeof...(Ts)) { + snplib_hash_combine(seed, std::forward(vs)...); + } +} + +} // end of snplib namespace \ No newline at end of file diff --git a/include/snipplib/utils/snplib_string.h b/include/snipplib/utils/snplib_string.h new file mode 100644 index 0000000..f5d552d --- /dev/null +++ b/include/snipplib/utils/snplib_string.h @@ -0,0 +1,77 @@ +#pragma once + +#include +#include + +#include "../concepts/snplib_concepts.h" + +namespace snplib { + +constexpr static bool snplib_is_space(char in) noexcept +{ + static constexpr auto ws = {' ', '\t', '\n', '\v', '\r', '\f'}; + return std::ranges::any_of(ws, [in](auto p) { return p == in; }); +}; + + +enum class TrimType { TRIM_LEFT, TRIM_RIGHT, TRIM_BOTH }; + +template +constexpr static OR snplib_trim_spaces(R&& r, TrimType type = TrimType::TRIM_BOTH, IsSpaceFuncT&& is_space_func = snplib_is_space) +{ + if (type == TrimType::TRIM_LEFT) { + auto res = r | std::views::drop_while(is_space_func); + return OR{res.begin(), res.end()}; + } else if (type == TrimType::TRIM_RIGHT) { + auto res = r | std::views::reverse | std::views::drop_while(is_space_func) | + std::views::reverse; + return OR{res.begin(), res.end()}; + } else if (type == TrimType::TRIM_BOTH) { + auto res = r | std::views::drop_while(is_space_func) | std::views::reverse | std::views::drop_while(is_space_func) | + std::views::reverse; + return OR{res.begin(), res.end()}; + } + + return OR{}; +} + +template +constexpr static std::string snplib_trim_spaces(R&& r, TrimType type = TrimType::TRIM_BOTH, IsSpaceFuncT&& is_space_func = snplib_is_space) +{ + return snplib_trim_spaces(std::forward(r), type, std::forward(is_space_func)); +} + +template +constexpr static std::string_view snplib_trim_spaces_as_view(R&& r, TrimType type = TrimType::TRIM_BOTH, IsSpaceFuncT&& is_space_func = snplib_is_space) + requires std::ranges::contiguous_range +{ + auto end = std::forward(r).end(); + + auto f1 = std::forward(r).begin(); + + if (type != TrimType::TRIM_RIGHT) { + // look for the first non-space symbol + f1 = std::ranges::find_if_not(std::forward(r), std::forward(is_space_func)); + if (f1 == end) { // all are spaces! + return std::string_view(); + } + } + + auto f2 = end; + + if (type != TrimType::TRIM_LEFT) { + auto f3 = f1; + + do { + f2 = std::ranges::find_if(++f3, end, std::forward(is_space_func)); + if (f2 == end) + break; + f3 = std::ranges::find_if_not(f2 + 1, end, std::forward(is_space_func)); + } while (f3 != end); + } + + return std::string_view(f1, f2); +} + + +} // end of snplib namespace \ No newline at end of file diff --git a/include/snipplib/utils/snplib_utils.h b/include/snipplib/utils/snplib_utils.h new file mode 100644 index 0000000..3f59c93 --- /dev/null +++ b/include/snipplib/utils/snplib_utils.h @@ -0,0 +1,2 @@ +#pragma once + diff --git a/snipplib.cpp b/snipplib.cpp new file mode 100644 index 0000000..74975d1 --- /dev/null +++ b/snipplib.cpp @@ -0,0 +1,5 @@ +#include + +void say_hello(){ + std::cout << "Hello, from snipplib!\n"; +}