start ...
This commit is contained in:
28
include/snipplib/concepts/snplib_concepts.h
Normal file
28
include/snipplib/concepts/snplib_concepts.h
Normal 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
|
||||
67
include/snipplib/hmap/snplib_hmap.h
Normal file
67
include/snipplib/hmap/snplib_hmap.h
Normal 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
|
||||
86
include/snipplib/utils/snplib_hash.h
Normal file
86
include/snipplib/utils/snplib_hash.h
Normal 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
|
||||
77
include/snipplib/utils/snplib_string.h
Normal file
77
include/snipplib/utils/snplib_string.h
Normal 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
|
||||
2
include/snipplib/utils/snplib_utils.h
Normal file
2
include/snipplib/utils/snplib_utils.h
Normal file
@@ -0,0 +1,2 @@
|
||||
#pragma once
|
||||
|
||||
Reference in New Issue
Block a user