Compare commits

...

6 Commits

26 changed files with 270 additions and 368 deletions

View File

@ -14,7 +14,6 @@
import os import os
import platform import platform
import shutil import shutil
import socket
import subprocess import subprocess
import sys import sys
from typing import List, Optional from typing import List, Optional

View File

@ -98,6 +98,7 @@ constexpr ox::Error model(T *io, ox::CommonPtrWith<TestStruct> auto *obj) noexce
oxReturnError(io->field("BString", &obj->BString)); oxReturnError(io->field("BString", &obj->BString));
oxReturnError(io->field("List", obj->List, 4)); oxReturnError(io->field("List", obj->List, 4));
oxReturnError(io->field("Vector", &obj->Vector)); oxReturnError(io->field("Vector", &obj->Vector));
oxReturnError(io->field("Vector2", &obj->Vector2));
oxReturnError(io->field("Map", &obj->Map)); oxReturnError(io->field("Map", &obj->Map));
oxReturnError(io->field("Struct", &obj->Struct)); oxReturnError(io->field("Struct", &obj->Struct));
oxReturnError(io->field("EmptyStruct", &obj->EmptyStruct)); oxReturnError(io->field("EmptyStruct", &obj->EmptyStruct));

View File

@ -79,9 +79,6 @@ static_assert(isBasicString_v<ox::BasicString<0ul>>);
static_assert(isBasicString_v<ox::BasicString<8ul>>); static_assert(isBasicString_v<ox::BasicString<8ul>>);
static_assert(isBasicString_v<ox::String>); static_assert(isBasicString_v<ox::String>);
template<typename T>
constexpr bool isOxString_v = isBString_v<T> || isBasicString_v<T>;
template<typename T> template<typename T>
consteval bool isOxVector(const T*) noexcept { consteval bool isOxVector(const T*) noexcept {
return false; return false;

View File

@ -118,6 +118,7 @@ install(
std.hpp std.hpp
stddef.hpp stddef.hpp
string.hpp string.hpp
stringliteral.hpp
stringview.hpp stringview.hpp
strongint.hpp strongint.hpp
strops.hpp strops.hpp

View File

@ -23,35 +23,10 @@ concept CommonRefWith = ox::is_same_v<typename ox::remove_reference_t<const T&>,
template<typename T, typename U> template<typename T, typename U>
concept same_as = ox::is_same_v<T, T>; concept same_as = ox::is_same_v<T, T>;
template<std::size_t SmallStringSize> template<typename T>
class BasicString; concept OxString_c = isOxString_v<T>;
template<std::size_t sz>
class BString;
class StringView;
namespace detail {
constexpr auto isOxString(const auto*) noexcept {
return false;
}
template<std::size_t sz>
constexpr auto isOxString(const BasicString<sz>*) noexcept {
return true;
}
template<std::size_t sz>
constexpr auto isOxString(const BString<sz>*) noexcept {
return true;
}
constexpr auto isOxString(const StringView*) noexcept {
return true;
}
}
template<typename T> template<typename T>
concept OxString_c = detail::isOxString(static_cast<T*>(nullptr)); concept Integral_c = ox::is_integral_v<T>;
} }

View File

@ -9,6 +9,7 @@
#pragma once #pragma once
#include "algorithm.hpp" #include "algorithm.hpp"
#include "stringview.hpp"
#include "strops.hpp" #include "strops.hpp"
#include "vector.hpp" #include "vector.hpp"
@ -21,6 +22,21 @@ class HashMap {
using value_t = T; using value_t = T;
private: private:
// Maybe StringView. If K (or KK for MaybeSV) is a string type,
// MaybeSV::type/MaybeSV_t is a StringView.
// This avoids creating unnecessary Strings when taking a StringView or C
// string in lookups.
template<typename KK, bool isStr = isOxString_v<KK>>
struct MaybeSV {
using type = KK;
};
template<typename KK>
struct MaybeSV<KK, true> {
using type = ox::StringView;
};
template<typename KK>
using MaybeSV_t = MaybeSV<KK>::type;
struct Pair { struct Pair {
K key = {}; K key = {};
T value{}; T value{};
@ -31,62 +47,55 @@ class HashMap {
public: public:
explicit constexpr HashMap(std::size_t size = 100); explicit constexpr HashMap(std::size_t size = 100);
constexpr HashMap(const HashMap &other); constexpr HashMap(HashMap const&other);
constexpr HashMap(HashMap &&other) noexcept; constexpr HashMap(HashMap &&other) noexcept;
constexpr ~HashMap(); constexpr ~HashMap();
constexpr bool operator==(const HashMap &other) const; constexpr bool operator==(HashMap const&other) const;
constexpr HashMap &operator=(const HashMap &other); constexpr HashMap &operator=(HashMap const&other);
constexpr HashMap &operator=(HashMap &&other) noexcept; constexpr HashMap &operator=(HashMap &&other) noexcept;
/** constexpr T &operator[](MaybeSV_t<K> const&key);
* K is assumed to be a null terminated string.
*/
constexpr T &operator[](const K &key);
/** constexpr Result<T*> at(MaybeSV_t<K> const&key) noexcept;
* K is assumed to be a null terminated string.
*/
constexpr Result<T*> at(const K &key) noexcept;
/** constexpr Result<const T*> at(MaybeSV_t<K> const&key) const noexcept;
* K is assumed to be a null terminated string.
*/
constexpr Result<const T*> at(const K &key) const noexcept;
constexpr void erase(const K &key); constexpr void erase(MaybeSV_t<K> const&key);
constexpr bool contains(const K &key) const noexcept; [[nodiscard]]
constexpr bool contains(MaybeSV_t<K> const&key) const noexcept;
[[nodiscard]] [[nodiscard]]
constexpr std::size_t size() const noexcept; constexpr std::size_t size() const noexcept;
[[nodiscard]] [[nodiscard]]
constexpr const Vector<K> &keys() const noexcept; constexpr Vector<K> const&keys() const noexcept;
constexpr void clear(); constexpr void clear();
private: private:
constexpr void expand(); constexpr void expand();
/** constexpr static uint64_t hash(Integral_c auto) noexcept;
* K is assumed to be a null terminated string.
*/ constexpr static uint64_t hash(StringView const&) noexcept;
constexpr static uint64_t hash(auto) noexcept;
/** /**
* K is assumed to be a null terminated string. * K is assumed to be a null terminated string.
*/ */
constexpr Pair *const&access(const Vector<Pair*> &pairs, const K &key) const; template<typename KK>
constexpr Pair *const&access(Vector<Pair*> const&pairs, KK const&key) const;
/** /**
* K is assumed to be a null terminated string. * K is assumed to be a null terminated string.
*/ */
constexpr Pair *&access(Vector<Pair*> &pairs, const K &key); template<typename KK>
constexpr Pair *&access(Vector<Pair*> &pairs, KK const&key);
}; };
@ -95,7 +104,7 @@ constexpr HashMap<K, T>::HashMap(std::size_t size): m_pairs(size) {
} }
template<typename K, typename T> template<typename K, typename T>
constexpr HashMap<K, T>::HashMap(const HashMap<K, T> &other) { constexpr HashMap<K, T>::HashMap(HashMap<K, T> const&other) {
m_pairs = other.m_pairs; m_pairs = other.m_pairs;
} }
@ -111,7 +120,7 @@ constexpr HashMap<K, T>::~HashMap() {
} }
template<typename K, typename T> template<typename K, typename T>
constexpr bool HashMap<K, T>::operator==(const HashMap &other) const { constexpr bool HashMap<K, T>::operator==(HashMap const&other) const {
if (m_keys != other.m_keys) { if (m_keys != other.m_keys) {
return false; return false;
} }
@ -125,7 +134,7 @@ constexpr bool HashMap<K, T>::operator==(const HashMap &other) const {
} }
template<typename K, typename T> template<typename K, typename T>
constexpr HashMap<K, T> &HashMap<K, T>::operator=(const HashMap<K, T> &other) { constexpr HashMap<K, T> &HashMap<K, T>::operator=(HashMap<K, T> const&other) {
if (this != &other) { if (this != &other) {
clear(); clear();
m_keys = other.m_keys; m_keys = other.m_keys;
@ -145,7 +154,7 @@ constexpr HashMap<K, T> &HashMap<K, T>::operator=(HashMap<K, T> &&other) noexcep
} }
template<typename K, typename T> template<typename K, typename T>
constexpr T &HashMap<K, T>::operator[](const K &k) { constexpr T &HashMap<K, T>::operator[](MaybeSV_t<K> const&k) {
auto &p = access(m_pairs, k); auto &p = access(m_pairs, k);
if (p == nullptr) { if (p == nullptr) {
if (static_cast<double>(m_pairs.size()) * 0.7 < if (static_cast<double>(m_pairs.size()) * 0.7 <
@ -154,13 +163,13 @@ constexpr T &HashMap<K, T>::operator[](const K &k) {
} }
p = new Pair; p = new Pair;
p->key = k; p->key = k;
m_keys.push_back(k); m_keys.emplace_back(k);
} }
return p->value; return p->value;
} }
template<typename K, typename T> template<typename K, typename T>
constexpr Result<T*> HashMap<K, T>::at(const K &k) noexcept { constexpr Result<T*> HashMap<K, T>::at(MaybeSV_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")};
@ -169,7 +178,7 @@ constexpr Result<T*> HashMap<K, T>::at(const K &k) noexcept {
} }
template<typename K, typename T> template<typename K, typename T>
constexpr Result<const T*> HashMap<K, T>::at(const K &k) const noexcept { constexpr Result<const T*> HashMap<K, T>::at(MaybeSV_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")};
@ -178,7 +187,7 @@ constexpr Result<const T*> HashMap<K, T>::at(const K &k) const noexcept {
} }
template<typename K, typename T> template<typename K, typename T>
constexpr void HashMap<K, T>::erase(const K &k) { constexpr void HashMap<K, T>::erase(MaybeSV_t<K> const&k) {
if (!contains(k)) { if (!contains(k)) {
return; return;
} }
@ -196,7 +205,7 @@ constexpr void HashMap<K, T>::erase(const K &k) {
} }
template<typename K, typename T> template<typename K, typename T>
constexpr bool HashMap<K, T>::contains(const K &k) const noexcept { constexpr bool HashMap<K, T>::contains(MaybeSV_t<K> const&k) const noexcept {
return access(m_pairs, k) != nullptr; return access(m_pairs, k) != nullptr;
} }
@ -206,7 +215,7 @@ constexpr std::size_t HashMap<K, T>::size() const noexcept {
} }
template<typename K, typename T> template<typename K, typename T>
constexpr const Vector<K> &HashMap<K, T>::keys() const noexcept { constexpr Vector<K> const&HashMap<K, T>::keys() const noexcept {
return m_keys; return m_keys;
} }
@ -230,24 +239,28 @@ constexpr void HashMap<K, T>::expand() {
} }
template<typename K, typename T> template<typename K, typename T>
constexpr uint64_t HashMap<K, T>::hash(auto k) noexcept { constexpr uint64_t HashMap<K, T>::hash(Integral_c auto k) noexcept {
uint64_t sum = 1; uint64_t sum = 1;
if constexpr(is_integral_v<decltype(k)>) { for (auto i = 0u; i < sizeof(K); ++i) {
for (auto i = 0u; i < sizeof(K); ++i) { const auto shift = i * 8;
const auto shift = i * 8; const auto v = static_cast<uint64_t>(k >> shift & 0xff);
const auto v = static_cast<uint64_t>(k >> shift & 0xff); sum += (sum + v) * 7 * sum;
sum += (sum + v) * 7 * sum;
}
} else {
for (auto i = 0u; k[i]; ++i) {
sum += ((sum + static_cast<uint64_t>(k[i])) * 7) * sum;
}
} }
return sum; return sum;
} }
template<typename K, typename T> template<typename K, typename T>
constexpr typename HashMap<K, T>::Pair *const&HashMap<K, T>::access(const Vector<Pair*> &pairs, const K &k) const { 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>(hash(k) % pairs.size());
while (true) { while (true) {
const auto &p = pairs[h]; const auto &p = pairs[h];
@ -260,12 +273,13 @@ constexpr typename HashMap<K, T>::Pair *const&HashMap<K, T>::access(const Vector
} }
template<typename K, typename T> template<typename K, typename T>
constexpr typename HashMap<K, T>::Pair *&HashMap<K, T>::access(Vector<Pair*> &pairs, const K &k) { 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>(hash(k) % pairs.size());
while (true) { while (true) {
auto &p = pairs[h]; auto &p = pairs[h];
bool matches = [&] { bool matches = [&] {
if constexpr (is_integral_v<K>) { if constexpr (is_integral_v<KK>) {
return p == nullptr || k == p->key; return p == nullptr || k == p->key;
} else { } else {
return p == nullptr || ox_strcmp(p->key, k) == 0; return p == nullptr || ox_strcmp(p->key, k) == 0;

View File

@ -282,10 +282,10 @@ constexpr bool operator!=(std::nullptr_t, const UniquePtr<T> &p2) noexcept {
} }
template<typename T, typename ...Args> template<typename T, typename U = T, typename ...Args>
[[nodiscard]] [[nodiscard]]
constexpr auto make_unique(Args&&... args) { constexpr auto make_unique(Args&&... args) {
return UniquePtr(new T(ox::forward<Args>(args)...)); return UniquePtr<U>(new T(ox::forward<Args>(args)...));
} }
} }

View File

@ -35,9 +35,9 @@ constexpr void *operator new[](std::size_t, void *addr) noexcept {
namespace ox { namespace ox {
template<typename T, typename ...Args> template<typename T, typename U = T, typename ...Args>
[[nodiscard]] [[nodiscard]]
constexpr T *make(Args &&...args) noexcept { constexpr U *make(Args &&...args) noexcept {
#ifdef __cpp_exceptions #ifdef __cpp_exceptions
try { try {
return new T(ox::forward<Args>(args)...); return new T(ox::forward<Args>(args)...);

View File

@ -118,6 +118,8 @@ class BasicString {
constexpr BasicString &operator=(BasicString &&src) noexcept; constexpr BasicString &operator=(BasicString &&src) noexcept;
constexpr BasicString &operator=(CRStringView src) noexcept;
constexpr BasicString &operator+=(const char *str) noexcept; constexpr BasicString &operator+=(const char *str) noexcept;
constexpr BasicString &operator+=(char *str) noexcept; constexpr BasicString &operator+=(char *str) noexcept;
@ -341,7 +343,15 @@ constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operat
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(BasicString &&src) noexcept { constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(BasicString &&src) noexcept {
m_buff = std::move(src.m_buff); if (this != &src) {
m_buff = std::move(src.m_buff);
}
return *this;
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(CRStringView src) noexcept {
set(src);
return *this; return *this;
} }

47
deps/ox/src/ox/std/stringliteral.hpp vendored Normal file
View File

@ -0,0 +1,47 @@
/*
* Copyright 2015 - 2022 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
#include "basestringview.hpp"
namespace ox {
/**
* StringLiteral is used for functions that want to ensure that they are taking
* string literals, and not strings outside of the data section of the program
* that might get deleted.
* This type cannot force you to use it correctly, so don't give it something
* that is not a literal.
* If you do this:
* StringLiteral(str.c_str())
* the resulting segfault is on you.
*/
class StringLiteral: public detail::BaseStringView {
public:
constexpr StringLiteral() noexcept = default;
constexpr StringLiteral(StringLiteral const&sv) noexcept = default;
constexpr explicit StringLiteral(std::nullptr_t) noexcept {}
constexpr explicit StringLiteral(const char *str) noexcept: BaseStringView(str) {}
constexpr explicit StringLiteral(const char *str, std::size_t len) noexcept: BaseStringView(str, len) {}
constexpr auto &operator=(StringLiteral const&other) noexcept {
if (&other != this) {
set(other.data(), other.len());
}
return *this;
}
};
}

View File

@ -13,11 +13,11 @@
#endif #endif
#include "bit.hpp" #include "bit.hpp"
#include "concepts.hpp"
#include "iterator.hpp" #include "iterator.hpp"
#include "stringliteral.hpp"
#include "strops.hpp" #include "strops.hpp"
#include "types.hpp"
#include "vector.hpp" #include "vector.hpp"
#include "writer.hpp"
namespace ox { namespace ox {
@ -27,256 +27,68 @@ class BString;
template<std::size_t buffLen> template<std::size_t buffLen>
class BasicString; class BasicString;
class StringView { class StringView: public detail::BaseStringView {
public:
template<typename RefType = char&, typename PtrType = char*, bool reverse = false>
struct iterator: public Iterator<std::bidirectional_iterator_tag, char> {
private:
PtrType m_t = nullptr;
std::size_t m_offset = 0;
std::size_t m_max = 0;
public:
constexpr iterator() noexcept = default;
constexpr iterator(PtrType t, std::size_t offset, std::size_t max) noexcept {
m_t = t;
m_offset = offset;
m_max = max;
}
[[nodiscard]]
constexpr auto offset() const noexcept {
return m_offset;
}
constexpr iterator operator+(std::size_t s) const noexcept {
if constexpr(reverse) {
return iterator(m_t, max<std::size_t>(m_offset - s, 0), m_max);
} else {
return iterator(m_t, min<std::size_t>(m_offset + s, m_max), m_max);
}
}
constexpr auto operator-(const iterator &other) const noexcept {
if constexpr(reverse) {
return m_offset + other.m_offset;
} else {
return m_offset - other.m_offset;
}
}
constexpr iterator operator-(std::size_t s) const noexcept {
if constexpr(reverse) {
return iterator(m_t, min<std::size_t>(m_offset + s, m_max), m_max);
} else {
return iterator(m_t, max<std::size_t>(m_offset - s, 0), m_max);
}
}
constexpr iterator &operator+=(std::size_t s) noexcept {
if constexpr(reverse) {
m_offset = max<std::size_t>(m_offset - s, 0);
} else {
m_offset = min(m_offset + s, m_max);
}
return *this;
}
constexpr iterator &operator-=(std::size_t s) noexcept {
if constexpr(reverse) {
m_offset = min(m_offset + s, m_max);
} else {
m_offset = max<std::size_t>(m_offset - s, 0);
}
return *this;
}
constexpr iterator &operator++() noexcept {
return operator+=(1);
}
constexpr iterator &operator--() noexcept {
return operator-=(1);
}
constexpr RefType operator*() const noexcept {
return m_t[m_offset];
}
constexpr RefType operator[](std::size_t s) const noexcept {
return m_t[s];
}
constexpr bool operator<(const iterator &other) const noexcept {
return m_offset < other.m_offset;
}
constexpr bool operator>(const iterator &other) const noexcept {
return m_offset > other.m_offset;
}
constexpr bool operator<=(const iterator &other) const noexcept {
return m_offset <= other.m_offset;
}
constexpr bool operator>=(const iterator &other) const noexcept {
return m_offset >= other.m_offset;
}
constexpr bool operator==(const iterator &other) const noexcept {
return m_t == other.m_t && m_offset == other.m_offset && m_max == other.m_max;
}
constexpr bool operator!=(const iterator &other) const noexcept {
return m_t != other.m_t || m_offset != other.m_offset || m_max != other.m_max;
}
};
private:
const char *m_str = nullptr;
std::size_t m_len = 0;
public: public:
constexpr StringView() noexcept = default; constexpr StringView() noexcept = default;
constexpr StringView(const StringView &sv) noexcept = default; constexpr StringView(const StringView &sv) noexcept = default;
#ifdef OX_USE_STDLIB #ifdef OX_USE_STDLIB
constexpr StringView(const std::string_view &sv) noexcept: m_str(sv.data()), m_len(sv.size()) {} constexpr StringView(const std::string_view &sv) noexcept: BaseStringView(sv.data(), sv.size()) {}
#endif #endif
template<std::size_t SmallStrSz> constexpr StringView(BaseStringView const&str) noexcept: BaseStringView(str.data(), str.bytes()) {}
constexpr StringView(const BasicString<SmallStrSz> &str) noexcept: m_str(str.c_str()), m_len(str.len()) {}
template<std::size_t SmallStrSz> template<std::size_t SmallStrSz>
constexpr StringView(const BString<SmallStrSz> &str) noexcept: m_str(str.c_str()), m_len(str.len()) {} constexpr StringView(const BasicString<SmallStrSz> &str) noexcept: BaseStringView(str.data(), str.len()) {}
template<std::size_t SmallStrSz>
constexpr StringView(const BString<SmallStrSz> &str) noexcept: BaseStringView(str.data(), str.len()) {}
constexpr StringView(std::nullptr_t) noexcept {} constexpr StringView(std::nullptr_t) noexcept {}
constexpr StringView(const char *str) noexcept: m_str(str), m_len(str ? ox_strlen(str) : 0) {} constexpr StringView(const char *str) noexcept: BaseStringView(str) {}
constexpr StringView(const char *str, std::size_t len) noexcept: m_str(str), m_len(len) {} constexpr StringView(const char *str, std::size_t len) noexcept: BaseStringView(str, len) {}
[[nodiscard]] constexpr auto &operator=(StringView const&other) noexcept {
constexpr iterator<const char&, const char*> begin() const noexcept { if (&other != this) {
return {m_str, 0, m_len}; set(other.data(), other.len());
}
[[nodiscard]]
constexpr iterator<const char&, const char*> end() const noexcept {
return {m_str, m_len, m_len};
}
[[nodiscard]]
constexpr iterator<const char&, const char*> cbegin() const noexcept {
return {m_str, 0, m_len};
}
[[nodiscard]]
constexpr iterator<const char&, const char*> cend() const noexcept {
return {m_str, m_len, m_len};
}
[[nodiscard]]
constexpr iterator<const char&, const char*, true> crbegin() const noexcept {
return {m_str, m_len - 1, m_len};
}
[[nodiscard]]
constexpr iterator<const char&, const char*, true> crend() const noexcept {
return {m_str, MaxValue<std::size_t>, m_len};
}
[[nodiscard]]
constexpr iterator<const char&, const char*, true> rbegin() const noexcept {
return {m_str, m_len - 1, m_len};
}
[[nodiscard]]
constexpr iterator<const char&, const char*, true> rend() const noexcept {
return {m_str, MaxValue<std::size_t>, m_len};
}
[[nodiscard]]
constexpr auto bytes() const noexcept {
return m_len;
}
[[nodiscard]]
constexpr auto len() const noexcept {
return m_len;
}
[[nodiscard]]
constexpr auto *data() const noexcept {
return &m_str[0];
}
[[nodiscard]]
constexpr auto &front() const noexcept {
return m_str[0];
}
[[nodiscard]]
constexpr auto &back() const noexcept {
return m_str[m_len - 1];
}
[[nodiscard]]
constexpr auto substr(std::size_t pos) const noexcept {
if (m_len >= pos) {
return StringView(m_str + pos, m_len - pos);
}
return StringView();
}
[[nodiscard]]
constexpr auto substr(std::size_t start, std::size_t end) const noexcept {
if (m_len >= start && end >= start) {
return StringView(m_str + start, end - start);
}
return StringView();
}
constexpr auto operator[](std::size_t i) const noexcept {
return m_str[i];
}
constexpr ox::StringView &operator=(const StringView &other) noexcept = default;
constexpr auto operator==(const StringView &other) const noexcept {
if (other.len() != len()) {
return false;
}
return ox_strncmp(m_str, other.m_str, len()) == 0;
}
constexpr auto operator<=>(const StringView &str2) const noexcept {
const StringView &str1 = *this;
const auto maxLen = ox::min(str1.len(), str2.len());
const auto a = &str1.front();
const auto b = &str2.front();
for (std::size_t i = 0; i < maxLen && (a[i] || b[i]); ++i) {
if (a[i] < b[i]) {
return -1;
} else if (a[i] > b[i]) {
return 1;
}
}
if (str1.len() > str2.len()) {
return 1;
} else if (str1.len() < str2.len()) {
return -1;
} else {
return 0;
} }
return *this;
} }
}; };
using CRStringView = const StringView&; using CRStringView = const StringView&;
constexpr auto operator==(CRStringView s1, CRStringView s2) noexcept {
if (s2.len() != s1.len()) {
return false;
}
return ox_strncmp(s1.data(), s2.data(), s1.len()) == 0;
}
constexpr auto operator<=>(CRStringView s1, CRStringView s2) noexcept {
const auto maxLen = ox::min(s1.len(), s2.len());
const auto a = &s1.front();
const auto b = &s2.front();
for (std::size_t i = 0; i < maxLen && (a[i] || b[i]); ++i) {
if (a[i] < b[i]) {
return -1;
} else if (a[i] > b[i]) {
return 1;
}
}
if (s1.len() > s2.len()) {
return 1;
} else if (s1.len() < s2.len()) {
return -1;
} else {
return 0;
}
}
[[nodiscard]] [[nodiscard]]
constexpr bool beginsWith(CRStringView base, CRStringView beginning) noexcept { constexpr bool beginsWith(CRStringView base, CRStringView beginning) noexcept {
const auto beginningLen = ox::min(beginning.len(), base.len()); const auto beginningLen = ox::min(beginning.len(), base.len());
@ -302,7 +114,7 @@ constexpr std::size_t find(CRStringView str, char search) noexcept {
constexpr std::size_t find(CRStringView str, CRStringView search) noexcept { constexpr std::size_t find(CRStringView str, CRStringView search) noexcept {
std::size_t i = 0; std::size_t i = 0;
for (; i < str.len(); ++i) { for (; i < str.len(); ++i) {
if (beginsWith(str.substr(i), search)) { if (beginsWith(substr(str, i), search)) {
break; break;
} }
} }
@ -313,14 +125,14 @@ template<std::size_t smallSz = 0>
constexpr ox::Vector<ox::StringView, smallSz> split(CRStringView str, char del) noexcept { constexpr ox::Vector<ox::StringView, smallSz> split(CRStringView str, char del) noexcept {
ox::Vector<ox::StringView, smallSz> out; ox::Vector<ox::StringView, smallSz> out;
constexpr auto nextSeg = [](CRStringView current, char del) { constexpr auto nextSeg = [](CRStringView current, char del) {
return current.substr(find(current, del) + 1); return substr(current, find(current, del) + 1);
}; };
for (auto current = str; current.len(); current = nextSeg(current, del)) { for (auto current = str; current.len(); current = nextSeg(current, del)) {
const auto next = find(current, del); const auto next = find(current, del);
if (const auto s = current.substr(0, next); s.len()) { if (const auto s = substr(current, 0, next); s.len()) {
out.emplace_back(s); out.emplace_back(s);
} }
current = current.substr(next); current = substr(current, next);
} }
return out; return out;
} }
@ -329,14 +141,14 @@ template<std::size_t smallSz = 0>
constexpr ox::Vector<ox::StringView, smallSz> split(CRStringView str, CRStringView del) noexcept { constexpr ox::Vector<ox::StringView, smallSz> split(CRStringView str, CRStringView del) noexcept {
ox::Vector<ox::StringView, smallSz> out; ox::Vector<ox::StringView, smallSz> out;
constexpr auto nextSeg = [](CRStringView current, CRStringView del) { constexpr auto nextSeg = [](CRStringView current, CRStringView del) {
return current.substr(find(current, del) + del.len()); return substr(current, find(current, del) + del.len());
}; };
for (auto current = str; current.len(); current = nextSeg(current, del)) { for (auto current = str; current.len(); current = nextSeg(current, del)) {
const auto next = find(current, del); const auto next = find(current, del);
if (const auto s = current.substr(0, next); s.len()) { if (const auto s = substr(current, 0, next); s.len()) {
out.emplace_back(s); out.emplace_back(s);
} }
current = current.substr(next); current = substr(current, next);
} }
return out; return out;
} }

View File

@ -8,6 +8,7 @@
#pragma once #pragma once
#include "concepts.hpp"
#include "error.hpp" #include "error.hpp"
#include "math.hpp" #include "math.hpp"
#include "types.hpp" #include "types.hpp"
@ -128,6 +129,24 @@ constexpr int ox_lastIndexOf(const auto &str, int character, std::size_t maxLen
namespace ox { namespace ox {
template<OxString_c Str>
[[nodiscard]]
constexpr Str substr(Str const&str, std::size_t pos) noexcept {
if (str.len() >= pos) {
return Str(str.data() + pos, str.len() - pos);
}
return Str();
}
template<OxString_c Str>
[[nodiscard]]
constexpr Str substr(Str const&str, std::size_t start, std::size_t end) noexcept {
if (str.len() >= start && end >= start) {
return Str(str.data() + start, end - start);
}
return Str();
}
template<typename Integer> template<typename Integer>
constexpr ox::Error itoa(Integer v, ox::Writer_c auto &writer) noexcept { constexpr ox::Error itoa(Integer v, ox::Writer_c auto &writer) noexcept {
if (v) { if (v) {

View File

@ -105,6 +105,10 @@ static std::map<ox::String, ox::Error(*)()> tests = {
oxAssert(endsWith(str, "df"), "String endsWith is broken"); oxAssert(endsWith(str, "df"), "String endsWith is broken");
oxAssert(!endsWith(str, "awefawe"), "String endsWith is broken"); oxAssert(!endsWith(str, "awefawe"), "String endsWith is broken");
oxAssert(!endsWith(str, "eu"), "String endsWith is broken"); oxAssert(!endsWith(str, "eu"), "String endsWith is broken");
oxAssert(ox::StringView("Write") != ox::String(""), "String / StringView comparison broken");
oxAssert(ox::String("Write") != ox::StringView(""), "String / StringView comparison broken");
oxAssert(ox::String("Write") == ox::StringView("Write"), "String / StringView comparison broken");
oxAssert(ox::String(ox::StringView("Write")) == ox::StringView("Write"), "String / StringView comparison broken");
return OxError(0); return OxError(0);
} }
}, },

View File

@ -266,4 +266,43 @@ constexpr bool is_move_constructible(bool) {
template<class T> template<class T>
constexpr bool is_move_constructible_v = detail::is_move_constructible<T>(0); constexpr bool is_move_constructible_v = detail::is_move_constructible<T>(0);
// is String?
template<std::size_t SmallStringSize>
class BasicString;
template<std::size_t sz>
class BString;
class StringLiteral;
class StringView;
namespace detail {
constexpr auto isOxString(const auto*) noexcept {
return false;
}
template<std::size_t sz>
constexpr auto isOxString(const BasicString<sz>*) noexcept {
return true;
}
template<std::size_t sz>
constexpr auto isOxString(const BString<sz>*) noexcept {
return true;
}
constexpr auto isOxString(const StringLiteral*) noexcept {
return true;
}
constexpr auto isOxString(const StringView*) noexcept {
return true;
}
}
template<typename T>
constexpr auto isOxString_v = detail::isOxString(static_cast<T*>(nullptr));
} }

View File

@ -132,7 +132,7 @@ class UUID {
++i; ++i;
continue; continue;
} }
const auto seg = s.substr(i, i + 2); const auto seg = substr(s, i, i + 2);
if (seg.len() != 2) { if (seg.len() != 2) {
return OxError(1, "Invalid UUID"); return OxError(1, "Invalid UUID");
} }

View File

@ -324,7 +324,7 @@ constexpr Vector<T, SmallVectorSize, Allocator>::Vector(std::size_t size) noexce
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr Vector<T, SmallVectorSize, Allocator>::Vector(std::initializer_list<T> list) noexcept { constexpr Vector<T, SmallVectorSize, Allocator>::Vector(std::initializer_list<T> list) noexcept {
for (auto &item : list) { for (auto &item : list) {
emplace_back(item); emplace_back(std::move(item));
} }
} }

View File

@ -194,13 +194,13 @@ class AssetManager {
ox::HashMap<ox::String, ox::UniquePtr<AssetContainer<T>>> m_cache; ox::HashMap<ox::String, ox::UniquePtr<AssetContainer<T>>> m_cache;
public: public:
ox::Result<AssetRef<T>> getAsset(const ox::String &assetId) const noexcept { ox::Result<AssetRef<T>> getAsset(const ox::StringView &assetId) const noexcept {
auto out = m_cache.at(assetId); auto out = m_cache.at(assetId);
oxReturnError(out); oxReturnError(out);
return AssetRef<T>(out.value->get()); return AssetRef<T>(out.value->get());
} }
ox::Result<AssetRef<T>> setAsset(const ox::String &assetId, const T &obj) noexcept { ox::Result<AssetRef<T>> setAsset(const ox::StringView &assetId, const T &obj) noexcept {
auto &p = m_cache[assetId]; auto &p = m_cache[assetId];
if (!p) { if (!p) {
p = ox::make_unique<AssetContainer<T>>(obj); p = ox::make_unique<AssetContainer<T>>(obj);
@ -211,7 +211,7 @@ class AssetManager {
return AssetRef<T>(p.get()); return AssetRef<T>(p.get());
} }
ox::Result<AssetRef<T>> setAsset(const ox::String &assetId, T &&obj) noexcept { ox::Result<AssetRef<T>> setAsset(const ox::StringView &assetId, T &&obj) noexcept {
auto &p = m_cache[assetId]; auto &p = m_cache[assetId];
if (!p) { if (!p) {
p = ox::make_unique<AssetContainer<T>>(obj); p = ox::make_unique<AssetContainer<T>>(obj);
@ -247,13 +247,13 @@ class AssetManager {
public: public:
template<typename T> template<typename T>
ox::Result<AssetRef<T>> getAsset(const ox::String &assetId) noexcept { ox::Result<AssetRef<T>> getAsset(ox::CRStringView assetId) noexcept {
auto m = getTypeManager<T>(); auto m = getTypeManager<T>();
return m->getAsset(assetId); return m->getAsset(assetId);
} }
template<typename T> template<typename T>
ox::Result<AssetRef<T>> setAsset(const ox::String &assetId, const T &obj) noexcept { ox::Result<AssetRef<T>> setAsset(ox::CRStringView assetId, const T &obj) noexcept {
auto m = getTypeManager<T>(); auto m = getTypeManager<T>();
return m->setAsset(assetId, obj); return m->setAsset(assetId, obj);
} }

View File

@ -25,8 +25,11 @@ ox::Result<char*> loadRom(ox::CRStringView path) noexcept {
file.read(buff, size); file.read(buff, size);
return buff; return buff;
} catch (const std::ios_base::failure &e) { } catch (const std::ios_base::failure &e) {
oxErrorf("Could not read ROM file: {}", e.what()); oxErrorf("Could not read ROM file due to file IO failure: {}", e.what());
return OxError(2, "Could not read ROM file"); return OxError(2, "Could not read ROM file");
} catch (const std::bad_alloc &e) {
oxErrorf("Could not read ROM file due to new failure: {}", e.what());
return OxError(2, "Could not allocate memory for ROM file");
} }
} }
@ -142,7 +145,7 @@ ox::Error setRomFs(Context *ctx, ox::UPtr<ox::FileSystem> fs) noexcept {
ox::Result<ox::UniquePtr<ox::FileSystem>> loadRomFs(ox::CRStringView path) noexcept { ox::Result<ox::UniquePtr<ox::FileSystem>> loadRomFs(ox::CRStringView path) noexcept {
const auto lastDot = ox_lastIndexOf(path, '.'); const auto lastDot = ox_lastIndexOf(path, '.');
const auto fsExt = lastDot != -1 ? path.substr(static_cast<std::size_t>(lastDot)) : ""; const auto fsExt = lastDot != -1 ? substr(path, static_cast<std::size_t>(lastDot)) : "";
if (ox_strcmp(fsExt, ".oxfs") == 0) { if (ox_strcmp(fsExt, ".oxfs") == 0) {
oxRequire(rom, loadRom(path)); oxRequire(rom, loadRom(path));
return {ox::make_unique<ox::FileSystem32>(rom, 32 * ox::units::MB, unloadRom)}; return {ox::make_unique<ox::FileSystem32>(rom, 32 * ox::units::MB, unloadRom)};

View File

@ -52,28 +52,24 @@ ox::Result<keel::AssetRef<T>> readObjFile(
ox::StringView path; ox::StringView path;
ox::UUIDStr uuidStr; ox::UUIDStr uuidStr;
if (beginsWith(assetId, "uuid://")) { if (beginsWith(assetId, "uuid://")) {
assetId = assetId.substr(7); assetId = substr(assetId, 7);
path = ctx->uuidToPath[assetId]; path = ctx->uuidToPath[assetId];
} else { } else {
path = assetId; path = assetId;
// Warning: StringView to String uuidStr = ctx->pathToUuid[path].toString();
uuidStr = ctx->pathToUuid[ox::String(path)].toString();
assetId = uuidStr; assetId = uuidStr;
} }
if (forceLoad) { if (forceLoad) {
oxRequire(buff, ctx->rom->read(path)); oxRequire(buff, ctx->rom->read(path));
oxRequire(obj, readConvert(ctx, buff)); oxRequire(obj, readConvert(ctx, buff));
// Warning: StringView to String oxRequire(cached, ctx->assetManager.setAsset(assetId, obj));
oxRequire(cached, ctx->assetManager.setAsset(ox::String(assetId), obj));
return cached; return cached;
} else { } else {
// Warning: StringView to String auto [cached, err] = ctx->assetManager.getAsset<T>(assetId);
auto [cached, err] = ctx->assetManager.getAsset<T>(ox::String(assetId));
if (err) { if (err) {
oxRequire(buff, ctx->rom->read(path)); oxRequire(buff, ctx->rom->read(path));
oxRequire(obj, readConvert(ctx, buff)); oxRequire(obj, readConvert(ctx, buff));
// Warning: StringView to String oxReturnError(ctx->assetManager.setAsset(assetId, obj).moveTo(&cached));
oxReturnError(ctx->assetManager.setAsset(ox::String(assetId), obj).moveTo(&cached));
} }
return cached; return cached;
} }
@ -107,14 +103,12 @@ ox::Result<AssetRef<T>> setAsset(keel::Context *ctx, ox::StringView assetId, T c
} }
ox::UUIDStr idStr; ox::UUIDStr idStr;
if (assetId[0] == '/') { if (assetId[0] == '/') {
// Warning: StringView to String const auto [id, err] = ctx->pathToUuid.at(assetId);
const auto [id, err] = ctx->pathToUuid.at(ox::String(assetId));
oxReturnError(err); oxReturnError(err);
idStr = id->toString(); idStr = id->toString();
assetId = idStr; assetId = idStr;
} }
// Warning: StringView to String return ctx->assetManager.setAsset(assetId, asset);
return ctx->assetManager.setAsset(ox::String(assetId), asset);
#else #else
return OxError(1, "Not supported on this platform"); return OxError(1, "Not supported on this platform");
#endif #endif

View File

@ -31,7 +31,7 @@ static ox::Error pathToInode(
} }
if (beginsWith(path, "uuid://")) { if (beginsWith(path, "uuid://")) {
#ifndef OX_BARE_METAL #ifndef OX_BARE_METAL
const auto uuid = ox::StringView(path).substr(7); const auto uuid = substr(ox::StringView(path), 7);
path = ctx->uuidToPath[uuid]; path = ctx->uuidToPath[uuid];
#else #else
return OxError(1, "UUID to path conversion not supported on this platform"); return OxError(1, "UUID to path conversion not supported on this platform");

View File

@ -29,10 +29,10 @@ class StudioModule: public studio::Module {
}; };
} }
ox::Vector<ox::UniquePtr<studio::ItemMaker>> itemMakers(turbine::Context*) const noexcept final { ox::Vector<ox::UPtr<studio::ItemMaker>> itemMakers(turbine::Context*) const noexcept final {
ox::Vector<ox::UniquePtr<studio::ItemMaker>> out; ox::Vector<ox::UniquePtr<studio::ItemMaker>> out;
out.emplace_back(ox::make<studio::ItemMakerT<core::TileSheet>>("Tile Sheet", "TileSheets", "ng")); out.emplace_back(ox::make<studio::ItemMakerT<core::TileSheet>>("Tile Sheet", "TileSheets", FileExt_ng));
out.emplace_back(ox::make<studio::ItemMakerT<core::Palette>>("Palette", "Palettes", "npal")); out.emplace_back(ox::make<studio::ItemMakerT<core::Palette>>("Palette", "Palettes", FileExt_npal));
return out; return out;
} }
}; };

View File

@ -632,7 +632,7 @@ ox::StringView TileSheetEditorModel::palPath() const noexcept {
} }
constexpr ox::StringView uuidPrefix = "uuid://"; constexpr ox::StringView uuidPrefix = "uuid://";
if (ox::beginsWith(path, uuidPrefix)) { if (ox::beginsWith(path, uuidPrefix)) {
auto uuid = ox::StringView(path + uuidPrefix.bytes(), ox_strlen(path) - uuidPrefix.bytes()); auto uuid = ox::StringView(path.data() + uuidPrefix.bytes(), path.bytes() - uuidPrefix.bytes());
auto out = m_ctx->keelCtx.uuidToPath.at(uuid); auto out = m_ctx->keelCtx.uuidToPath.at(uuid);
if (out.error) { if (out.error) {
return {}; return {};

View File

@ -35,17 +35,7 @@ int main(int argc, const char **argv) {
#endif #endif
OX_INIT_DEBUG_LOGGER(loggerConn, "Nostalgia Player") OX_INIT_DEBUG_LOGGER(loggerConn, "Nostalgia Player")
ox::Error err; ox::Error err;
#ifdef __cpp_exceptions
try {
err = run(argc, argv);
} catch (ox::Exception const&ex) {
err = ex.toError();
} catch (...) {
err = OxError(1, "Non-Ox exception");
}
#else
err = run(argc, argv); err = run(argc, argv);
#endif
oxAssert(err, "Something went wrong..."); oxAssert(err, "Something went wrong...");
return static_cast<int>(err); return static_cast<int>(err);
} }

View File

@ -33,7 +33,7 @@ constexpr ox::Result<ox::StringView> fileExt(ox::CRStringView path) noexcept {
if (!extStart) { if (!extStart) {
return OxError(1, "Cannot open a file without valid extension."); return OxError(1, "Cannot open a file without valid extension.");
} }
return path.substr(extStart + 1); return substr(path, extStart + 1);
} }
class Project { class Project {

View File

@ -104,7 +104,7 @@ ox::Error BaseEditor::saveItem() noexcept {
ox::StringView BaseEditor::pathToItemName(ox::CRStringView path) noexcept { ox::StringView BaseEditor::pathToItemName(ox::CRStringView path) noexcept {
const auto lastSlash = std::find(path.rbegin(), path.rend(), '/').offset(); const auto lastSlash = std::find(path.rbegin(), path.rend(), '/').offset();
return path.substr(lastSlash + 1); return substr(path, lastSlash + 1);
} }
void BaseEditor::setRequiresConstantRefresh(bool value) noexcept { void BaseEditor::setRequiresConstantRefresh(bool value) noexcept {

View File

@ -23,7 +23,7 @@ static void generateTypes(ox::TypeStore *ts) noexcept {
Project::Project(keel::Context *ctx, ox::String path, ox::CRStringView projectDataDir) noexcept: Project::Project(keel::Context *ctx, ox::String path, ox::CRStringView projectDataDir) noexcept:
m_ctx(ctx), m_ctx(ctx),
m_path(path), m_path(std::move(path)),
m_projectDataDir(projectDataDir), m_projectDataDir(projectDataDir),
m_typeStore(ctx->rom.get(), ox::sfmt("/.{}/type_descriptors", projectDataDir)), m_typeStore(ctx->rom.get(), ox::sfmt("/.{}/type_descriptors", projectDataDir)),
m_fs(ctx->rom.get()) { m_fs(ctx->rom.get()) {
@ -57,8 +57,7 @@ bool Project::exists(ox::CRStringView path) const noexcept {
} }
const ox::Vector<ox::String> &Project::fileList(ox::CRStringView ext) noexcept { const ox::Vector<ox::String> &Project::fileList(ox::CRStringView ext) noexcept {
// Warning: StringView to String return m_fileExtFileMap[ext];
return m_fileExtFileMap[ox::String(ext)];
} }
void Project::buildFileIndex() noexcept { void Project::buildFileIndex() noexcept {
@ -81,8 +80,7 @@ void Project::indexFile(ox::CRStringView path) noexcept {
if (err) { if (err) {
return; return;
} }
// Warning: StringView to String m_fileExtFileMap[ext].emplace_back(path);
m_fileExtFileMap[ox::String(ext)].emplace_back(path);
} }
ox::Error Project::writeBuff(const ox::StringView &path, const ox::Buffer &buff) noexcept { ox::Error Project::writeBuff(const ox::StringView &path, const ox::Buffer &buff) noexcept {
@ -90,8 +88,7 @@ ox::Error Project::writeBuff(const ox::StringView &path, const ox::Buffer &buff)
ox::Buffer outBuff; ox::Buffer outBuff;
outBuff.reserve(buff.size() + HdrSz); outBuff.reserve(buff.size() + HdrSz);
ox::BufferWriter writer(&outBuff); ox::BufferWriter writer(&outBuff);
// Warning: StringView to String const auto [uuid, err] = m_ctx->pathToUuid.at(path);
const auto [uuid, err] = m_ctx->pathToUuid.at(ox::String(path));
if (!err) { if (!err) {
oxReturnError(keel::writeUuidHeader(writer, *uuid)); oxReturnError(keel::writeUuidHeader(writer, *uuid));
} }