[ox] Improve hasing and MaybeView
All checks were successful
Build / build (push) Successful in 2m29s

* Add CityHash dep
* Use CityHash for HashMap
* Make MaybeView more versatile
* Cleanup some inappropriate MaybeView uses
This commit is contained in:
2024-04-24 20:55:26 -05:00
parent 6b47133c22
commit 32e4702dc7
13 changed files with 911 additions and 73 deletions

View File

@ -64,7 +64,7 @@ constexpr Error DataWalker<Reader, T>::read(const DescriptorField &f, Reader *rd
template<typename Reader, typename T>
constexpr void DataWalker<Reader, T>::pushNamePath(const FieldName &fn) noexcept {
m_path.push_back(fn);
m_path.emplace_back(fn);
}
template<typename Reader, typename T>

View File

@ -81,6 +81,7 @@ target_link_libraries(
OxStd PUBLIC
$<$<CXX_COMPILER_ID:GNU>:gcc>
OxTraceHook
CityHash
)
install(

170
deps/ox/src/ox/std/hash.hpp vendored Normal file
View File

@ -0,0 +1,170 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#if __has_include(<functional>)
#include <functional>
#else
namespace std {
template<typename T>
struct hash;
}
#endif
#include <cityhash/city.h>
#include "istring.hpp"
#include "string.hpp"
#include "stringview.hpp"
#include "types.hpp"
namespace ox {
template<typename T>
struct hash {
[[nodiscard]]
constexpr size_t operator()(T const&v) const noexcept {
return std::hash<T>{}(v);
}
};
template<>
struct hash<bool> {
[[nodiscard]]
constexpr size_t operator()(bool v) const noexcept {
return static_cast<size_t>(v);
}
};
template<>
struct hash<char> {
[[nodiscard]]
constexpr size_t operator()(char v) const noexcept {
return static_cast<size_t>(v);
}
};
template<>
struct hash<short> {
[[nodiscard]]
constexpr size_t operator()(short v) const noexcept {
return static_cast<size_t>(v);
}
};
template<>
struct hash<int> {
[[nodiscard]]
constexpr size_t operator()(int v) const noexcept {
return static_cast<size_t>(v);
}
};
template<>
struct hash<long> {
[[nodiscard]]
constexpr size_t operator()(long v) const noexcept {
return static_cast<size_t>(v);
}
};
template<>
struct hash<long long> {
[[nodiscard]]
constexpr size_t operator()(long long v) const noexcept {
return static_cast<size_t>(v);
}
};
template<>
struct hash<unsigned char> {
[[nodiscard]]
constexpr size_t operator()(unsigned char v) const noexcept {
return static_cast<size_t>(v);
}
};
template<>
struct hash<unsigned short> {
[[nodiscard]]
constexpr size_t operator()(unsigned short v) const noexcept {
return static_cast<size_t>(v);
}
};
template<>
struct hash<unsigned int> {
[[nodiscard]]
constexpr size_t operator()(unsigned int v) const noexcept {
return static_cast<size_t>(v);
}
};
template<>
struct hash<unsigned long> {
[[nodiscard]]
constexpr size_t operator()(unsigned long v) const noexcept {
return static_cast<size_t>(v);
}
};
template<>
struct hash<unsigned long long> {
[[nodiscard]]
constexpr size_t operator()(unsigned long long v) const noexcept {
return static_cast<size_t>(v);
}
};
[[nodiscard]]
constexpr auto hashString(ox::StringView const&v) noexcept {
if constexpr(sizeof(void*) == 8) {
return cityhash::CityHash64(v.data(), v.bytes());
} else {
return cityhash::CityHash32(v.data(), v.bytes());
}
}
template<>
struct hash<ox::StringView> {
[[nodiscard]]
constexpr size_t operator()(ox::StringView v) const noexcept {
return hashString(v);
}
};
template<>
struct hash<ox::String> {
[[nodiscard]]
constexpr size_t operator()(ox::StringView v) const noexcept {
return hashString(v);
}
};
template<size_t sz>
struct hash<ox::IString<sz>> {
[[nodiscard]]
constexpr size_t operator()(ox::StringView v) const noexcept {
return hashString(v);
}
};
template<>
struct hash<const char*> {
[[nodiscard]]
constexpr size_t operator()(ox::StringView v) const noexcept {
return hashString(v);
}
};
}

View File

@ -9,6 +9,7 @@
#pragma once
#include "algorithm.hpp"
#include "hash.hpp"
#include "ignore.hpp"
#include "stringview.hpp"
#include "strops.hpp"
@ -32,7 +33,7 @@ class HashMap {
Vector<Pair*> m_pairs;
public:
explicit constexpr HashMap(std::size_t size = 100);
explicit constexpr HashMap(std::size_t size = 127);
constexpr HashMap(HashMap const&other);
@ -68,10 +69,6 @@ class HashMap {
private:
constexpr void expand();
constexpr static uint64_t hash(Integral_c auto) noexcept;
constexpr static uint64_t hash(StringView const&) noexcept;
template<typename KK>
constexpr Pair *const&access(Vector<Pair*> const&pairs, KK const&key) const;
@ -172,14 +169,14 @@ constexpr void HashMap<K, T>::erase(MaybeView_t<K> const&k) {
if (!contains(k)) {
return;
}
auto h = hash(k) % m_pairs.size();
auto h = ox::hash<MaybeView_t<K>>{}(k) % m_pairs.size();
while (true) {
const auto &p = m_pairs[h];
if (p == nullptr || p->key == k) {
std::ignore = m_pairs.erase(h);
break;
} else {
h = hash(h) % m_pairs.size();
h = ox::hash<MaybeView_t<K>>{}(k) % m_pairs.size();
}
}
std::ignore = m_keys.erase(ox::find(m_keys.begin(), m_keys.end(), k));
@ -206,7 +203,7 @@ constexpr void HashMap<K, T>::clear() {
delete m_pairs[i];
}
m_pairs.clear();
m_pairs.resize(100);
m_pairs.resize(127);
}
template<typename K, typename T>
@ -219,30 +216,10 @@ constexpr void HashMap<K, T>::expand() {
m_pairs = std::move(r);
}
template<typename K, typename T>
constexpr uint64_t HashMap<K, T>::hash(Integral_c auto k) noexcept {
uint64_t sum = 1;
for (auto i = 0u; i < sizeof(K); ++i) {
const auto shift = i * 8;
const auto v = static_cast<uint64_t>(k >> shift & 0xff);
sum += (sum + v) * 7 * sum;
}
return sum;
}
template<typename K, typename T>
constexpr uint64_t HashMap<K, T>::hash(StringView const&k) noexcept {
uint64_t sum = 1;
for (auto i = 0u; i < k.len(); ++i) {
sum += ((sum + static_cast<uint64_t>(k[i])) * 7) * sum;
}
return sum;
}
template<typename K, typename T>
template<typename KK>
constexpr typename HashMap<K, T>::Pair *const&HashMap<K, T>::access(Vector<Pair*> const&pairs, KK const&k) const {
auto h = static_cast<std::size_t>(hash(k) % pairs.size());
auto h = static_cast<std::size_t>(ox::hash<KK>{}(k) % pairs.size());
while (true) {
const auto &p = pairs[h];
if (p == nullptr || p->key == k) {
@ -256,7 +233,7 @@ constexpr typename HashMap<K, T>::Pair *const&HashMap<K, T>::access(Vector<Pair*
template<typename K, typename T>
template<typename KK>
constexpr typename HashMap<K, T>::Pair *&HashMap<K, T>::access(Vector<Pair*> &pairs, KK const&k) {
auto h = static_cast<std::size_t>(hash(k) % pairs.size());
auto h = static_cast<std::size_t>(ox::hash<KK>{}(k) % pairs.size());
while (true) {
auto &p = pairs[h];
if (p == nullptr || p->key == k) {

View File

@ -282,4 +282,9 @@ constexpr std::size_t IString<buffLen>::cap() const noexcept {
return buffLen;
}
template<size_t sz>
struct MaybeView<ox::IString<sz>> {
using type = ox::StringView;
};
}

View File

@ -15,7 +15,7 @@ namespace ox {
// Maybe StringView. If T is a string type, MaybeType::type/MaybeView_t is a
// StringView. This avoids creating unnecessary Strings when taking a
// StringView or C string as a function argument.
template<typename T, bool isStr = isOxString_v<T>>
template<typename T>
struct MaybeView {
using type = T;
};

View File

@ -589,4 +589,9 @@ constexpr auto alignOf(const ox::BasicString<SmallStringSize_v>&) noexcept {
return alignOf<PlatSpec>(&v);
}
template<size_t sz>
struct MaybeView<ox::BasicString<sz>> {
using type = ox::StringView;
};
}

View File

@ -98,11 +98,6 @@ constexpr auto toStdStringView(CRStringView sv) noexcept {
#endif
template<typename T>
struct MaybeView<T, true> {
using type = ox::StringView;
};
constexpr ox::Result<int> atoi(ox::CRStringView str) noexcept {
int total = 0;
int multiplier = 1;

View File

@ -8,7 +8,27 @@
#pragma once
#if __has_include(<utility>)
#include <utility>
#include "typetraits.hpp"
#else
#include "typetraits.hpp"
namespace std {
template<typename T>
constexpr typename ox::remove_reference<T>::type &&move(T &&t) noexcept {
return static_cast<typename ox::remove_reference<T>::type&&>(t);
}
template<typename T>
constexpr void swap(T &a, T &b) noexcept {
auto temp = std::move(a);
a = std::move(b);
b = std::move(temp);
}
}
#endif
namespace ox {
@ -30,14 +50,3 @@ constexpr T &&forward(remove_reference_t<T> &&t) noexcept {
}
#if __has_include(<utility>)
#include <utility>
#else
namespace std {
template<typename T>
constexpr typename ox::remove_reference<T>::type &&move(T &&t) noexcept {
return static_cast<typename ox::remove_reference<T>::type&&>(t);
}
}
#endif

View File

@ -272,9 +272,9 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
constexpr bool contains(MaybeView_t<T> const&) const noexcept(useNoexcept);
constexpr iterator<T&, T*, false> insert(
std::size_t pos, std::size_t cnt, MaybeView_t<T> const&val) noexcept(useNoexcept);
std::size_t pos, std::size_t cnt, T val) noexcept(useNoexcept);
constexpr iterator<T&, T*, false> insert(std::size_t pos, MaybeView_t<T> const&val) noexcept(useNoexcept);
constexpr iterator<T&, T*, false> insert(std::size_t pos, T val) noexcept(useNoexcept);
template<typename... Args>
constexpr iterator<T&, T*, false> emplace(std::size_t pos, Args&&... args) noexcept(useNoexcept);
@ -282,9 +282,7 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
template<typename... Args>
constexpr T &emplace_back(Args&&... args) noexcept(useNoexcept);
constexpr void push_back(T &&item) noexcept(useNoexcept);
constexpr void push_back(MaybeView_t<T> const&item) noexcept(useNoexcept);
constexpr void push_back(T item) noexcept(useNoexcept);
constexpr void pop_back() noexcept(useNoexcept);
@ -534,14 +532,14 @@ constexpr bool Vector<T, SmallVectorSize, Allocator>::contains(MaybeView_t<T> co
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false>
Vector<T, SmallVectorSize, Allocator>::insert(
std::size_t pos, std::size_t cnt, MaybeView_t<T> const&val) noexcept(useNoexcept) {
std::size_t pos, std::size_t cnt, T val) noexcept(useNoexcept) {
if (m_size + cnt > m_cap) {
reserveInsert(m_cap ? m_size + cnt : initialCap, pos, cnt);
if (pos < m_size) {
m_items[pos] = val;
m_items[pos] = std::move(val);
} else {
for (auto i = 0u; i < cnt; ++i) {
std::construct_at(&m_items[pos + i], val);
std::construct_at(&m_items[pos + i], m_items[pos]);
}
}
} else {
@ -549,10 +547,10 @@ Vector<T, SmallVectorSize, Allocator>::insert(
for (auto i = m_size + cnt - 1; i > pos; --i) {
std::construct_at(&m_items[i], std::move(m_items[i - cnt]));
}
m_items[pos] = val;
m_items[pos] = std::move(val);
} else {
for (auto i = 0u; i < cnt; ++i) {
std::construct_at(&m_items[pos + i], val);
std::construct_at(&m_items[pos + i], m_items[pos]);
}
}
}
@ -562,22 +560,22 @@ Vector<T, SmallVectorSize, Allocator>::insert(
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false>
Vector<T, SmallVectorSize, Allocator>::insert(std::size_t pos, MaybeView_t<T> const&val) noexcept(useNoexcept) {
Vector<T, SmallVectorSize, Allocator>::insert(std::size_t pos, T val) noexcept(useNoexcept) {
if (m_size == m_cap) {
reserveInsert(m_cap ? m_cap * 2 : initialCap, pos);
if (pos < m_size) {
m_items[pos] = val;
m_items[pos] = std::move(val);
} else {
std::construct_at(&m_items[pos], val);
std::construct_at(&m_items[pos], m_items[pos]);
}
} else {
if (pos < m_size) {
for (auto i = m_size; i > pos; --i) {
std::construct_at(&m_items[i], std::move(m_items[i - 1]));
}
m_items[pos] = val;
m_items[pos] = std::move(val);
} else {
std::construct_at(&m_items[pos], val);
std::construct_at(&m_items[pos], m_items[pos]);
}
}
++m_size;
@ -619,7 +617,7 @@ constexpr T &Vector<T, SmallVectorSize, Allocator>::emplace_back(Args&&... args)
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T &&item) noexcept(useNoexcept) {
constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T item) noexcept(useNoexcept) {
if (m_size == m_cap) {
reserve(m_cap ? m_cap * 2 : initialCap);
}
@ -627,15 +625,6 @@ constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T &&item) noexce
++m_size;
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(MaybeView_t<T> const&item) noexcept(useNoexcept) {
if (m_size == m_cap) {
reserve(m_cap ? m_cap * 2 : initialCap);
}
std::construct_at(&m_items[m_size], item);
++m_size;
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::pop_back() noexcept(useNoexcept) {
--m_size;