Compare commits

...

10 Commits

Author SHA1 Message Date
889fe04255 [nostalgia/studio] Set version to 2024.05.0
All checks were successful
Build / build (push) Successful in 2m29s
2024-05-23 22:11:52 -05:00
eed115b287 [keel] Fix a GCC break
All checks were successful
Build / build (push) Successful in 2m39s
2024-05-17 21:13:15 -05:00
7233da75ea [ox/std] Remove dedicated keys array from SmallMap
All checks were successful
Build / build (push) Successful in 2m31s
2024-05-11 01:59:40 -05:00
30797c710b [ox/std] Add small sz option to SmallMap 2024-05-11 00:53:31 -05:00
e8041121d0 [ox/std] Add missing oxExpect to timeMapStrToUuid
All checks were successful
Build / build (push) Successful in 2m32s
2024-05-11 00:26:57 -05:00
d054528e49 [ox/std] Remove empty if from SmallMap
Some checks failed
Build / build (push) Has been cancelled
2024-05-11 00:24:37 -05:00
09d840cfd0 [ox/std] Add some functions for comparing HashMap and SmallMap
All checks were successful
Build / build (push) Successful in 2m31s
2024-05-10 23:58:35 -05:00
aeb1ef3b12 [ox/std] Cleanup SmallMap, make it easier to make potential changes 2024-05-10 23:58:22 -05:00
b66f61c217 [ox/std] Add hash function for UUID 2024-05-10 23:55:41 -05:00
b089bf460b [ox/std] Optimize Array compare 2024-05-10 23:54:22 -05:00
7 changed files with 280 additions and 83 deletions

View File

