start ...

This commit is contained in:
2026-06-17 01:45:40 +03:00
commit 60a261f18c
9 changed files with 393 additions and 0 deletions

View File

@@ -0,0 +1,28 @@
#pragma once
#include <concepts>
#include <ranges>
namespace snplib {
// type T is hashable
template <typename T>
concept snplib_hashable_c = requires(T t) {
{ std::hash<T>(t) } -> std::convertible_to<size_t>;
};
template <typename T, typename CharT = char>
concept snplib_char_range_c = std::ranges::range<T> && std::same_as<std::ranges::range_value_t<T>, CharT>;
template <typename T, typename CharT = char>
concept snplib_input_char_range_c = std::ranges::input_range<T> && std::same_as<std::ranges::range_value_t<T>, CharT>;
template <typename T, typename CharT = char>
concept snplib_output_char_range_c = std::ranges::output_range<T, CharT>;
template <typename T, typename CharT = char>
concept snplib_char_view_c = std::ranges::view<T> && std::same_as<std::ranges::range_value_t<T>, CharT>;
} // end of snplib namespace

View File

@@ -0,0 +1,67 @@
#pragma once
#include "../concepts/snplib_concepts.h"
#include "../utils/snplib_hash.h"
namespace snplib {
template<snplib_hashable_c KeyT>
class HeterogenMap {
protected:
// actuall map key type
typedef std::pair<const HeterogenMap*, KeyT> 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 <typename VT>
inline static std::unordered_map<key_t, VT, KeyHash> _umap{};
std::vector<std::function<void()>> _clearFunc{};
public:
enum Error : {ERROR_OK, ERROR_NO_ELEM};
HeterogenMap() = default;
~HeterogenMap() {
for (auto &func: _clearFunc) {
func();
}
}
template<typename VT>
size_t push(KeyT const& key, VT&& value) {
auto it = _umap<std::decay_t<VT>>.emplace(std::make_pair(this, key), std::forward<VT>(value));
if (it.second){
_clearFunc.empace_back([it=it.first]() { _umap<std::decay_t<VT>>.erase(it); });
} // here the element already exists (just update its value)
return _clearFunc.size();
}
template<typename VT, typename ...CtorArgTs>
size_t emplace(KeyT const&, CtorArgTs&& ...args) {
return push(key, VT(std::forward<CtorArgTs>(args)...));
}
template<typename VT>
std::expected<VT, Error> get(KeyT const& key) const {
if (auto it = _umap<VT>.find(std::make_pair(this, key)); it != _umap<VT>.end()) {
return it->second;
}
return std::unexpected(Error::ERROR_NO_ELEM);
}
};
} // end of namespace snplib

View File

@@ -0,0 +1,86 @@
#pragma once
#include "../concepts/snplib_concepts.h"
#include <iterator>
namespace snplib {
template <snplib_input_char_range_c R>
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<decltype(begin)> auto end)
requires std::same_as<std::remove_cv_t<std::iter_value_t<decltype(begin)>>, 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 <snplib_hashable_c T, snplib_hashable_c ...Ts>
static constexpr void snplib_hash_combine(std::size_t& seed, const T& v, Ts&& ... vs) {
static constexpr auto digits = std::numeric_limits<std::size_t>::digits;
static_assert(digits == 64 || digits == 32, "Unsupported 'size_t' type size!");
if constexpr (digits == 64) {
std::size_t x = seed + 0x9e3779b9 + std::hash<T>()(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<T>()(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<Ts>(vs)...);
}
}
} // end of snplib namespace

View File

@@ -0,0 +1,77 @@
#pragma once
#include <algorithm>
#include <string>
#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 <snplib_output_char_range_c OR, snplib_input_char_range_c R, typename IsSpaceFuncT = decltype(snplib_is_space)>
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 <snplib_input_char_range_c R, typename IsSpaceFuncT = decltype(snplib_is_space)>
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::string>(std::forward<R>(r), type, std::forward<IsSpaceFuncT>(is_space_func));
}
template <snplib_input_char_range_c R, typename IsSpaceFuncT = decltype(snplib_is_space)>
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<R>
{
auto end = std::forward<R>(r).end();
auto f1 = std::forward<R>(r).begin();
if (type != TrimType::TRIM_RIGHT) {
// look for the first non-space symbol
f1 = std::ranges::find_if_not(std::forward<R>(r), std::forward<IsSpaceFuncT>(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<IsSpaceFuncT>(is_space_func));
if (f2 == end)
break;
f3 = std::ranges::find_if_not(f2 + 1, end, std::forward<IsSpaceFuncT>(is_space_func));
} while (f3 != end);
}
return std::string_view(f1, f2);
}
} // end of snplib namespace

View File

@@ -0,0 +1,2 @@
#pragma once