@ -137,12 +137,16 @@ constexpr Array<T, ArraySize>::Array(Array &&other) noexcept {
template<typename T, std::size_t ArraySize> template<typename T, std::size_t ArraySize>
constexpr bool Array<T, ArraySize>::operator==(const Array &other) const { constexpr bool Array<T, ArraySize>::operator==(const Array &other) const {
for (std::size_t i = 0; i < ArraySize; i++) { if (std::is_constant_evaluated()) {
if (!(m_items[i] == other.m_items[i])) { for (std::size_t i = 0; i < ArraySize; i++) {
return false; if (!(m_items[i] == other.m_items[i])) {
return false;
}
} }
return true;
} else {
return memcmp(this, &other, sizeof(*this)) == 0;
} }
return true;
} }
template<typename T, std::size_t ArraySize> template<typename T, std::size_t ArraySize>

View File

@ -17,23 +17,23 @@
namespace ox { namespace ox {
template<typename K, typename T> template<typename K, typename T, size_t SmallSz = 0>
class SmallMap { class SmallMap {
public: public:
using key_t = K; using key_t = K;
using value_t = T; using value_t = T;
private:
struct Pair { struct Pair {
K key = {}; K key = {};
T value{}; T value{};
}; };
Vector<K> m_keys;
Vector<Pair> m_pairs; private:
using PairVector = Vector<Pair, SmallSz>;
PairVector m_pairs;
public: public:
explicit constexpr SmallMap(std::size_t size = 127); constexpr SmallMap() = default;
constexpr SmallMap(SmallMap const&other); constexpr SmallMap(SmallMap const&other);
@ -62,75 +62,74 @@ class SmallMap {
constexpr std::size_t size() const noexcept; constexpr std::size_t size() const noexcept;
[[nodiscard]] [[nodiscard]]
constexpr Vector<K> const&keys() const noexcept; constexpr Vector<K> keys() const noexcept;
[[nodiscard]]
constexpr K const&key(size_t i) const noexcept;
[[nodiscard]]
constexpr T const&value(size_t i) const noexcept;
[[nodiscard]]
constexpr T &value(size_t i) noexcept;
[[nodiscard]]
constexpr Pair const&get(size_t i) const noexcept;
[[nodiscard]]
constexpr Pair &get(size_t i) noexcept;
constexpr void clear(); constexpr void clear();
private: private:
template<typename KK> template<typename KK>
constexpr Pair const&access(Vector<Pair> const&pairs, KK const&key, bool &isNew) const; constexpr Pair const&access(PairVector const&pairs, KK const&key, bool &isNew) const;
template<typename KK> template<typename KK>
constexpr Pair &access(Vector<Pair> &pairs, KK const&key, bool &isNew); constexpr Pair &access(PairVector &pairs, KK const&key, bool &isNew);
}; };
template<typename K, typename T> template<typename K, typename T, size_t SmallSz>
constexpr SmallMap<K, T>::SmallMap(std::size_t size): m_pairs(size) { constexpr SmallMap<K, T, SmallSz>::SmallMap(SmallMap<K, T, SmallSz> const&other) {
}
template<typename K, typename T>
constexpr SmallMap<K, T>::SmallMap(SmallMap<K, T> const&other) {
m_pairs = other.m_pairs; m_pairs = other.m_pairs;
} }
template<typename K, typename T> template<typename K, typename T, size_t SmallSz>
constexpr SmallMap<K, T>::SmallMap(SmallMap<K, T> &&other) noexcept { constexpr SmallMap<K, T, SmallSz>::SmallMap(SmallMap<K, T, SmallSz> &&other) noexcept {
m_keys = std::move(other.m_keys);
m_pairs = std::move(other.m_pairs); m_pairs = std::move(other.m_pairs);
} }
template<typename K, typename T> template<typename K, typename T, size_t SmallSz>
constexpr SmallMap<K, T>::~SmallMap() { constexpr SmallMap<K, T, SmallSz>::~SmallMap() {
clear(); clear();
} }
template<typename K, typename T> template<typename K, typename T, size_t SmallSz>
constexpr bool SmallMap<K, T>::operator==(SmallMap const&other) const { constexpr bool SmallMap<K, T, SmallSz>::operator==(SmallMap const&other) const {
if (m_keys != other.m_keys) { return m_pairs == other.m_pairs;
return false;
}
for (int i = 0; i < m_keys.size(); ++i) {
auto &k = m_keys[i];
if (at(k) != other.at(k)) {
return false;
}
}
return true;
} }
template<typename K, typename T> template<typename K, typename T, size_t SmallSz>
constexpr SmallMap<K, T> &SmallMap<K, T>::operator=(SmallMap<K, T> const&other) { constexpr SmallMap<K, T, SmallSz> &SmallMap<K, T, SmallSz>::operator=(SmallMap<K, T, SmallSz> const&other) {
if (this != &other) { if (this != &other) {
clear(); clear();
m_keys = other.m_keys;
m_pairs = other.m_pairs; m_pairs = other.m_pairs;
} }
return *this; return *this;
} }
template<typename K, typename T> template<typename K, typename T, size_t SmallSz>
constexpr SmallMap<K, T> &SmallMap<K, T>::operator=(SmallMap<K, T> &&other) noexcept { constexpr SmallMap<K, T, SmallSz> &SmallMap<K, T, SmallSz>::operator=(SmallMap<K, T, SmallSz> &&other) noexcept {
if (this != &other) { if (this != &other) {
clear(); clear();
m_keys = std::move(other.m_keys);
m_pairs = std::move(other.m_pairs); m_pairs = std::move(other.m_pairs);
} }
return *this; return *this;
} }
template<typename K, typename T> template<typename K, typename T, size_t SmallSz>
constexpr T &SmallMap<K, T>::operator[](MaybeView_t<K> const&k) { constexpr T &SmallMap<K, T, SmallSz>::operator[](MaybeView_t<K> const&k) {
bool isNew{}; bool isNew{};
auto p = &access(m_pairs, k, isNew); auto p = &access(m_pairs, k, isNew);
if (isNew) { if (isNew) {
@ -139,8 +138,8 @@ constexpr T &SmallMap<K, T>::operator[](MaybeView_t<K> const&k) {
return p->value; return p->value;
} }
template<typename K, typename T> template<typename K, typename T, size_t SmallSz>
constexpr Result<T*> SmallMap<K, T>::at(MaybeView_t<K> const&k) noexcept { constexpr Result<T*> SmallMap<K, T, SmallSz>::at(MaybeView_t<K> const&k) noexcept {
auto p = access(m_pairs, k); auto p = access(m_pairs, k);
if (!p) { if (!p) {
return {nullptr, OxError(1, "value not found for given key")}; return {nullptr, OxError(1, "value not found for given key")};
@ -148,8 +147,8 @@ constexpr Result<T*> SmallMap<K, T>::at(MaybeView_t<K> const&k) noexcept {
return &p->value; return &p->value;
} }
template<typename K, typename T> template<typename K, typename T, size_t SmallSz>
constexpr Result<const T*> SmallMap<K, T>::at(MaybeView_t<K> const&k) const noexcept { constexpr Result<const T*> SmallMap<K, T, SmallSz>::at(MaybeView_t<K> const&k) const noexcept {
auto p = access(m_pairs, k); auto p = access(m_pairs, k);
if (!p) { if (!p) {
return {nullptr, OxError(1, "value not found for given key")}; return {nullptr, OxError(1, "value not found for given key")};
@ -157,8 +156,8 @@ constexpr Result<const T*> SmallMap<K, T>::at(MaybeView_t<K> const&k) const noex
return &p->value; return &p->value;
} }
template<typename K, typename T> template<typename K, typename T, size_t SmallSz>
constexpr void SmallMap<K, T>::erase(MaybeView_t<K> const&k) { constexpr void SmallMap<K, T, SmallSz>::erase(MaybeView_t<K> const&k) {
size_t i{}; size_t i{};
for (auto const&p : m_pairs) { for (auto const&p : m_pairs) {
if (k == p.key) { if (k == p.key) {
@ -167,34 +166,62 @@ constexpr void SmallMap<K, T>::erase(MaybeView_t<K> const&k) {
++i; ++i;
} }
std::ignore = m_pairs.erase(i); std::ignore = m_pairs.erase(i);
std::ignore = m_keys.erase(i);
} }
template<typename K, typename T> template<typename K, typename T, size_t SmallSz>
constexpr bool SmallMap<K, T>::contains(MaybeView_t<K> const&k) const noexcept { constexpr bool SmallMap<K, T, SmallSz>::contains(MaybeView_t<K> const&k) const noexcept {
return access(m_pairs, k) != nullptr; return access(m_pairs, k) != nullptr;
} }
template<typename K, typename T> template<typename K, typename T, size_t SmallSz>
constexpr std::size_t SmallMap<K, T>::size() const noexcept { constexpr std::size_t SmallMap<K, T, SmallSz>::size() const noexcept {
return m_keys.size(); return m_pairs.size();
} }
template<typename K, typename T> template<typename K, typename T, size_t SmallSz>
constexpr Vector<K> const&SmallMap<K, T>::keys() const noexcept { constexpr Vector<K> SmallMap<K, T, SmallSz>::keys() const noexcept {
return m_keys; ox::Vector<K> keys;
keys.reserve(m_pairs.size());
for (auto const&p : m_pairs) {
keys.emplace_back(p.key);
}
return keys;
} }
template<typename K, typename T> template<typename K, typename T, size_t SmallSz>
constexpr void SmallMap<K, T>::clear() { constexpr K const&SmallMap<K, T, SmallSz>::key(size_t i) const noexcept {
return m_pairs[i].key;
}
template<typename K, typename T, size_t SmallSz>
constexpr T const&SmallMap<K, T, SmallSz>::value(size_t i) const noexcept {
return m_pairs[i].value;
}
template<typename K, typename T, size_t SmallSz>
constexpr T &SmallMap<K, T, SmallSz>::value(size_t i) noexcept {
return m_pairs[i].value;
}
template<typename K, typename T, size_t SmallSz>
constexpr SmallMap<K, T, SmallSz>::Pair const&SmallMap<K, T, SmallSz>::get(size_t i) const noexcept {
return m_pairs[i];
}
template<typename K, typename T, size_t SmallSz>
constexpr SmallMap<K, T, SmallSz>::Pair &SmallMap<K, T, SmallSz>::get(size_t i) noexcept {
return m_pairs[i];
}
template<typename K, typename T, size_t SmallSz>
constexpr void SmallMap<K, T, SmallSz>::clear() {
m_pairs.clear(); m_pairs.clear();
m_pairs.resize(127);
} }
template<typename K, typename T> template<typename K, typename T, size_t SmallSz>
template<typename KK> template<typename KK>
constexpr typename SmallMap<K, T>::Pair const&SmallMap<K, T>::access( constexpr typename SmallMap<K, T, SmallSz>::Pair const&SmallMap<K, T, SmallSz>::access(
Vector<Pair> const&pairs, KK const&k, bool &isNew) const { PairVector const&pairs, KK const&k, bool &isNew) const {
for (auto const&p : pairs) { for (auto const&p : pairs) {
if (p.key == k) { if (p.key == k) {
isNew = false; isNew = false;
@ -202,14 +229,13 @@ constexpr typename SmallMap<K, T>::Pair const&SmallMap<K, T>::access(
} }
} }
isNew = true; isNew = true;
m_keys.emplace_back(K(k));
return pairs.emplace_back(); return pairs.emplace_back();
} }
template<typename K, typename T> template<typename K, typename T, size_t SmallSz>
template<typename KK> template<typename KK>
constexpr typename SmallMap<K, T>::Pair &SmallMap<K, T>::access( constexpr typename SmallMap<K, T, SmallSz>::Pair &SmallMap<K, T, SmallSz>::access(
Vector<Pair> &pairs, KK const&k, bool &isNew) { PairVector &pairs, KK const&k, bool &isNew) {
for (auto &p : pairs) { for (auto &p : pairs) {
if (p.key == k) { if (p.key == k) {
isNew = false; isNew = false;
@ -217,10 +243,6 @@ constexpr typename SmallMap<K, T>::Pair &SmallMap<K, T>::access(
} }
} }
isNew = true; isNew = true;
if (static_cast<double>(m_pairs.size()) * 0.7 <
static_cast<double>(m_keys.size())) {
}
m_keys.emplace_back(K(k));
return pairs.emplace_back(); return pairs.emplace_back();
} }

View File

@ -12,8 +12,10 @@ add_test("[ox/std] ox_memcmp HIJKLMN != ABCDEFG" ${CMAKE_RUNTIME_OUTPUT_DIRECTOR
add_test("[ox/std] ox_memcmp ABCDEFG == ABCDEFG" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "ABCDEFG == ABCDEFG") add_test("[ox/std] ox_memcmp ABCDEFG == ABCDEFG" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "ABCDEFG == ABCDEFG")
add_test("[ox/std] ox_memcmp ABCDEFGHI == ABCDEFG" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "ABCDEFGHI == ABCDEFG") add_test("[ox/std] ox_memcmp ABCDEFGHI == ABCDEFG" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "ABCDEFGHI == ABCDEFG")
add_test("[ox/std] itoa" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "itoa") add_test("[ox/std] itoa" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "itoa")
add_test("[ox/std] BString" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "BString") add_test("[ox/std] IString" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "IString")
add_test("[ox/std] String" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "String") add_test("[ox/std] String" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "String")
add_test("[ox/std] SmallMap" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "SmallMap")
add_test("[ox/std] SmallMap2" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "SmallMap2")
add_test("[ox/std] Vector" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "Vector") add_test("[ox/std] Vector" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "Vector")
add_test("[ox/std] HashMap" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "HashMap") add_test("[ox/std] HashMap" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "HashMap")
add_test("[ox/std] HeapMgr" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest malloc) add_test("[ox/std] HeapMgr" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest malloc)

View File

@ -6,13 +6,112 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#include "ox/std/def.hpp" #if __has_include(<chrono>)
#include<chrono>
#endif
#include <ox/std/def.hpp>
#undef NDEBUG #undef NDEBUG
#include <map> #include <map>
#include <ox/std/uuid.hpp> #include <ox/std/uuid.hpp>
#include <ox/std/std.hpp> #include <ox/std/std.hpp>
[[nodiscard]]
static uint64_t nowMs() {
#if __has_include(<chrono>)
using namespace std::chrono;
return static_cast<uint64_t>(
duration_cast<milliseconds>(
system_clock::now().time_since_epoch()).count());
#else
return 0;
#endif
}
template<typename Map = ox::SmallMap<ox::String, ox::UUID>>
uint64_t timeMapStrToUuid(int elemCnt, int lookups, uint64_t seed = 4321) noexcept {
ox::UUID::seedGenerator({1234, seed});
Map map;
// setup test map
for (int i = 0; i < elemCnt; ++i) {
auto const uuid = ox::UUID::generate().unwrap();
map[uuid.toString()] = uuid;
}
auto const keys = map.keys();
ox::Random rand;
// start
auto const startTime = nowMs();
for (int i = 0; i < lookups; ++i) {
auto const&k = keys[rand.gen() % keys.size()];
map[k];
oxExpect(map[k], ox::UUID::fromString(k).unwrap());
}
return nowMs() - startTime;
}
template<typename Map = ox::SmallMap<ox::UUID, ox::String>>
uint64_t timeMapUuidToStr(int elemCnt, int lookups, uint64_t seed = 4321) noexcept {
ox::UUID::seedGenerator({1234, seed});
Map map;
// setup test map
for (int i = 0; i < elemCnt; ++i) {
auto const uuid = ox::UUID::generate().unwrap();
map[uuid] = uuid.toString();
}
auto const keys = map.keys();
ox::Random rand;
// start
auto const startTime = nowMs();
for (int i = 0; i < lookups; ++i) {
auto const&k = keys[rand.gen() % keys.size()];
oxExpect(map[k], k.toString());
}
return nowMs() - startTime;
}
static ox::Error compareMaps(int lookupCnt = 1'000'000) {
auto const seed = nowMs();
uint64_t hashTime{};
uint64_t smallTime{};
int elemCnt = 1;
oxOut("UUIDStr to UUID:\n\n");
while (hashTime >= smallTime) {
smallTime = timeMapStrToUuid<ox::SmallMap<ox::UUIDStr, ox::UUID>>(elemCnt, lookupCnt, seed);
hashTime = timeMapStrToUuid<ox::HashMap<ox::UUIDStr, ox::UUID>>(elemCnt, lookupCnt, seed);
oxOutf(
"UUIDStr to UUID: elemCnt: {}, lookupCnt: {} - hash map time: {}ms, small map time: {}ms\n",
elemCnt, lookupCnt, hashTime, smallTime);
++elemCnt;
}
oxOut("\n\nString to UUID:\n\n");
hashTime = 0;
smallTime = 0;
elemCnt = 1;
while (hashTime >= smallTime) {
smallTime = timeMapStrToUuid<ox::SmallMap<ox::String, ox::UUID>>(elemCnt, lookupCnt, seed);
hashTime = timeMapStrToUuid<ox::HashMap<ox::String, ox::UUID>>(elemCnt, lookupCnt, seed);
oxOutf(
"String to UUID: elemCnt: {}, lookupCnt: {} - hash map time: {}ms, small map time: {}ms\n",
elemCnt, lookupCnt, hashTime, smallTime);
++elemCnt;
}
oxOut("\n\nUUID to UUIDStr:\n\n");
hashTime = 0;
smallTime = 0;
elemCnt = 1;
while (hashTime >= smallTime) {
smallTime = timeMapUuidToStr<ox::SmallMap<ox::UUID, ox::UUIDStr>>(elemCnt, lookupCnt, seed);
hashTime = timeMapUuidToStr<ox::HashMap<ox::UUID, ox::UUIDStr>>(elemCnt, lookupCnt, seed);
oxOutf(
"UUID to UUIDStr: elemCnt: {}, lookupCnt: {} - hash map time: {}ms, small map time: {}ms\n",
elemCnt, lookupCnt, hashTime, smallTime);
++elemCnt;
}
oxOut("\n");
return {};
}
static std::map<ox::StringView, ox::Error(*)()> tests = { static std::map<ox::StringView, ox::Error(*)()> tests = {
{ {
"malloc", "malloc",
@ -23,6 +122,8 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
auto a2 = static_cast<char*>(ox::heapmgr::malloc(5)); auto a2 = static_cast<char*>(ox::heapmgr::malloc(5));
oxAssert(a1 >= buff.front().unwrap() && a1 < buff.back().unwrap(), "malloc is broken"); oxAssert(a1 >= buff.front().unwrap() && a1 < buff.back().unwrap(), "malloc is broken");
oxAssert(a2 >= buff.front().unwrap() && a2 < buff.back().unwrap() && a2 > a1 + 5, "malloc is broken"); oxAssert(a2 >= buff.front().unwrap() && a2 < buff.back().unwrap() && a2 > a1 + 5, "malloc is broken");
ox::heapmgr::free(a1);
ox::heapmgr::free(a2);
return OxError(0); return OxError(0);
} }
}, },
@ -67,14 +168,14 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
} }
}, },
{ {
"BString", "IString",
[]() { []() {
ox::IString<5> s; ox::IString<5> s;
oxReturnError(s.append("A")); oxReturnError(s.append("A"));
oxReturnError(s.append("B")); oxReturnError(s.append("B"));
oxReturnError(s.append("9")); oxReturnError(s.append("9"));
oxReturnError(s.append("C")); oxReturnError(s.append("C"));
oxAssert(s == "AB9C", "BString append broken"); oxAssert(s == "AB9C", "IString append broken");
s = "asdf"; s = "asdf";
oxAssert(s == "asdf", "String assign broken"); oxAssert(s == "asdf", "String assign broken");
oxAssert(s != "aoeu", "String assign broken"); oxAssert(s != "aoeu", "String assign broken");
@ -134,10 +235,38 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
return OxError(0); return OxError(0);
} }
}, },
{
"SmallMap",
[] {
ox::SmallMap<ox::String, ox::String> map;
map["asdf"] = "aoeu";
oxExpect(map["asdf"], "aoeu");
oxExpect(map.size(), 1u);
oxExpect(map["aoeu"], "");
oxExpect(map.size(), 2u);
return OxError(0);
}
},
{
"SmallMap2",
[] {
ox::SmallMap<ox::String, int> si;
si["asdf"] = 42;
si["aoeu"] = 100;
oxAssert(si["asdf"] == 42, "asdf != 42");
oxAssert(si["aoeu"] == 100, "aoeu != 100");
ox::SmallMap<int, int> ii;
ii[4] = 42;
ii[5] = 100;
oxAssert(ii[4] == 42, "4 != 42");
oxAssert(ii[5] == 100, "5 != 100");
return OxError(0);
}
},
{ {
"HashMap", "HashMap",
[] { [] {
ox::HashMap<const char*, int> si; ox::HashMap<ox::String, int> si;
si["asdf"] = 42; si["asdf"] = 42;
si["aoeu"] = 100; si["aoeu"] = 100;
oxAssert(si["asdf"] == 42, "asdf != 42"); oxAssert(si["asdf"] == 42, "asdf != 42");
@ -150,6 +279,26 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
return OxError(0); return OxError(0);
} }
}, },
{
"TimeSmallMapMillion",
[] {
timeMapStrToUuid<ox::SmallMap<ox::String, ox::UUID>>(1'000, 1'000'000);
return ox::Error{};
}
},
{
"TimeHashMapMillion",
[] {
timeMapStrToUuid<ox::HashMap<ox::String, ox::UUID>>(1'000, 1'000'000);
return ox::Error{};
}
},
{
"CompareMaps",
[] {
return compareMaps();
}
},
{ {
"Serialize-Int", "Serialize-Int",
[] { [] {

View File

@ -8,9 +8,11 @@
#pragma once #pragma once
#include "bit.hpp"
#include "ignore.hpp" #include "ignore.hpp"
#include "istring.hpp" #include "istring.hpp"
#include "buffer.hpp" #include "buffer.hpp"
#include "hash.hpp"
#include "random.hpp" #include "random.hpp"
#include "ranges.hpp" #include "ranges.hpp"
#include "stringview.hpp" #include "stringview.hpp"
@ -105,7 +107,7 @@ class UUID {
static ox::Result<UUID> generate() noexcept; static ox::Result<UUID> generate() noexcept;
[[nodiscard]] [[nodiscard]]
constexpr auto value() const noexcept { constexpr auto const&value() const noexcept {
return m_value; return m_value;
} }
@ -118,8 +120,8 @@ class UUID {
return false; return false;
} else { } else {
constexpr uint64_t zero = 0; constexpr uint64_t zero = 0;
return ox::memcmp(&zero, m_value.data() + 0, 8) == 0 return memcmp(&zero, m_value.data() + 0, 8) == 0
&& ox::memcmp(&zero, m_value.data() + 8, 8) == 0; && memcmp(&zero, m_value.data() + 8, 8) == 0;
} }
} }
@ -192,6 +194,24 @@ class UUID {
} }
}; };
template<>
struct hash<ox::UUID> {
[[nodiscard]]
constexpr size_t operator()(ox::UUID v) const noexcept {
size_t out{};
if (std::is_constant_evaluated()) {
for (auto i = 0u; i < sizeof(out); ++i) {
out |= static_cast<size_t>(v.value()[i]) << (i * 8);
}
} else {
memcpy(&out, &v, sizeof(out));
}
return out;
}
};
template<typename T> template<typename T>
constexpr Error model(T *io, ox::CommonPtrWith<UUID> auto *obj) noexcept { constexpr Error model(T *io, ox::CommonPtrWith<UUID> auto *obj) noexcept {
oxReturnError(io->template setTypeInfo<UUID>()); oxReturnError(io->template setTypeInfo<UUID>());

View File

@ -11,7 +11,7 @@ target_link_libraries(
target_compile_definitions( target_compile_definitions(
NostalgiaStudio PUBLIC NostalgiaStudio PUBLIC
OLYMPIC_APP_VERSION="dev build" OLYMPIC_APP_VERSION="d2024.05.0"
) )
install( install(

View File

@ -94,7 +94,7 @@ ox::Error preloadObj(
oxOutf("preloading {} as a {}\n", path, obj.type()->typeName); oxOutf("preloading {} as a {}\n", path, obj.type()->typeName);
// preload // preload
oxRequire(a, pl.startAlloc(ox::sizeOf<GbaPlatSpec>(&obj), ox::alignOf<GbaPlatSpec>(obj))); oxRequire(a, pl.startAlloc(ox::sizeOf<GbaPlatSpec>(&obj), ox::alignOf<GbaPlatSpec>(obj)));
auto const err = ox::preload<GbaPlatSpec, decltype(obj)>(&pl, &obj); auto const err = ox::preload<GbaPlatSpec, ox::ModelObject>(&pl, &obj);
oxReturnError(pl.endAlloc()); oxReturnError(pl.endAlloc());
oxReturnError(err); oxReturnError(err);
keel::PreloadPtr const p{.preloadAddr = static_cast<uint32_t>(a)}; keel::PreloadPtr const p{.preloadAddr = static_cast<uint32_t>(a)};