Squashed 'deps/nostalgia/' content from commit 9cb6bd4a

git-subtree-dir: deps/nostalgia
git-subtree-split: 9cb6bd4a32e9f39a858f72443ff5c6d40489fe22
This commit is contained in:
2023-12-23 14:17:05 -06:00
commit 587dd92414
1112 changed files with 283489 additions and 0 deletions

145
deps/ox/src/ox/std/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,145 @@
if(OX_USE_STDLIB AND OX_ENABLE_TRACEHOOK)
add_library(
OxTraceHook SHARED
tracehook.cpp
)
else()
add_library(
OxTraceHook
tracehook.cpp
)
endif()
target_compile_definitions(
OxTraceHook PUBLIC
$<$<BOOL:${OX_BARE_METAL}>:OX_BARE_METAL>
$<$<BOOL:${OX_USE_STDLIB}>:OX_USE_STDLIB>
$<$<BOOL:${OX_NODEBUG}>:OX_NODEBUG>
)
add_library(
OxStd
assert.cpp
bit.cpp
buffer.cpp
buildinfo.cpp
byteswap.cpp
concepts.cpp
fmt.cpp
heapmgr.cpp
math.cpp
memops.cpp
random.cpp
reader.cpp
substitutes.cpp
stacktrace.cpp
string.cpp
stringview.cpp
strops.cpp
trace.cpp
typetraits.cpp
uuid.cpp
vec.cpp
)
if(NOT MSVC)
target_compile_options(OxStd PRIVATE -Wsign-conversion)
target_compile_options(OxStd PRIVATE -Wconversion)
if(${OX_OS_LINUX})
target_compile_options(OxStd PUBLIC -export-dynamic)
#target_link_options(OxStd PUBLIC -W1,-E)
elseif(${OX_OS_FREEBSD})
target_link_libraries(
OxStd PUBLIC
execinfo
)
endif()
endif()
if(NOT OX_BARE_METAL)
set_property(
TARGET
OxStd
PROPERTY
POSITION_INDEPENDENT_CODE ON
)
endif()
target_compile_definitions(
OxStd PUBLIC
$<$<BOOL:${OX_USE_STDLIB}>:OX_USE_STDLIB>
$<$<BOOL:${OX_NODEBUG}>:OX_NODEBUG>
)
if(NOT WIN32)
target_link_libraries(
OxStd PUBLIC
$<$<CXX_COMPILER_ID:GNU>:$<$<BOOL:${OX_USE_STDLIB}>:dl>>
)
endif()
target_link_libraries(
OxStd PUBLIC
$<$<CXX_COMPILER_ID:GNU>:gcc>
OxTraceHook
)
install(
FILES
algorithm.hpp
array.hpp
assert.hpp
bit.hpp
bounds.hpp
bstring.hpp
buffer.hpp
buildinfo.hpp
byteswap.hpp
concepts.hpp
def.hpp
defer.hpp
defines.hpp
error.hpp
fmt.hpp
hardware.hpp
hashmap.hpp
heapmgr.hpp
iterator.hpp
math.hpp
memops.hpp
memory.hpp
new.hpp
optional.hpp
point.hpp
random.hpp
ranges.hpp
serialize.hpp
size.hpp
stacktrace.hpp
std.hpp
stddef.hpp
string.hpp
stringliteral.hpp
stringview.hpp
strongint.hpp
strops.hpp
trace.hpp
typeinfo.hpp
types.hpp
typetraits.hpp
units.hpp
uuid.hpp
vec.hpp
vector.hpp
writer.hpp
DESTINATION
include/ox/std
)
install(TARGETS OxStd OxTraceHook
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
if(OX_RUN_TESTS)
add_subdirectory(test)
endif()

43
deps/ox/src/ox/std/algorithm.hpp vendored Normal file
View File

@@ -0,0 +1,43 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
namespace ox {
template<typename It, typename T>
constexpr It find(It begin, It end, const T &value) {
for (; begin != end; ++begin) {
if (*begin == value) {
return begin;
}
}
return end;
}
template<typename It>
constexpr It find_if(It begin, It end, auto predicate) {
for (; begin != end; ++begin) {
if (predicate(*begin)) {
return begin;
}
}
return end;
}
template<typename It, typename Size, typename OutIt>
constexpr OutIt copy_n(It in, Size cnt, OutIt out) {
for (Size i = 0; i < cnt; ++i) {
*out = *in;
++out;
++in;
}
return out;
}
}

195
deps/ox/src/ox/std/array.hpp vendored Normal file
View File

@@ -0,0 +1,195 @@
/*
* Copyright 2015 - 2023 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "bit.hpp"
#include "error.hpp"
#include "initializerlist.hpp"
#include "iterator.hpp"
#include "math.hpp"
#include "memory.hpp"
#include "new.hpp"
#include "types.hpp"
#include "utility.hpp"
namespace ox {
template<typename T, std::size_t ArraySize>
class Array {
public:
using value_type = T;
using size_type = std::size_t;
template<typename RefType = T&, typename PtrType = T*, bool reverse = false>
using iterator = SpanIterator<T, RefType, PtrType, reverse>;
private:
T m_items[ArraySize]{};
public:
constexpr Array() noexcept = default;
constexpr Array(std::initializer_list<T> list) noexcept;
constexpr Array(const Array &other);
constexpr Array(Array &&other) noexcept;
~Array() = default;
constexpr iterator<> begin() noexcept {
return iterator<>(&m_items[0], 0, ArraySize);
}
constexpr iterator<> end() noexcept {
return iterator<>(&m_items[0], ArraySize, ArraySize);
}
constexpr iterator<const T&, const T*> begin() const noexcept {
return iterator<const T&, const T*>(&m_items[0], 0, ArraySize);
}
constexpr iterator<const T&, const T*> end() const noexcept {
return iterator<const T&, const T*>(&m_items[0], ArraySize, ArraySize);
}
constexpr iterator<T&, T*, true> rbegin() noexcept {
return iterator<T&, T*, true>(&m_items[0], ArraySize - 1, ArraySize);
}
constexpr iterator<T&, T*, true> rend() noexcept {
return iterator<T&, T*, true>(&m_items[0], MaxValue<size_type>, ArraySize);
}
constexpr iterator<const T&, const T*, true> rbegin() const noexcept {
return iterator<const T&, const T*, true>(m_items, ArraySize - 1, ArraySize);
}
constexpr iterator<const T&, const T*, true> rend() const noexcept {
return iterator<const T&, const T*, true>(m_items, MaxValue<size_type>, ArraySize);
}
constexpr bool operator==(const Array &other) const;
constexpr Array &operator=(const Array &other);
constexpr Array &operator=(Array &&other) noexcept;
constexpr T &operator[](std::size_t i) noexcept;
constexpr const T &operator[](std::size_t i) const noexcept;
[[nodiscard]]
constexpr std::size_t size() const noexcept;
[[nodiscard]]
constexpr T *data() noexcept {
return m_items;
}
[[nodiscard]]
constexpr const T *data() const noexcept {
return m_items;
}
[[nodiscard]]
constexpr bool contains(const T&) const;
};
template<typename T, std::size_t ArraySize, typename RefType, bool reverse>
using ArrayIt = typename Array<T, ArraySize>::template iterator<RefType, reverse>;
template<typename T, std::size_t ArraySize, typename RefType, bool reverse>
constexpr ArrayIt<T, ArraySize, RefType, reverse> operator+(std::size_t n, const ArrayIt<T, ArraySize, RefType, reverse> &a) {
return a + n;
}
template<typename T, std::size_t ArraySize>
constexpr Array<T, ArraySize>::Array(std::initializer_list<T> list) noexcept {
for (auto i = 0ul; auto &item : list) {
this->operator[](i) = item;
++i;
}
}
template<typename T, std::size_t ArraySize>
constexpr Array<T, ArraySize>::Array(const Array &other) {
for (std::size_t i = 0; i < ArraySize; ++i) {
m_items[i] = T(other.m_items[i]);
}
}
template<typename T, std::size_t ArraySize>
constexpr Array<T, ArraySize>::Array(Array &&other) noexcept {
if (this != &other) {
for (std::size_t i = 0; i < ArraySize; ++i) {
m_items[i] = T(std::move(other.m_items[i]));
}
}
}
template<typename T, std::size_t ArraySize>
constexpr bool Array<T, ArraySize>::operator==(const Array &other) const {
for (std::size_t i = 0; i < ArraySize; i++) {
if (!(m_items[i] == other.m_items[i])) {
return false;
}
}
return true;
}
template<typename T, std::size_t ArraySize>
constexpr Array<T, ArraySize> &Array<T, ArraySize>::operator=(const Array &other) {
if (this != &other) {
for (std::size_t i = 0; i < ArraySize; ++i) {
m_items[i] = other.m_items[i];
}
}
return *this;
return *this;
}
template<typename T, std::size_t ArraySize>
constexpr Array<T, ArraySize> &Array<T, ArraySize>::operator=(Array &&other) noexcept {
if (this != &other) {
for (std::size_t i = 0; i < ArraySize; ++i) {
m_items[i] = std::move(other.m_items[i]);
}
}
return *this;
}
template<typename T, std::size_t ArraySize>
constexpr T &Array<T, ArraySize>::operator[](std::size_t i) noexcept {
return m_items[i];
}
template<typename T, std::size_t ArraySize>
constexpr const T &Array<T, ArraySize>::operator[](std::size_t i) const noexcept {
return m_items[i];
}
template<typename T, std::size_t ArraySize>
constexpr std::size_t Array<T, ArraySize>::size() const noexcept {
return ArraySize;
}
template<typename T, std::size_t ArraySize>
constexpr bool Array<T, ArraySize>::contains(const T &v) const {
for (std::size_t i = 0; i < ArraySize; i++) {
if (m_items[i] == v) {
return true;
}
}
return false;
}
}

34
deps/ox/src/ox/std/assert.cpp vendored Normal file
View File

@@ -0,0 +1,34 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#include "stacktrace.hpp"
#include "trace.hpp"
#include "assert.hpp"
namespace ox {
void panic(const char *file, int line, const char *panicMsg, const Error &err) noexcept {
oxErrf("\033[31;1;1mPANIC:\033[0m [{}:{}]: {}\n", file, line, panicMsg);
if (err.msg) {
oxErrf("\tError Message:\t{}\n", err.msg);
}
oxErrf("\tError Code:\t{}\n", static_cast<ErrorCode>(err));
if (err.file != nullptr) {
oxErrf("\tError Location:\t{}:{}\n", err.file, err.line);
}
#ifdef OX_USE_STDLIB
printStackTrace(2);
oxTrace("panic").del("") << "Panic: " << panicMsg << " (" << file << ":" << line << ")";
std::abort();
#else
while (1);
#endif
}
}

96
deps/ox/src/ox/std/assert.hpp vendored Normal file
View File

@@ -0,0 +1,96 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
#if defined(OX_USE_STDLIB)
#include <iostream>
#endif
#include "def.hpp"
#include "defines.hpp"
#include "error.hpp"
#include "realstd.hpp"
#include "stacktrace.hpp"
#include "trace.hpp"
#include "typetraits.hpp"
namespace ox {
void panic(CRStringView file, int line, CRStringView panicMsg, const Error &err = OxError(0)) noexcept;
constexpr void constexprPanic(CRStringView file, int line, CRStringView panicMsg, const Error &err = OxError(0)) noexcept {
if (!std::is_constant_evaluated()) {
panic(file, line, panicMsg, err);
} else {
while (true);
}
}
constexpr void assertFunc(CRStringView file, int line, bool pass, [[maybe_unused]]CRStringView assertTxt, [[maybe_unused]]CRStringView msg) noexcept {
if (!pass) {
if (!std::is_constant_evaluated()) {
#ifdef OX_USE_STDLIB
oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, msg);
printStackTrace(2);
oxTracef("assert", "Failed assert: {} ({}) [{}:{}]", msg, assertTxt, file, line);
std::abort();
#else
oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, msg);
oxTracef("assert", "Failed assert: {} ({}) [{}:{}]", msg, assertTxt, file, line);
constexprPanic(file, line, msg);
#endif
} else {
while (true);
}
}
}
constexpr void assertFunc(CRStringView file, int line, const Error &err, CRStringView, CRStringView assertMsg) noexcept {
if (err) {
if (!std::is_constant_evaluated()) {
#if defined(OX_USE_STDLIB)
oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, assertMsg);
if (err.msg) {
oxErrf("\tError Message:\t{}\n", err.msg);
}
oxErrf("\tError Code:\t{}\n", static_cast<ErrorCode>(err));
if (err.file != nullptr) {
oxErrf("\tError Location:\t{}:{}\n", err.file, err.line);
}
printStackTrace(2);
oxTracef("assert", "Failed assert: {} [{}:{}]", assertMsg, file, line);
std::abort();
#else
constexprPanic(file, line, assertMsg);
#endif
} else {
while (true);
}
}
}
constexpr void expect(CRStringView file, int line, const auto &actual, const auto &expected) noexcept {
if (actual != expected) {
if (!std::is_constant_evaluated()) {
#if defined(OX_USE_STDLIB)
oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, "Value incorrect");
oxErrf("expected: {}\nactual: {}\n", detail::toStringView<true>(expected), detail::toStringView<true>(actual));
printStackTrace(2);
oxTracef("assert.expect", "Failed assert: {} == {} [{}:{}]", detail::toStringView<true>(actual), detail::toStringView<true>(expected), file, line);
std::abort();
#else
constexprPanic(file, line, "Comparison failed");
#endif
} else {
while (true);
}
}
}
}

217
deps/ox/src/ox/std/basestringview.hpp vendored Normal file
View File

@@ -0,0 +1,217 @@
/*
* Copyright 2015 - 2023 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 "bit.hpp"
#include "cstrops.hpp"
#include "iterator.hpp"
namespace ox::detail {
class 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;
protected:
constexpr BaseStringView() noexcept = default;
constexpr BaseStringView(BaseStringView const&sv) noexcept = default;
constexpr explicit BaseStringView(std::nullptr_t) noexcept {}
constexpr explicit BaseStringView(const char *str) noexcept: m_str(str), m_len(str ? ox_strlen(str) : 0) {}
constexpr explicit BaseStringView(const char *str, std::size_t len) noexcept: m_str(str), m_len(len) {}
public:
[[nodiscard]]
constexpr iterator<const char&, const char*> begin() const noexcept {
return {m_str, 0, m_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 operator[](std::size_t i) const noexcept {
return m_str[i];
}
protected:
constexpr void set(const char *str, std::size_t len) noexcept {
m_str = str;
m_len = len;
}
};
}

23
deps/ox/src/ox/std/bit.cpp vendored Normal file
View File

@@ -0,0 +1,23 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#include "bit.hpp"
static_assert(ox::onMask<int>(1) == 0b0001);
static_assert(ox::onMask<int>(2) == 0b0011);
static_assert(ox::onMask<int>(3) == 0b0111);
static_assert(ox::onMask<int>(4) == 0b1111);
static_assert(ox::MaxValue<int8_t> == 127);
static_assert(ox::MaxValue<int16_t> == 32767);
static_assert(ox::MaxValue<int32_t> == 2147483647);
static_assert(ox::MaxValue<int64_t> == 9223372036854775807);
static_assert(ox::MaxValue<uint8_t> == 255);
static_assert(ox::MaxValue<uint16_t> == 65535);
static_assert(ox::MaxValue<uint32_t> == 4294967295);
static_assert(ox::MaxValue<uint64_t> == 18446744073709551615u);

61
deps/ox/src/ox/std/bit.hpp vendored Normal file
View File

@@ -0,0 +1,61 @@
/*
* Copyright 2015 - 2023 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
#if defined(OX_USE_STDLIB)
#include <bit>
#endif
#include "defines.hpp"
#include "memops.hpp"
#include "types.hpp"
#include "typetraits.hpp"
#if !defined(OX_USE_STDLIB)
namespace std {
template<typename To, typename From>
[[nodiscard]]
constexpr To bit_cast(const From &src) noexcept requires(sizeof(To) == sizeof(From)) {
return __builtin_bit_cast(To, src);
}
}
#endif
namespace ox {
template<typename To, typename From>
constexpr typename enable_if<sizeof(To) == sizeof(From), To>::type cbit_cast(From src) noexcept {
To dst = {};
ox_memcpy(&dst, &src, sizeof(src));
return dst;
}
template<typename T>
[[nodiscard]]
constexpr T rotl(T i, int shift) noexcept {
constexpr auto bits = sizeof(i) * 8;
return (i << static_cast<T>(shift)) | (i >> (bits - static_cast<T>(shift)));
}
template<typename T, typename B = int>
[[nodiscard]]
constexpr T onMask(B bits = sizeof(T) << 3 /* *8 */) noexcept {
T out = T(0);
for (B i = 0; i < bits; i++) {
out |= static_cast<T>(1) << i;
}
return out;
}
template<typename T>
constexpr auto MaxValue = onMask<T>(is_signed_v<T> ? sizeof(T) * 8 - 1 : sizeof(T) * 8);
}

138
deps/ox/src/ox/std/bounds.hpp vendored Normal file
View File

@@ -0,0 +1,138 @@
/*
* Copyright 2015 - 2023 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <ox/std/error.hpp>
#include <ox/std/new.hpp>
#include "point.hpp"
namespace ox {
class Bounds {
public:
static constexpr auto TypeName = "net.drinkingtea.ox.Bounds";
static constexpr auto TypeVersion = 1;
int x = 0;
int y = 0;
int width = 0;
int height = 0;
constexpr Bounds() noexcept = default;
constexpr Bounds(int x, int y, int w, int h) noexcept;
constexpr Bounds(const Point &pt1, const Point &pt2) noexcept;
[[nodiscard]]
constexpr bool intersects(const Bounds &other) const noexcept;
[[nodiscard]]
constexpr bool contains(int x, int y) const noexcept;
[[nodiscard]]
constexpr bool contains(const Point &pt) const noexcept;
[[nodiscard]]
constexpr int x2() const noexcept;
[[nodiscard]]
constexpr int y2() const noexcept;
[[nodiscard]]
constexpr Point pt1() const noexcept;
[[nodiscard]]
constexpr Point pt2() const noexcept;
constexpr void setPt2(const Point &pt) noexcept;
private:
constexpr void set(const Point &pt1, const Point &pt2) noexcept;
};
constexpr Bounds::Bounds(int x, int y, int w, int h) noexcept {
this->x = x;
this->y = y;
this->width = w;
this->height = h;
}
constexpr Bounds::Bounds(const Point &pt1, const Point &pt2) noexcept {
set(pt1, pt2);
}
constexpr bool Bounds::intersects(const Bounds &o) const noexcept {
return o.x2() >= x && x2() >= o.x && o.y2() >= y && y2() >= o.y;
}
constexpr bool Bounds::contains(int x, int y) const noexcept {
return x >= this->x && y >= this->y && x <= x2() && y <= y2();
}
constexpr bool Bounds::contains(const Point &pt) const noexcept {
return contains(pt.x, pt.y);
}
constexpr int Bounds::x2() const noexcept {
return x + width;
}
constexpr int Bounds::y2() const noexcept {
return y + height;
}
constexpr Point Bounds::pt1() const noexcept {
return {x, y};
}
constexpr Point Bounds::pt2() const noexcept {
return {x2(), y2()};
}
constexpr void Bounds::setPt2(const Point &pt) noexcept {
set(pt1(), pt);
}
constexpr void Bounds::set(const Point &pt1, const Point &pt2) noexcept {
int x1 = 0, x2 = 0, y1 = 0, y2 = 0;
if (pt1.x <= pt2.x) {
x1 = pt1.x;
x2 = pt2.x;
} else {
x1 = pt2.x;
x2 = pt1.x;
}
if (pt1.y <= pt2.y) {
y1 = pt1.y;
y2 = pt2.y;
} else {
y1 = pt2.y;
y2 = pt1.y;
}
this->x = x1;
this->y = y1;
this->width = x2 - x1;
this->height = y2 - y1;
}
template<typename T>
constexpr Error model(T *io, ox::CommonPtrWith<Bounds> auto *obj) noexcept {
oxReturnError(io->template setTypeInfo<Bounds>());
oxReturnError(io->field("x", &obj->x));
oxReturnError(io->field("y", &obj->y));
oxReturnError(io->field("width", &obj->width));
oxReturnError(io->field("height", &obj->height));
return {};
}
}

281
deps/ox/src/ox/std/bstring.hpp vendored Normal file
View File

@@ -0,0 +1,281 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "memops.hpp"
#include "stringview.hpp"
#include "strops.hpp"
#include "typetraits.hpp"
namespace ox {
// Bounded String
template<std::size_t buffLen>
class BString {
private:
char m_buff[buffLen + 1];
public:
constexpr BString() noexcept;
constexpr BString(StringView str) noexcept;
constexpr BString(const char *str) noexcept;
constexpr BString &operator=(CRStringView str) noexcept;
constexpr BString &operator=(const char *str) noexcept;
constexpr BString &operator=(char *str) noexcept;
constexpr BString &operator=(Integer_c auto i) noexcept;
constexpr BString &operator+=(const char *str) noexcept;
constexpr BString &operator+=(char *str) noexcept;
constexpr BString &operator+=(Integer_c auto i) noexcept;
constexpr BString &operator+=(StringView s) noexcept;
constexpr BString operator+(const char *str) const noexcept;
constexpr BString operator+(char *str) const noexcept;
constexpr BString operator+(Integer_c auto i) const noexcept;
constexpr bool operator==(const char *other) const noexcept;
constexpr bool operator==(const OxString_c auto &other) const noexcept;
constexpr bool operator!=(const char *other) const noexcept;
constexpr bool operator!=(const OxString_c auto &other) noexcept;
constexpr char operator[](std::size_t i) const noexcept;
constexpr char &operator[](std::size_t i) noexcept;
constexpr Error append(const char *str, std::size_t strLen) noexcept;
[[nodiscard]]
constexpr const char *data() const noexcept;
[[nodiscard]]
constexpr char *data() noexcept;
[[nodiscard]]
constexpr const char *c_str() const noexcept;
/**
* Returns the number of characters in this string.
*/
[[nodiscard]]
constexpr std::size_t len() const noexcept;
/**
* Returns the number of bytes used for this string.
*/
[[nodiscard]]
constexpr std::size_t bytes() const noexcept;
/**
* Returns the capacity of bytes for this string.
*/
[[nodiscard]]
constexpr std::size_t cap() const noexcept;
};
template<std::size_t size>
constexpr BString<size>::BString() noexcept: m_buff{{0}} {
}
template<std::size_t size>
constexpr BString<size>::BString(StringView str) noexcept: m_buff{{0}} {
operator=(str);
}
template<std::size_t size>
constexpr BString<size>::BString(const char *str) noexcept: m_buff{{0}} {
operator=(str);
}
template<std::size_t size>
constexpr BString<size> &BString<size>::operator=(Integer_c auto i) noexcept {
char str[65] = {};
ox_itoa(i, str);
return this->operator=(str);
}
template<std::size_t size>
constexpr BString<size> &BString<size>::operator=(ox::CRStringView str) noexcept {
std::size_t strLen = str.bytes() + 1;
if (cap() < strLen) {
strLen = cap();
}
ox_memcpy(m_buff, str.data(), strLen);
// make sure last element is a null terminator
m_buff[strLen] = 0;
return *this;
}
template<std::size_t size>
constexpr BString<size> &BString<size>::operator=(const char *str) noexcept {
std::size_t strLen = ox_strlen(str) + 1;
if (cap() < strLen) {
strLen = cap();
}
ox_memcpy(m_buff, str, strLen);
// make sure last element is a null terminator
m_buff[cap()] = 0;
return *this;
}
template<std::size_t size>
constexpr BString<size> &BString<size>::operator=(char *str) noexcept {
return *this = static_cast<const char*>(str);
}
template<std::size_t size>
constexpr BString<size> &BString<size>::operator+=(const char *str) noexcept {
std::size_t strLen = ox_strlen(str) + 1;
oxIgnoreError(append(str, strLen));
return *this;
}
template<std::size_t size>
constexpr BString<size> &BString<size>::operator+=(char *str) noexcept {
return *this += static_cast<const char*>(str);
}
template<std::size_t size>
constexpr BString<size> &BString<size>::operator+=(Integer_c auto i) noexcept {
char str[65] = {};
ox_itoa(i, str);
return this->operator+=(str);
}
template<std::size_t size>
constexpr BString<size> &BString<size>::operator+=(StringView s) noexcept {
std::size_t strLen = s.bytes();
oxIgnoreError(append(s.data(), strLen));
return *this;
}
template<std::size_t size>
constexpr BString<size> BString<size>::operator+(const char *str) const noexcept {
auto out = *this;
std::size_t strLen = ox_strlen(str) + 1;
oxIgnoreError(out.append(str, strLen));
return out;
}
template<std::size_t size>
constexpr BString<size> BString<size>::operator+(char *str) const noexcept {
return *this + static_cast<const char*>(str);
}
template<std::size_t size>
constexpr BString<size> BString<size>::operator+(Integer_c auto i) const noexcept {
char str[65] = {};
ox_itoa(i, str);
return this->operator+(str);
}
template<std::size_t buffLen>
constexpr bool BString<buffLen>::operator==(const char *other) const noexcept {
return ox::StringView(*this) == other;
}
template<std::size_t buffLen>
constexpr bool BString<buffLen>::operator==(const OxString_c auto &other) const noexcept {
return ox::StringView(*this) == ox::StringView(other);
}
template<std::size_t buffLen>
constexpr bool BString<buffLen>::operator!=(const char *other) const noexcept {
return !operator==(other);
}
template<std::size_t buffLen>
constexpr bool BString<buffLen>::operator!=(const OxString_c auto &other) noexcept {
return !operator==(other);
}
template<std::size_t buffLen>
constexpr char BString<buffLen>::operator[](std::size_t i) const noexcept {
return m_buff[i];
}
template<std::size_t buffLen>
constexpr char &BString<buffLen>::operator[](std::size_t i) noexcept {
return m_buff[i];
}
template<std::size_t buffLen>
constexpr Error BString<buffLen>::append(const char *str, std::size_t strLen) noexcept {
Error err;
auto currentLen = len();
if (cap() < currentLen + strLen + 1) {
strLen = cap() - currentLen;
err = OxError(1, "Insufficient space for full string");
}
ox_strncpy(m_buff + currentLen, str, strLen);
// make sure last element is a null terminator
m_buff[currentLen + strLen] = 0;
return err;
}
template<std::size_t buffLen>
constexpr const char *BString<buffLen>::data() const noexcept {
return static_cast<const char*>(m_buff);
}
template<std::size_t buffLen>
constexpr char *BString<buffLen>::data() noexcept {
return static_cast<char*>(m_buff);
}
template<std::size_t buffLen>
constexpr const char *BString<buffLen>::c_str() const noexcept {
return static_cast<const char*>(m_buff);
}
template<std::size_t buffLen>
constexpr std::size_t BString<buffLen>::len() const noexcept {
std::size_t length = 0;
for (std::size_t i = 0; i < buffLen; i++) {
uint8_t b = static_cast<uint8_t>(m_buff[i]);
if (b) {
const auto asciiChar = (b & 128) == 0;
const auto utf8Char = (b & (256 << 6)) == (256 << 6);
if (asciiChar || utf8Char) {
length++;
}
} else {
break;
}
}
return length;
}
template<std::size_t buffLen>
constexpr std::size_t BString<buffLen>::bytes() const noexcept {
std::size_t i = 0;
for (i = 0; i < buffLen && m_buff[i]; i++);
return i + 1; // add one for null terminator
}
template<std::size_t buffLen>
constexpr std::size_t BString<buffLen>::cap() const noexcept {
return buffLen;
}
}

20
deps/ox/src/ox/std/buffer.cpp vendored Normal file
View File

@@ -0,0 +1,20 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#include "error.hpp"
#include "buffer.hpp"
namespace ox {
template class Vector<char>;
template class ReaderT<BufferReader>;
template class WriterT<BufferWriter>;
template class WriterT<CharBuffWriter>;
}

240
deps/ox/src/ox/std/buffer.hpp vendored Normal file
View File

@@ -0,0 +1,240 @@
/*
* Copyright 2015 - 2023 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "error.hpp"
#include "reader.hpp"
#include "vector.hpp"
#include "writer.hpp"
namespace ox {
extern template class Vector<char>;
using Buffer = Vector<char>;
class BufferWriter {
private:
std::size_t m_it = 0;
ox::Buffer &m_buff;
public:
explicit constexpr BufferWriter(Buffer *buff) noexcept: m_it(buff->size()), m_buff(*buff) {
}
explicit constexpr BufferWriter(Buffer *buff, std::size_t it) noexcept: m_it(it), m_buff(*buff) {
}
constexpr ox::Error seekp(std::size_t p) noexcept {
m_it = p;
return {};
}
constexpr ox::Error seekp(ox::Signed<std::size_t> off, ox::ios_base::seekdir dir) noexcept {
ox::Signed<std::size_t> base = 0;
switch (dir) {
case ox::ios_base::beg:
base = 0;
break;
case ox::ios_base::end:
base = static_cast<ox::Signed<std::size_t>>(m_buff.size());
break;
case ox::ios_base::cur:
base = static_cast<ox::Signed<std::size_t>>(m_it);
break;
default:
return OxError(1, "Invalid seekdir");
}
m_it = static_cast<std::size_t>(base + off);
return {};
}
[[nodiscard]]
constexpr auto tellp() const noexcept {
return m_it;
}
constexpr ox::Error put(char val) noexcept {
if (m_it >= m_buff.size()) {
m_buff.resize(m_buff.size() + 1);
}
m_buff[m_it] = val;
++m_it;
return {};
}
constexpr ox::Error write(const char *inBuff, std::size_t cnt) noexcept {
const auto end = m_it + cnt;
if (end >= m_buff.size()) {
m_buff.resize(end);
}
if (inBuff) {
const auto buff = m_buff.data() + m_it;
for (auto i = 0u; i < cnt; ++i) {
buff[i] = inBuff[i];
}
}
m_it += cnt;
return {};
}
[[nodiscard]]
constexpr const auto &buff() const noexcept {
return m_buff;
}
};
class CharBuffWriter {
private:
std::size_t m_it = 0;
std::size_t m_cap = 0;
std::size_t m_size = 0;
char *m_buff = nullptr;
public:
template<std::size_t sz>
explicit constexpr CharBuffWriter(ox::Array<char, sz> &buff) noexcept:
m_cap(buff.size()),
m_buff(buff.data()) {
}
explicit constexpr CharBuffWriter(char *buff, std::size_t size) noexcept: m_cap(size), m_buff(buff) {
}
constexpr ox::Error seekp(std::size_t p) noexcept {
m_it = p;
return {};
}
constexpr ox::Error seekp(ox::Signed<std::size_t> off, ox::ios_base::seekdir dir) noexcept {
ox::Signed<std::size_t> base = 0;
switch (dir) {
case ox::ios_base::beg:
base = 0;
break;
case ox::ios_base::end:
base = static_cast<ox::Signed<std::size_t>>(m_size);
break;
case ox::ios_base::cur:
base = static_cast<ox::Signed<std::size_t>>(m_it);
break;
default:
return OxError(1, "Invalid seekdir");
}
m_it = static_cast<std::size_t>(base + off);
return {};
}
[[nodiscard]]
constexpr auto tellp() const noexcept {
return m_it;
}
constexpr ox::Error put(char val) noexcept {
if (m_it >= m_cap) [[unlikely]] {
return OxError(1, "Buffer overrun");
}
m_buff[m_it] = val;
++m_it;
m_size = ox::max(m_it, m_size);
return {};
}
constexpr ox::Error write(const char *buff, std::size_t cnt) noexcept {
const auto end = m_it + cnt;
if (end > m_cap) [[unlikely]] {
return OxError(1, "Buffer overrun");
}
if (buff) {
for (auto i = 0u; i < cnt; ++i) {
m_buff[m_it + i] = buff[i];
}
}
m_it += cnt;
m_size = ox::max(m_it, m_size);
return {};
}
[[nodiscard]]
constexpr auto data() const noexcept {
return m_buff;
}
};
class BufferReader {
private:
std::size_t m_it = 0;
std::size_t m_size = 0;
char const* m_buff = nullptr;
public:
constexpr explicit BufferReader(char const*buff, std::size_t sz) noexcept:
m_size(sz), m_buff(buff) {}
constexpr explicit BufferReader(ox::Buffer const&buffer) noexcept:
m_size(buffer.size()), m_buff(buffer.data()) {}
constexpr ox::Result<char> peek() const noexcept {
if (m_it >= m_size) [[unlikely]] {
return OxError(1, "Peek failed: buffer overrun");
}
return m_buff[m_it];
}
constexpr ox::Result<std::size_t> read(void *v, std::size_t sz) noexcept {
sz = ox::min(sz, m_size - m_it);
if (m_it + sz > m_size) [[unlikely]] {
return OxError(1, "Read failed: Buffer overrun");
}
ox_memcpy(v, &m_buff[m_it], sz);
m_it += sz;
return sz;
}
constexpr ox::Error seekg(std::size_t p) noexcept {
if (p > m_size) [[unlikely]] {
return OxError(1, "Seek failed: Buffer overrun");
}
m_it = p;
return {};
}
constexpr ox::Error seekg(int64_t off, ios_base::seekdir dir) noexcept {
ox::Signed<std::size_t> base = 0;
switch (dir) {
case ox::ios_base::beg:
base = 0;
break;
case ox::ios_base::end:
base = static_cast<ox::Signed<std::size_t>>(m_size);
break;
case ox::ios_base::cur:
base = static_cast<ox::Signed<std::size_t>>(m_it);
break;
default:
return OxError(1, "Invalid seekdir");
}
auto const newIt = static_cast<std::size_t>(base + off);
if (newIt > m_size) [[unlikely]] {
return OxError(1, "Seek failed: Buffer overrun");
}
m_it = newIt;
return {};
}
constexpr ox::Result<std::size_t> tellg() const noexcept {
return m_it;
}
};
extern template class ReaderT<BufferReader>;
extern template class WriterT<BufferWriter>;
extern template class WriterT<CharBuffWriter>;
}

46
deps/ox/src/ox/std/buildinfo.cpp vendored Normal file
View File

@@ -0,0 +1,46 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
namespace ox::buildinfo {
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-const-variable"
#endif
#if defined(OX_USE_STDLIB)
const bool UseStdLib = true;
#else
const bool UseStdLib = false;
#endif
#if defined(DEBUG)
const bool Debug = true;
#else
const bool Debug = false;
#endif
#if defined(NDEBUG)
const bool NDebug = true;
#else
const bool NDebug = false;
#endif
#if defined(__BIG_ENDIAN__)
const bool BigEndian = true;
const bool LittleEndian = false;
#else
const bool BigEndian = false;
const bool LittleEndian = true;
#endif
#ifdef __clang__
#pragma clang diagnostic pop
#endif
}

17
deps/ox/src/ox/std/buildinfo.hpp vendored Normal file
View File

@@ -0,0 +1,17 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
namespace ox::buildinfo {
extern const bool UseStdLib;
extern const bool Debug;
extern const bool NDebug;
extern const bool BigEndian;
extern const bool LittleEndian;
}

58
deps/ox/src/ox/std/byteswap.cpp vendored Normal file
View File

@@ -0,0 +1,58 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#include "byteswap.hpp"
namespace ox {
template<typename T>
static constexpr bool testLittleEndian(T i) noexcept {
return LittleEndian<T>(i) == i;
}
template<typename T>
static constexpr bool testBigEndian(T i) noexcept {
return BigEndian<T>(i) == i;
}
static_assert(testLittleEndian<uint16_t>(0x00ff), "Test LittleEndian 0x00ff");
static_assert(testLittleEndian<uint16_t>(0xff00), "Test LittleEndian 0xff00");
static_assert(testLittleEndian<uint32_t>(0x000000ff), "Test LittleEndian 0x000000ff");
static_assert(testLittleEndian<uint32_t>(0x0000ff00), "Test LittleEndian 0x0000ff00");
static_assert(testLittleEndian<uint32_t>(0x00ff0000), "Test LittleEndian 0x00ff0000");
static_assert(testLittleEndian<uint32_t>(0xff000000), "Test LittleEndian 0xff000000");
static_assert(testLittleEndian<uint64_t>(0x00000000000000ff), "Test LittleEndian 0x00000000000000ff");
static_assert(testLittleEndian<uint64_t>(0x000000000000ff00), "Test LittleEndian 0x000000000000ff00");
static_assert(testLittleEndian<uint64_t>(0x0000000000ff0000), "Test LittleEndian 0x0000000000ff0000");
static_assert(testLittleEndian<uint64_t>(0x00000000ff000000), "Test LittleEndian 0x00000000ff000000");
static_assert(testLittleEndian<uint64_t>(0x000000ff00000000), "Test LittleEndian 0x000000ff00000000");
static_assert(testLittleEndian<uint64_t>(0x0000ff0000000000), "Test LittleEndian 0x0000ff0000000000");
static_assert(testLittleEndian<uint64_t>(0x00ff000000000000), "Test LittleEndian 0x00ff000000000000");
static_assert(testLittleEndian<uint64_t>(0xff00000000000000), "Test LittleEndian 0xff00000000000000");
static_assert(testBigEndian<uint16_t>(0x00ff), "Test BigEndian 0x00ff");
static_assert(testBigEndian<uint16_t>(0xff00), "Test BigEndian 0xff00");
static_assert(testBigEndian<uint32_t>(0x000000ff), "Test BigEndian 0x000000ff");
static_assert(testBigEndian<uint32_t>(0x0000ff00), "Test BigEndian 0x0000ff00");
static_assert(testBigEndian<uint32_t>(0x00ff0000), "Test BigEndian 0x00ff0000");
static_assert(testBigEndian<uint32_t>(0xff000000), "Test BigEndian 0xff000000");
static_assert(testBigEndian<uint64_t>(0x00000000000000ff), "Test BigEndian 0x00000000000000ff");
static_assert(testBigEndian<uint64_t>(0x000000000000ff00), "Test BigEndian 0x000000000000ff00");
static_assert(testBigEndian<uint64_t>(0x0000000000ff0000), "Test BigEndian 0x0000000000ff0000");
static_assert(testBigEndian<uint64_t>(0x00000000ff000000), "Test BigEndian 0x00000000ff000000");
static_assert(testBigEndian<uint64_t>(0x000000ff00000000), "Test BigEndian 0x000000ff00000000");
static_assert(testBigEndian<uint64_t>(0x0000ff0000000000), "Test BigEndian 0x0000ff0000000000");
static_assert(testBigEndian<uint64_t>(0x00ff000000000000), "Test BigEndian 0x00ff000000000000");
static_assert(testBigEndian<uint64_t>(0xff00000000000000), "Test BigEndian 0xff00000000000000");
}

211
deps/ox/src/ox/std/byteswap.hpp vendored Normal file
View File

@@ -0,0 +1,211 @@
/*
* Copyright 2015 - 2023 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "defines.hpp"
#include "stddef.hpp"
#include "types.hpp"
#include "typetraits.hpp"
namespace ox {
template<typename T>
[[nodiscard]]
constexpr T byteSwap(typename enable_if<sizeof(T) == 1, T>::type i) noexcept {
return i;
}
template<typename T>
[[nodiscard]]
constexpr T byteSwap(typename enable_if<sizeof(T) == 2, T>::type i) noexcept {
return static_cast<T>(i << 8) | static_cast<T>(i >> 8);
}
template<typename T>
[[nodiscard]]
constexpr T byteSwap(typename enable_if<sizeof(T) == 4, T>::type i) noexcept {
return ((i >> 24) & 0x000000ff) |
((i >> 8) & 0x0000ff00) |
((i << 8) & 0x00ff0000) |
((i << 24) & 0xff000000);
}
template<typename T>
[[nodiscard]]
constexpr T byteSwap(typename enable_if<sizeof(T) == 8, T>::type i) noexcept {
return ((i >> 56) & 0x00000000000000ff) |
((i >> 40) & 0x000000000000ff00) |
((i >> 24) & 0x0000000000ff0000) |
((i >> 8) & 0x00000000ff000000) |
((i << 8) & 0x000000ff00000000) |
((i << 24) & 0x0000ff0000000000) |
((i << 40) & 0x00ff000000000000) |
((i << 56) & 0xff00000000000000);
}
/**
* Takes an int and byte swaps if the platform is the given condition is true.
*/
template<typename T, bool byteSwap>
[[nodiscard]]
constexpr T conditionalByteSwap(T i) noexcept {
if constexpr(byteSwap) {
return ox::byteSwap<T>(i);
} else {
return i;
}
}
template<typename T>
[[nodiscard]]
constexpr T fromLittleEndian(T i) noexcept {
return conditionalByteSwap<T, defines::BigEndian>(i);
}
template<typename T>
[[nodiscard]]
constexpr T fromBigEndian(T i) noexcept {
return conditionalByteSwap<T, defines::LittleEndian>(i);
}
template<typename T>
[[nodiscard]]
constexpr T toLittleEndian(T i) noexcept {
return conditionalByteSwap<T, defines::BigEndian>(i);
}
template<typename T>
[[nodiscard]]
constexpr T toBigEndian(T i) noexcept {
return conditionalByteSwap<T, defines::LittleEndian>(i);
}
template<typename T, bool byteSwap>
class OX_PACKED ByteSwapInteger {
private:
T m_value;
public:
constexpr ByteSwapInteger() noexcept = default;
constexpr ByteSwapInteger(const ByteSwapInteger &other) noexcept {
m_value = other.m_value;
}
constexpr ByteSwapInteger(T value) noexcept: m_value(conditionalByteSwap<T, byteSwap>(value)) {
}
constexpr ByteSwapInteger &operator=(const ByteSwapInteger &other) noexcept {
m_value = other.m_value;
return *this;
}
constexpr ByteSwapInteger &operator=(T value) noexcept {
m_value = conditionalByteSwap<T, byteSwap>(value);
return *this;
}
constexpr operator T() const noexcept {
return conditionalByteSwap<T, byteSwap>(m_value);
}
constexpr ByteSwapInteger operator+=(T other) noexcept {
const auto newVal = static_cast<T>(*this + other);
m_value = conditionalByteSwap<T, byteSwap>(newVal);
return *this;
}
constexpr ByteSwapInteger operator-=(T other) noexcept {
const auto newVal = static_cast<T>(*this - other);
m_value = conditionalByteSwap<T, byteSwap>(newVal);
return *this;
}
constexpr ByteSwapInteger operator*=(T other) noexcept {
const auto newVal = static_cast<T>(*this * other);
m_value = conditionalByteSwap<T, byteSwap>(newVal);
return *this;
}
constexpr ByteSwapInteger operator/=(T other) noexcept {
const auto newVal = static_cast<T>(*this / other);
m_value = conditionalByteSwap<T, byteSwap>(newVal);
return *this;
}
// Prefix increment
constexpr ByteSwapInteger operator++() noexcept {
return operator+=(1);
}
// Prefix decrement
constexpr ByteSwapInteger operator--() noexcept {
return operator-=(1);
}
template<typename I>
constexpr T operator&=(I other) noexcept {
auto newVal = *this & other;
m_value = conditionalByteSwap<T, byteSwap>(newVal);
return newVal;
}
template<typename I>
constexpr T operator|=(I other) noexcept {
auto newVal = *this | other;
m_value = conditionalByteSwap<T, byteSwap>(newVal);
return newVal;
}
template<typename I>
constexpr T operator^=(I other) noexcept {
auto newVal = *this ^ other;
m_value = conditionalByteSwap<T, byteSwap>(newVal);
return newVal;
}
template<typename I>
constexpr T operator>>=(I other) noexcept {
auto newVal = *this >> other;
m_value = conditionalByteSwap<T, byteSwap>(newVal);
return newVal;
}
template<typename I>
constexpr T operator<<=(I other) noexcept {
auto newVal = *this << other;
m_value = conditionalByteSwap<T, byteSwap>(newVal);
return newVal;
}
[[nodiscard]]
constexpr auto get() const noexcept -> T {
return static_cast<T>(*this);
}
/**
* Returns the integer as it is stored. If it is stored as little endian,
* a little endian integer is returned regardless of the endianness of
* the system.
*/
[[nodiscard]]
constexpr auto raw() const noexcept -> T {
return m_value;
}
};
template<typename T>
using LittleEndian = ByteSwapInteger<T, defines::BigEndian>;
template<typename T>
using BigEndian = ByteSwapInteger<T, defines::LittleEndian>;
}

23
deps/ox/src/ox/std/concepts.cpp vendored Normal file
View File

@@ -0,0 +1,23 @@
/*
* 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/.
*/
#include "concepts.hpp"
namespace ox::detail::test {
class TestType;
[[nodiscard]] constexpr bool ok(auto*) noexcept { return false; }
[[nodiscard]] constexpr bool ok(CommonPtrWith<TestType> auto*) noexcept { return true; }
static_assert(ok(static_cast<TestType*>(nullptr)));
static_assert(ok(static_cast<const TestType*>(nullptr)));
static_assert(!ok(static_cast<int*>(nullptr)));
static_assert(!ok(static_cast<const int*>(nullptr)));
}

32
deps/ox/src/ox/std/concepts.hpp vendored Normal file
View File

@@ -0,0 +1,32 @@
/*
* 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 "typetraits.hpp"
namespace ox {
template<typename T, typename U>
concept CommonPtrWith = ox::is_same_v<typename ox::remove_pointer<const T*>::type,
typename ox::remove_pointer<const U*>::type>;
template<typename T, typename U>
concept CommonRefWith = ox::is_same_v<typename ox::remove_reference_t<const T&>,
typename ox::remove_reference_t<const U&>>;
template<typename T, typename U>
concept same_as = ox::is_same_v<T, T>;
template<typename T>
concept OxString_c = isOxString_v<T>;
template<typename T>
concept Integral_c = ox::is_integral_v<T>;
}

53
deps/ox/src/ox/std/cstringview.hpp vendored Normal file
View File

@@ -0,0 +1,53 @@
/*
* Copyright 2015 - 2023 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"
#include "bstring.hpp"
#include "string.hpp"
#include "stringliteral.hpp"
namespace ox {
class CStringView: public detail::BaseStringView {
public:
constexpr CStringView() noexcept = default;
constexpr CStringView(CStringView const&sv) noexcept = default;
constexpr CStringView(StringLiteral const&str) noexcept: BaseStringView(str.data(), str.len()) {}
template<std::size_t SmallStrSz>
constexpr CStringView(BasicString<SmallStrSz> const&str) noexcept: BaseStringView(str.data(), str.len()) {}
template<std::size_t SmallStrSz>
constexpr CStringView(BString<SmallStrSz> const&str) noexcept: BaseStringView(str.data(), str.len()) {}
constexpr CStringView(std::nullptr_t) noexcept {}
constexpr CStringView(const char *str) noexcept: BaseStringView(str) {}
constexpr CStringView(const char *str, std::size_t len) noexcept: BaseStringView(str, len) {}
constexpr auto &operator=(CStringView const&other) noexcept {
if (&other != this) {
set(other.data(), other.len());
}
return *this;
}
[[nodiscard]]
constexpr const char *c_str() const noexcept {
return data();
}
};
}

145
deps/ox/src/ox/std/cstrops.hpp vendored Normal file
View File

@@ -0,0 +1,145 @@
/*
* Copyright 2015 - 2023 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 "types.hpp"
#include "typetraits.hpp"
template<typename T1, typename T2>
constexpr T1 ox_strncpy(T1 dest, T2 src, std::size_t maxLen) noexcept {
using T1Type = typename ox::remove_reference<decltype(dest[0])>::type;
std::size_t i = 0;
while (i < maxLen && src[i]) {
dest[i] = static_cast<T1Type>(src[i]);
++i;
}
// set null terminator
dest[i] = 0;
return dest;
}
[[nodiscard]]
constexpr auto ox_strnlen(const char *str1, std::size_t maxLen) noexcept {
std::size_t len = 0;
for (; len < maxLen && str1[len]; len++);
return len;
}
template<typename T>
[[nodiscard]]
constexpr auto ox_strlen(T const&str1) noexcept {
std::size_t len = 0;
for (; str1[len]; len++);
return len;
}
template<typename T1, typename T2>
[[nodiscard]]
constexpr int ox_strcmp(const T1 &str1, const T2 &str2) noexcept {
auto retval = 0;
auto i = 0u;
while (str1[i] || str2[i]) {
if (str1[i] < str2[i]) {
retval = -1;
break;
} else if (str1[i] > str2[i]) {
retval = 1;
break;
}
i++;
}
return retval;
}
template<typename T1, typename T2>
[[nodiscard]]
constexpr int ox_strncmp(T1 const&str1, T2 const&str2, const std::size_t maxLen) noexcept {
auto retval = 0;
std::size_t i = 0;
while (i < maxLen && (str1[i] || str2[i])) {
if (str1[i] < str2[i]) {
retval = -1;
break;
} else if (str1[i] > str2[i]) {
retval = 1;
break;
}
i++;
}
return retval;
}
[[nodiscard]]
constexpr const char *ox_strchr(const char *str, int character, std::size_t maxLen = 0xFFFFFFFF) noexcept {
for (std::size_t i = 0; i <= maxLen; i++) {
if (str[i] == character) {
return &str[i];
} else if (str[i] == 0) {
return nullptr;
}
}
return nullptr;
}
[[nodiscard]]
constexpr char *ox_strchr(char *str, int character, std::size_t maxLen = 0xFFFFFFFF) noexcept {
for (std::size_t i = 0; i < maxLen; i++) {
if (str[i] == character) {
return &str[i];
} else if (str[i] == 0) {
return nullptr;
}
}
return nullptr;
}
[[nodiscard]]
constexpr int ox_lastIndexOf(const auto &str, int character, std::size_t maxLen = 0xFFFFFFFF) noexcept {
int retval = -1;
for (std::size_t i = 0; i < maxLen && str[i]; i++) {
if (str[i] == character) {
retval = static_cast<int>(i);
}
}
return retval;
}
template<typename Integer, typename T>
constexpr T ox_itoa(Integer v, T str) noexcept {
if (v) {
ox::ResizedInt_t<Integer, 64> mod = 1000000000000000000;
ox::ResizedInt_t<Integer, 64> val = v;
constexpr auto base = 10;
auto it = 0;
if (val < 0) {
str[static_cast<std::size_t>(it)] = '-';
it++;
}
while (mod) {
auto digit = val / mod;
val %= mod;
mod /= base;
if (it || digit) {
ox::ResizedInt_t<Integer, 64> start = '0';
if (digit >= 10) {
start = 'a';
digit -= 10;
}
str[static_cast<std::size_t>(it)] = static_cast<typename ox::remove_reference<decltype(str[0])>::type>(start + digit);
it++;
}
}
str[static_cast<std::size_t>(it)] = 0;
} else {
// 0 is a special case
str[0] = '0';
str[1] = 0;
}
return str;
}

86
deps/ox/src/ox/std/def.hpp vendored Normal file
View File

@@ -0,0 +1,86 @@
/*
* Copyright 2015 - 2023 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
// Logging
#define oxLogError(...) ox::trace::logError(__FILE__, __LINE__, __VA_ARGS__)
#define oxTrace(...) ox::trace::TraceStream(__FILE__, __LINE__, __VA_ARGS__)
#define oxOut(...) ox::trace::OutStream(__FILE__, __LINE__, "stdout", __VA_ARGS__)
#define oxErr(...) ox::trace::OutStream(__FILE__, __LINE__, "stderr", __VA_ARGS__)
#define oxTracef(ch, fmt, ...) ox::trace::TraceStream(__FILE__, __LINE__, ch, ox::detail::fmtSegments<ox::detail::argCount(fmt)+1>(fmt), __VA_ARGS__)
#define oxOutf(fmt, ...) ox::trace::OutStream(__FILE__, __LINE__, "stdout", ox::detail::fmtSegments<ox::detail::argCount(fmt)+1>(fmt), __VA_ARGS__)
#define oxErrf(fmt, ...) ox::trace::OutStream(__FILE__, __LINE__, "stderr", ox::detail::fmtSegments<ox::detail::argCount(fmt)+1>(fmt), __VA_ARGS__)
#define oxInfo(...) oxTrace("info", __VA_ARGS__)
#define oxInfof(...) oxTracef("info", __VA_ARGS__)
#define oxError(...) oxTrace("error", __VA_ARGS__)
#define oxErrorf(...) oxTracef("error", __VA_ARGS__)
#ifndef OX_NODEBUG
#define oxDebug(...) ox::trace::OutStream(__FILE__, __LINE__, "debug", __VA_ARGS__)
#define oxDebugf(fmt, ...) ox::trace::OutStream(__FILE__, __LINE__, "debug", ox::detail::fmtSegments<ox::detail::argCount(fmt)+1>(fmt), __VA_ARGS__)
#else
#define oxDebug(...) static_assert(false, "Debug prints were checked in.");
#define oxDebugf(...) static_assert(false, "Debug prints were checked in.");
#endif
// Error handling
#define oxReturnError(x) { if (const auto _ox_error = ox::detail::toError(x)) [[unlikely]] return _ox_error; } (void) 0
#define oxThrowError(x) { if (const auto _ox_error = ox::detail::toError(x)) [[unlikely]] throw ox::Exception(_ox_error); } (void) 0
#define oxConcatImpl(a, b) a##b
#define oxConcat(a, b) oxConcatImpl(a, b)
// oxRequire Mutable
#define oxRequireM(out, x) auto [out, oxConcat(oxRequire_err_, __LINE__)] = x; oxReturnError(oxConcat(oxRequire_err_, __LINE__))
#define oxRequire(out, x) const oxRequireM(out, x)
// oxRequire Mutable Throw
#define oxRequireMT(out, x) auto [out, oxConcat(oxRequire_err_, __LINE__)] = x; oxThrowError(oxConcat(oxRequire_err_, __LINE__))
// oxRequire Throw
#define oxRequireT(out, x) const oxRequireMT(out, x)
// Asserts
#define oxPanic(errCode, msg) ox::panic(__FILE__, __LINE__, msg, errCode)
#ifndef NDEBUG
#define oxAssert(pass, msg) ox::assertFunc(__FILE__, __LINE__, pass, #pass, msg)
#else
namespace ox {
struct [[nodiscard]] Error;
}
constexpr void oxAssert(bool, const char*) noexcept {}
constexpr void oxAssert(const ox::Error&, const char*) noexcept {}
#endif
#define oxExpect(actual, expected) ox::expect(__FILE__, __LINE__, actual, expected)
// Alloca
#if defined(_MSC_VER)
#define ox_alloca(size) _alloca(size)
#elif OX_USE_STDLIB
#define ox_alloca(size) alloca(size)
#else
#define ox_alloca(size) __builtin_alloca(size)
#endif
/**
* @return an ox::MallocaPtr of the given type pointing to the requested size memory allocation
*/
#if defined(OX_USE_STDLIB)
#define ox_malloca(size, Type, ...) ox::MallocaPtr<Type>(size > ox::MallocaStackLimit, new (size > ox::MallocaStackLimit ? new uint8_t[size] : ox_alloca(size)) Type(__VA_ARGS__))
#else
#define ox_malloca(size, Type, ...) ox::MallocaPtr<Type>(false, new (ox_alloca(size)) Type(__VA_ARGS__))
#endif

37
deps/ox/src/ox/std/defer.hpp vendored Normal file
View File

@@ -0,0 +1,37 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "error.hpp"
namespace ox {
template<typename T>
class Defer {
private:
T m_deferredFunc;
public:
Defer(T deferredFunc) {
m_deferredFunc = deferredFunc;
}
Defer(const Defer&) = delete;
~Defer() {
m_deferredFunc();
}
Defer &operator=(const Defer&) = delete;
};
}
#define oxDefer ox::Defer oxConcat(oxDefer_, __LINE__) = [&]

85
deps/ox/src/ox/std/defines.hpp vendored Normal file
View File

@@ -0,0 +1,85 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
namespace ox {
enum class OS {
BareMetal,
NetBSD,
OpenBSD,
FreeBSD,
DragonFlyBSD,
Linux,
Darwin,
Windows
};
namespace defines {
#if defined(OX_NODEBUG)
constexpr bool NoDebug = true;
#else
constexpr bool NoDebug = false;
#endif
#if defined(OX_USE_STDLIB)
constexpr auto UseStdLib = true;
#else
constexpr auto UseStdLib = false;
#endif
#if defined(DEBUG)
constexpr auto Debug = true;
#else
constexpr auto Debug = false;
#endif
#if defined(NDEBUG)
constexpr auto NDebug = true;
#else
constexpr auto NDebug = false;
#endif
#if defined(__BIG_ENDIAN__)
constexpr auto BigEndian = true;
constexpr auto LittleEndian = false;
#else
constexpr auto BigEndian = false;
constexpr auto LittleEndian = true;
#endif
#if defined(__FreeBSD__)
constexpr OS OS = OS::FreeBSD;
#define OX_OS_FreeBSD
#elif defined(__NetBSD__)
constexpr OS OS = OS::NetBSD;
#define OX_OS_NetBSD
#elif defined(__OpenBSD__)
constexpr OS OS = OS::OpenBSD;
#define OX_OS_OpenBSD
#elif defined(__DragonFly__)
constexpr OS OS = OS::DragonFlyBSD;
#define OX_OS_DragonFlyBSD
#elif defined(__gnu_linux__)
constexpr OS OS = OS::Linux;
#define OX_OS_Linux
#elif defined(_WIN32)
constexpr OS OS = OS::Windows;
#define OX_OS_Windows
#elif defined(__APPLE__)
constexpr OS OS = OS::Darwin;
#define OX_OS_Darwin
#else
constexpr OS OS = OS::BareMetal;
#define OX_OS_BareMetal
#endif
}
}

286
deps/ox/src/ox/std/error.hpp vendored Normal file
View File

@@ -0,0 +1,286 @@
/*
* Copyright 2015 - 2023 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(<exception>)
#include <exception>
#else
namespace std {
class exception {
public:
virtual ~exception() = default;
[[nodiscard]]
virtual const char *what() const noexcept {
return "";
}
};
}
#endif
#include "def.hpp"
#include "typetraits.hpp"
#include "utility.hpp"
#define OxError(...) ox::Error(__FILE__, __LINE__, __VA_ARGS__)
#define OxException(...) ox::Exception(__FILE__, __LINE__, __VA_ARGS__)
namespace ox {
using ErrorCode = uint16_t;
struct [[nodiscard]] Error {
const char *msg = nullptr;
const char *file = nullptr;
uint16_t line = 0;
ErrorCode errCode = 0;
constexpr Error() noexcept = default;
explicit constexpr Error(ErrorCode ec) noexcept: errCode(ec) {
}
explicit constexpr Error(const char *file, uint32_t line, ErrorCode errCode, const char *msg = nullptr) noexcept {
this->file = file;
this->line = static_cast<uint16_t>(line);
this->msg = msg;
this->errCode = errCode;
}
constexpr Error(const Error &o) noexcept {
this->msg = o.msg;
this->file = o.file;
this->line = o.line;
this->errCode = o.errCode;
}
constexpr Error &operator=(const Error &o) noexcept {
this->msg = o.msg;
this->file = o.file;
this->line = o.line;
this->errCode = o.errCode;
return *this;
}
constexpr operator uint64_t() const noexcept {
return errCode;
}
};
[[nodiscard]]
constexpr auto errCode(const Error &err) noexcept {
return err.errCode;
}
template<typename T=const char*>
[[nodiscard]]
constexpr auto toStr(const Error &err) noexcept {
return err.msg ? T(err.msg) : "";
}
struct Exception: public std::exception {
const char *msg = nullptr;
const char *file = nullptr;
uint16_t line = 0;
ErrorCode errCode = 0;
explicit inline Exception(const char *file, uint32_t line, ErrorCode errCode, const char *msg = "") noexcept {
this->file = file;
this->line = static_cast<uint16_t>(line);
this->msg = msg;
this->errCode = errCode;
}
explicit inline Exception(const Error &err) {
if (err.msg) {
this->msg = err.msg;
} else {
this->msg = "";
}
this->file = err.file;
this->line = err.line;
this->errCode = err.errCode;
}
constexpr Error toError() const noexcept {
return Error(file, line, errCode, msg);
}
[[nodiscard]]
const char *what() const noexcept override {
return msg;
}
};
void panic(const char *file, int line, const char *panicMsg, const Error &err) noexcept;
template<typename T>
struct [[nodiscard]] Result {
using type = typename remove_reference<T>::type;
T value;
Error error;
constexpr Result() noexcept: value(), error(0) {
}
template<typename U>
constexpr Result(const Result<U> &other) noexcept: value(other.value), error(other.error) {
}
template<typename U>
constexpr Result(Result<U> &&other) noexcept: value(std::move(other.value)), error(std::move(other.error)) {
}
constexpr Result(const Error &error) noexcept: value(), error(error) {
}
constexpr Result(const type &value, const Error &error = OxError(0)) noexcept: value(value), error(error) {
}
constexpr Result(type &&value, const Error &error = OxError(0)) noexcept: value(std::move(value)), error(error) {
}
constexpr ~Result() noexcept = default;
explicit constexpr operator const type&() const noexcept {
return value;
}
explicit constexpr operator type&() noexcept {
return value;
}
[[nodiscard]]
constexpr bool ok() const noexcept {
return error == 0;
}
constexpr Error copyTo(type &val) const & noexcept {
if (!error) [[likely]] {
val = value;
}
return error;
}
constexpr Error copyTo(type &val) const && noexcept {
if (!error) [[likely]] {
val = value;
}
return error;
}
constexpr Error copyTo(type &val) & noexcept {
if (!error) [[likely]] {
val = value;
}
return error;
}
constexpr Error copyTo(type &val) && noexcept {
if (!error) [[likely]] {
val = std::move(value);
}
return error;
}
constexpr Error moveTo(type &val) noexcept {
if (!error) [[likely]] {
val = std::move(value);
}
return error;
}
[[nodiscard]]
constexpr T &unwrap() & noexcept {
if (error) {
oxPanic(error, "Failed unwrap");
}
return value;
}
[[nodiscard]]
constexpr T &&unwrap() && noexcept {
if (error) {
oxPanic(error, "Failed unwrap");
}
return std::move(value);
}
[[nodiscard]]
constexpr T const&unwrap() const & noexcept {
if (error) [[unlikely]] {
oxPanic(error, "Failed unwrap");
}
return value;
}
[[nodiscard]]
constexpr T &unwrapThrow() & {
if (error) {
throw ox::Exception(error);
}
return value;
}
[[nodiscard]]
constexpr T &&unwrapThrow() && {
if (error) {
throw ox::Exception(error);
}
return std::move(value);
}
[[nodiscard]]
constexpr T const&unwrapThrow() const & {
if (error) {
throw ox::Exception(error);
}
return value;
}
template<typename U = T>
constexpr ox::Result<U> to(auto const&f) & noexcept {
if (error) [[unlikely]] {
return error;
}
return f(value);
}
template<typename U = T>
constexpr ox::Result<U> to(auto const&f) && noexcept {
if (error) [[unlikely]] {
return error;
}
return f(std::move(value));
}
};
namespace detail {
constexpr Error toError(const Error &e) noexcept {
return e;
}
template<typename T>
constexpr Error toError(const Result<T> &r) noexcept {
return r.error;
}
}
}
constexpr void oxIgnoreError(const ox::Error&) noexcept {}
template<typename T>
constexpr void oxIgnoreError(const ox::Result<T>&) noexcept {}

74
deps/ox/src/ox/std/fmt.cpp vendored Normal file
View File

@@ -0,0 +1,74 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#include "fmt.hpp"
namespace ox::detail {
static_assert(argCount("sadf asdf") == 0);
static_assert(argCount("{}") == 1);
static_assert(argCount("{}{}") == 2);
static_assert(argCount("thing1: {}, thing2: {}") == 2);
static_assert(argCount("thing1: {}, thing2: {}{}") == 3);
static_assert([] {
constexpr auto fmt = "{}";
return fmtSegments<argCount(fmt) + 1>(fmt) == Fmt<2>{
{
{"", 0},
{"", 0},
}
};
}()
);
static_assert([] {
constexpr auto fmt = "thing: {}";
return fmtSegments<argCount(fmt) + 1>(fmt) == Fmt<2>{
{
{"thing: ", 7},
{"", 0},
}
};
}()
);
static_assert([] {
constexpr auto fmt = "thing: {}, thing2: {}";
return fmtSegments<argCount(fmt) + 1>(fmt) == Fmt<3>{
{
{"thing: ", 7},
{", thing2: ", 10},
{"", 0},
}
};
}()
);
static_assert([] {
constexpr auto fmt = "thing: {}, thing2: {}s";
return fmtSegments<argCount(fmt) + 1>(fmt) == Fmt<3>{
{
{"thing: ", 7},
{", thing2: ", 10},
{"s", 1},
}
};
}()
);
static_assert([] {
constexpr auto fmt = "loadTexture: section: {}, w: {}, h: {}";
return fmtSegments<argCount(fmt) + 1>(fmt) == Fmt<4>{
{
{"loadTexture: section: ", 22},
{", w: ", 5},
{", h: ", 5},
}
};
}()
);
}

218
deps/ox/src/ox/std/fmt.hpp vendored Normal file
View File

@@ -0,0 +1,218 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
#if __has_include(<string>)
#include <string>
#endif
#if __has_include(<QString>)
#include <QString>
#endif
#include "realstd.hpp"
#include "error.hpp"
#include "bstring.hpp"
#include "string.hpp"
#include "strops.hpp"
#include "types.hpp"
#include "typetraits.hpp"
namespace ox {
namespace detail {
template<bool force = false>
constexpr StringView toStringView(const StringView &s) noexcept {
return s;
}
template<bool force = false>
constexpr StringView toStringView(const char *s) noexcept {
return s;
}
template<bool force = false, std::size_t size>
constexpr StringView toStringView(const BString<size> &s) noexcept {
return s.c_str();
}
template<bool force = false, std::size_t size>
constexpr StringView toStringView(const BasicString<size> &s) noexcept {
return s.c_str();
}
#if __has_include(<string>)
template<bool force = false>
#ifdef OX_OS_Darwin
constexpr
#else
inline
#endif
StringView toStringView(const std::string &s) noexcept {
return s.c_str();
}
#endif
#if __has_include(<QString>)
template<bool force = false>
inline StringView toStringView(const QString &s) noexcept {
return s.toUtf8().data();
}
#endif
template<bool force = false>
constexpr StringView toStringView(const auto&) noexcept requires(force) {
return "<unstringable>";
}
class FmtArg {
private:
char dataStr[10] = {};
template<typename T>
static StringView sv(const T &v, char *dataStr) noexcept {
if constexpr(is_bool_v<T>) {
return v ? "true" : "false";
} else if constexpr(is_integer_v<T>) {
return ox_itoa(v, dataStr);
} else {
return toStringView(v);
}
}
public:
const StringView out = nullptr;
template<typename T>
constexpr FmtArg(const T &v) noexcept: out(sv(v, dataStr)) {
}
};
[[nodiscard]]
constexpr uint64_t argCount(StringView str) noexcept {
uint64_t cnt = 0;
const auto prev = [str](std::size_t i) -> char {
if (i > 0) {
return str[i - 1];
} else {
return '\0';
}
};
const auto next = [str](std::size_t i) -> char {
if (i < str.bytes() - 1) {
return str[i + 1];
} else {
return '\0';
}
};
for (std::size_t i = 0; i < str.bytes(); ++i) {
if (str[i] == '{' && prev(i) != '\\' && next(i) == '}') {
++cnt;
}
}
return cnt;
}
struct FmtSegment {
const char *str = nullptr;
unsigned length = 0;
constexpr bool operator==(const FmtSegment &o) const noexcept {
return length == o.length && ox_strncmp(str, o.str, length) == 0;
}
constexpr bool operator!=(const FmtSegment &o) const noexcept {
return length != o.length || ox_strncmp(str, o.str, length) != 0;
}
};
template<std::size_t sz>
struct Fmt {
static constexpr std::size_t size = sz;
ox::Array<FmtSegment, sz> segments;
constexpr bool operator==(const Fmt<sz> &o) const noexcept {
for (std::size_t i = 0; i < sz; ++i) {
if (segments[i] != o.segments[i]) {
return false;
}
}
return true;
}
};
template<std::size_t segementCnt>
[[nodiscard]]
constexpr Fmt<segementCnt> fmtSegments(StringView fmt) noexcept {
Fmt<segementCnt> out;
const auto prev = [fmt](std::size_t i) -> char {
if (i > 0) {
return fmt[i - 1];
} else {
return '\0';
}
};
const auto next = [fmt](std::size_t i) -> char {
if (i < fmt.bytes() - 1) {
return fmt[i + 1];
} else {
return '\0';
}
};
auto current = &out.segments[0];
current->str = fmt.data();
for (std::size_t i = 0; i < fmt.bytes(); ++i) {
if (fmt[i] == '{' && prev(i) != '\\' && next(i) == '}') {
++current;
current->str = fmt.data() + i + 2;
current->length = 0;
i += 1;
} else {
++current->length;
}
}
return out;
}
}
template<typename StringType = String, typename ...Args>
[[nodiscard]]
constexpr StringType sfmt(StringView fmt, Args&&... args) noexcept {
assert(ox::detail::argCount(fmt) == sizeof...(args));
StringType out;
const auto fmtSegments = ox::detail::fmtSegments<sizeof...(args)+1>(fmt);
const auto &firstSegment = fmtSegments.segments[0];
oxIgnoreError(out.append(firstSegment.str, firstSegment.length));
const detail::FmtArg elements[sizeof...(args)] = {args...};
for (size_t i = 0; i < fmtSegments.size - 1; ++i) {
out += elements[i].out;
const auto &s = fmtSegments.segments[i + 1];
oxIgnoreError(out.append(s.str, s.length));
}
return out;
}
template<typename T = String>
constexpr Result<T> join(auto d, const auto &list) {
if (!list.size()) {
return T("");
}
T out;
out += list[0];
for (auto i = 1ul; i < list.size(); ++i) {
out += d;
out += list[i];
}
return out;
}
}

38
deps/ox/src/ox/std/hardware.hpp vendored Normal file
View File

@@ -0,0 +1,38 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
#if defined(__x86_64__) || defined(_M_AMD64)
#define OX_ARCH_x86_64
#elif defined(__i386__) || defined(_M_IX86)
#define OX_ARCH_x86_32
#elif defined(__arm64__) || defined(__aarch64__)
#define OX_ARCH_ARM64
#elif defined(__arm__)
#define OX_ARCH_ARM
#endif
#if defined(OX_ARCH_ARM)
#if defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__)
#define OX_HW_DIV 1
#else
#define OX_HW_DIV 0
#endif
#elif defined(OX_ARCH_x86_32) || defined(OX_ARCH_x86_64) || defined(OX_ARCH_ARM64)
#define OX_HW_DIV 1
#else
#error "Undefined hardware"
#endif

269
deps/ox/src/ox/std/hashmap.hpp vendored Normal file
View File

@@ -0,0 +1,269 @@
/*
* Copyright 2015 - 2023 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 "algorithm.hpp"
#include "stringview.hpp"
#include "strops.hpp"
#include "vector.hpp"
namespace ox {
template<typename K, typename T>
class HashMap {
public:
using key_t = K;
using value_t = T;
private:
struct Pair {
K key = {};
T value{};
};
Vector<K> m_keys;
Vector<Pair*> m_pairs;
public:
explicit constexpr HashMap(std::size_t size = 100);
constexpr HashMap(HashMap const&other);
constexpr HashMap(HashMap &&other) noexcept;
constexpr ~HashMap();
constexpr bool operator==(HashMap const&other) const;
constexpr HashMap &operator=(HashMap const&other);
constexpr HashMap &operator=(HashMap &&other) noexcept;
constexpr T &operator[](MaybeSV_t<K> const&key);
constexpr Result<T*> at(MaybeSV_t<K> const&key) noexcept;
constexpr Result<const T*> at(MaybeSV_t<K> const&key) const noexcept;
constexpr void erase(MaybeSV_t<K> const&key);
[[nodiscard]]
constexpr bool contains(MaybeSV_t<K> const&key) const noexcept;
[[nodiscard]]
constexpr std::size_t size() const noexcept;
[[nodiscard]]
constexpr Vector<K> const&keys() const noexcept;
constexpr void clear();
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;
template<typename KK>
constexpr Pair *&access(Vector<Pair*> &pairs, KK const&key);
};
template<typename K, typename T>
constexpr HashMap<K, T>::HashMap(std::size_t size): m_pairs(size) {
}
template<typename K, typename T>
constexpr HashMap<K, T>::HashMap(HashMap<K, T> const&other) {
m_pairs = other.m_pairs;
}
template<typename K, typename T>
constexpr HashMap<K, T>::HashMap(HashMap<K, T> &&other) noexcept {
m_keys = std::move(other.m_keys);
m_pairs = std::move(other.m_pairs);
}
template<typename K, typename T>
constexpr HashMap<K, T>::~HashMap() {
clear();
}
template<typename K, typename T>
constexpr bool HashMap<K, T>::operator==(HashMap const&other) const {
if (m_keys != other.m_keys) {
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>
constexpr HashMap<K, T> &HashMap<K, T>::operator=(HashMap<K, T> const&other) {
if (this != &other) {
clear();
m_keys = other.m_keys;
m_pairs = other.m_pairs;
}
return *this;
}
template<typename K, typename T>
constexpr HashMap<K, T> &HashMap<K, T>::operator=(HashMap<K, T> &&other) noexcept {
if (this != &other) {
clear();
m_keys = std::move(other.m_keys);
m_pairs = std::move(other.m_pairs);
}
return *this;
}
template<typename K, typename T>
constexpr T &HashMap<K, T>::operator[](MaybeSV_t<K> const&k) {
auto &p = access(m_pairs, k);
if (p == nullptr) {
if (static_cast<double>(m_pairs.size()) * 0.7 <
static_cast<double>(m_keys.size())) {
expand();
}
p = new Pair;
p->key = k;
m_keys.emplace_back(k);
}
return p->value;
}
template<typename K, typename T>
constexpr Result<T*> HashMap<K, T>::at(MaybeSV_t<K> const&k) noexcept {
auto p = access(m_pairs, k);
if (!p) {
return {nullptr, OxError(1, "value not found for given key")};
}
return &p->value;
}
template<typename K, typename T>
constexpr Result<const T*> HashMap<K, T>::at(MaybeSV_t<K> const&k) const noexcept {
auto p = access(m_pairs, k);
if (!p) {
return {nullptr, OxError(1, "value not found for given key")};
}
return &p->value;
}
template<typename K, typename T>
constexpr void HashMap<K, T>::erase(MaybeSV_t<K> const&k) {
if (!contains(k)) {
return;
}
auto h = hash(k) % m_pairs.size();
while (true) {
const auto &p = m_pairs[h];
if (p == nullptr || p->key == k) {
oxIgnoreError(m_pairs.erase(h));
break;
} else {
h = hash(h) % m_pairs.size();
}
}
oxIgnoreError(m_keys.erase(ox::find(m_keys.begin(), m_keys.end(), k)));
}
template<typename K, typename T>
constexpr bool HashMap<K, T>::contains(MaybeSV_t<K> const&k) const noexcept {
return access(m_pairs, k) != nullptr;
}
template<typename K, typename T>
constexpr std::size_t HashMap<K, T>::size() const noexcept {
return m_keys.size();
}
template<typename K, typename T>
constexpr Vector<K> const&HashMap<K, T>::keys() const noexcept {
return m_keys;
}
template<typename K, typename T>
constexpr void HashMap<K, T>::clear() {
for (std::size_t i = 0; i < m_pairs.size(); i++) {
delete m_pairs[i];
}
m_pairs.clear();
m_pairs.resize(100);
}
template<typename K, typename T>
constexpr void HashMap<K, T>::expand() {
Vector<Pair*> r;
for (std::size_t i = 0; i < m_keys.size(); ++i) {
K k{m_keys[i]};
access(r, k) = std::move(access(m_pairs, k));
}
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());
while (true) {
const auto &p = pairs[h];
if (p == nullptr || p->key == k) {
return p;
} else {
h = (h + 1) % pairs.size();
}
}
}
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());
while (true) {
auto &p = pairs[h];
if (p == nullptr || p->key == k) {
return p;
} else {
h = (h + 1) % pairs.size();
}
}
}
}

144
deps/ox/src/ox/std/heapmgr.cpp vendored Normal file
View File

@@ -0,0 +1,144 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#include "assert.hpp"
#include "bit.hpp"
#include "heapmgr.hpp"
namespace ox::heapmgr {
static struct HeapSegment *volatile g_heapBegin = nullptr;
static struct HeapSegment *volatile g_heapEnd = nullptr;
static struct HeapSegment *volatile heapIdx = nullptr;
static constexpr std::size_t alignedSize(std::size_t sz) noexcept {
return sz + (sz & 7);
}
template<typename T>
static constexpr std::size_t alignedSize(T = {}) noexcept {
return alignedSize(sizeof(T));
}
void HeapSegment::init(std::size_t maxSize = std::bit_cast<std::size_t>(g_heapEnd)) noexcept {
this->size = maxSize - std::bit_cast<std::size_t>(this);
this->inUse = false;
}
template<typename T>
T *HeapSegment::data() noexcept {
return reinterpret_cast<T*>(reinterpret_cast<uint8_t*>(this) + alignedSize(this));
}
template<typename T>
T *HeapSegment::end() noexcept {
const auto size = alignedSize(this) + alignedSize(this->size);
auto e = std::bit_cast<uintptr_t>(reinterpret_cast<uint8_t*>(this) + size);
return reinterpret_cast<T*>(e);
}
void initHeap(void *heapBegin, void *heapEnd) noexcept {
g_heapBegin = reinterpret_cast<HeapSegment*>(heapBegin);
g_heapEnd = reinterpret_cast<HeapSegment*>(heapEnd);
heapIdx = g_heapBegin;
heapIdx->size = std::bit_cast<std::size_t>(heapEnd) - std::bit_cast<std::size_t>(heapIdx);
heapIdx->inUse = false;
}
struct SegmentPair {
HeapSegment *anteSegment = nullptr;
HeapSegment *segment = nullptr;
};
static SegmentPair findSegmentOf(void *ptr) noexcept {
HeapSegment *prev = nullptr;
for (auto seg = g_heapBegin; seg < g_heapEnd;) {
if (seg->data<void>() == ptr) {
return {prev, seg};
}
prev = seg;
seg = seg->end<HeapSegment>();
}
return {};
}
static HeapSegment *findSegmentFor(std::size_t sz) noexcept {
for (auto s = g_heapBegin; s <= g_heapEnd; s = s->end<HeapSegment>()) {
if (s->size >= sz && !s->inUse) {
return s;
}
}
oxPanic(OxError(1), "malloc: could not find segment");
return nullptr;
}
[[nodiscard]]
void *malloc(std::size_t allocSize) noexcept {
const auto targetSize = alignedSize(sizeof(HeapSegment)) + alignedSize(allocSize);
auto seg = findSegmentFor(targetSize);
if (seg == nullptr) {
return nullptr;
}
const auto bytesRemaining = seg->size - targetSize;
seg->size = targetSize;
seg->inUse = true;
seg->end<HeapSegment>()->init(bytesRemaining);
return seg->data<void>();
}
void free(void *ptr) noexcept {
auto p = findSegmentOf(ptr);
if (p.anteSegment) {
p.anteSegment->size += p.segment->size;
} else if (p.segment) {
p.segment->inUse = false;
} else {
oxPanic(OxError(1), "Bad heap free");
}
}
}
#ifndef OX_USE_STDLIB
using namespace ox;
void *operator new(std::size_t allocSize) noexcept {
return heapmgr::malloc(allocSize);
}
void *operator new[](std::size_t allocSize) noexcept {
return heapmgr::malloc(allocSize);
}
void operator delete(void *ptr) noexcept {
heapmgr::free(ptr);
}
void operator delete[](void *ptr) noexcept {
heapmgr::free(ptr);
}
void operator delete(void *ptr, unsigned) noexcept {
heapmgr::free(ptr);
}
void operator delete[](void *ptr, unsigned) noexcept {
heapmgr::free(ptr);
}
void operator delete(void *ptr, unsigned long int) noexcept {
heapmgr::free(ptr);
}
void operator delete[](void *ptr, unsigned long int) noexcept {
heapmgr::free(ptr);
}
#endif

36
deps/ox/src/ox/std/heapmgr.hpp vendored Normal file
View File

@@ -0,0 +1,36 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#include "types.hpp"
namespace ox::heapmgr {
struct HeapSegment {
std::size_t size;
uint8_t inUse;
void init(std::size_t maxSize) noexcept;
template<typename T>
[[nodiscard]]
T *data() noexcept;
template<typename T = uint8_t>
[[nodiscard]]
T *end() noexcept;
};
void initHeap(void *heapBegin, void *heapEnd) noexcept;
[[nodiscard]]
void *malloc(std::size_t allocSize) noexcept;
void free(void *ptr) noexcept;
}

46
deps/ox/src/ox/std/initializerlist.hpp vendored Normal file
View File

@@ -0,0 +1,46 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
#if __has_include(<initializer_list>)
#include <initializer_list>
#else
#include "types.hpp"
namespace std {
template<typename T>
class initializer_list {
private:
T *m_begin = nullptr;
size_t m_size = 0;
public:
constexpr initializer_list() noexcept = default;
constexpr size_t size() const noexcept {
return m_size;
}
constexpr T *begin() const noexcept {
return m_begin;
}
constexpr T *end() const noexcept {
return m_begin + m_size;
}
private:
constexpr initializer_list(T *begin, size_t size) noexcept: m_begin(begin), m_size(size) {}
};
}
#endif

165
deps/ox/src/ox/std/iterator.hpp vendored Normal file
View File

@@ -0,0 +1,165 @@
/*
* Copyright 2015 - 2023 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "math.hpp"
#if !__has_include(<iterator>)
#include "stddef.hpp"
namespace std {
struct input_iterator_tag {
};
struct output_iterator_tag {
};
struct forward_iterator_tag: public input_iterator_tag {
};
struct bidirectional_iterator_tag: public forward_iterator_tag {
};
struct random_access_iterator_tag: public bidirectional_iterator_tag {
};
struct contiguous_iterator_tag: public random_access_iterator_tag {
};
}
#else
#include <iterator>
#endif
namespace ox {
template<typename Category, typename T, typename DiffType = std::ptrdiff_t,
typename PointerType = T*, typename ReferenceType = T&>
struct Iterator {
using iterator_category = Category;
using value_type = T;
using pointer = T*;
using reference = T&;
using difference_type = DiffType;
};
template<typename T, typename RefType, typename PtrType, bool reverse = false>
struct SpanIterator {
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = T;
using pointer = T*;
using reference = T&;
using difference_type = std::ptrdiff_t;
private:
PtrType m_t = nullptr;
std::size_t m_offset = 0;
std::size_t m_max = 0;
public:
constexpr SpanIterator() noexcept = default;
constexpr SpanIterator(PtrType t, std::size_t offset, std::size_t max) noexcept:
m_t(t),
m_offset(offset),
m_max(max) {
}
constexpr auto offset() const noexcept {
return m_offset;
}
constexpr SpanIterator operator+(std::size_t s) const noexcept {
if constexpr(reverse) {
return SpanIterator(m_t, max<std::size_t>(m_offset - s, 0), m_max);
} else {
return SpanIterator(m_t, min<std::size_t>(m_offset + s, m_max), m_max);
}
}
constexpr auto operator-(const SpanIterator &other) const noexcept {
if constexpr(reverse) {
return m_offset + other.m_offset;
} else {
return m_offset - other.m_offset;
}
}
constexpr SpanIterator operator-(std::size_t s) const noexcept {
if constexpr(reverse) {
return SpanIterator(m_t, min<std::size_t>(m_offset + s, m_max), m_max);
} else {
return SpanIterator(m_t, max<std::size_t>(m_offset - s, 0), m_max);
}
}
constexpr SpanIterator &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 SpanIterator &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 SpanIterator &operator++() noexcept {
return operator+=(1);
}
constexpr SpanIterator &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 SpanIterator &other) const noexcept {
return m_offset < other.m_offset;
}
constexpr bool operator>(const SpanIterator &other) const noexcept {
return m_offset > other.m_offset;
}
constexpr bool operator<=(const SpanIterator &other) const noexcept {
return m_offset <= other.m_offset;
}
constexpr bool operator>=(const SpanIterator &other) const noexcept {
return m_offset >= other.m_offset;
}
constexpr bool operator==(const SpanIterator &other) const noexcept {
return m_t == other.m_t && m_offset == other.m_offset && m_max == other.m_max;
}
constexpr bool operator!=(const SpanIterator &other) const noexcept {
return m_t != other.m_t || m_offset != other.m_offset || m_max != other.m_max;
}
};
}

23
deps/ox/src/ox/std/math.cpp vendored Normal file
View File

@@ -0,0 +1,23 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#include "math.hpp"
namespace ox {
static_assert(min(2, 1) == 1);
static_assert(min(1, 2) == 1);
static_assert(max(2, 1) == 2);
static_assert(max(1, 2) == 2);
static_assert(clamp(2, 1, 3) == 2);
static_assert(clamp(1, 2, 3) == 2);
static_assert(clamp(3, 1, 2) == 2);
}

61
deps/ox/src/ox/std/math.hpp vendored Normal file
View File

@@ -0,0 +1,61 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "typetraits.hpp"
namespace ox {
template<typename T>
[[nodiscard]]
constexpr T min(T a, T b) noexcept requires(ox::is_integral_v<T>) {
return a < b ? a : b;
}
template<typename T>
[[nodiscard]]
constexpr const T &min(const T &a, const T &b) noexcept requires(!ox::is_integral_v<T>) {
return a < b ? a : b;
}
template<typename T>
[[nodiscard]]
constexpr T max(T a, T b) noexcept requires(ox::is_integral_v<T>) {
return a > b ? a : b;
}
template<typename T>
[[nodiscard]]
constexpr const T &max(const T &a, const T &b) noexcept requires(!ox::is_integral_v<T>) {
return a > b ? a : b;
}
template<typename T>
[[nodiscard]]
constexpr T clamp(T v, T lo, T hi) noexcept requires(ox::is_integral_v<T>) {
return min(ox::max(v, lo), hi);
}
template<typename T>
[[nodiscard]]
constexpr const T &clamp(const T &v, const T &lo, const T &hi) noexcept requires(!ox::is_integral_v<T>) {
return min(ox::max(v, lo), hi);
}
template<typename I>
[[nodiscard]]
constexpr I pow(I v, int e) noexcept {
I out = 1;
for (I i = 0; i < e; i++) {
out *= v;
}
return out;
}
}

55
deps/ox/src/ox/std/memops.cpp vendored Normal file
View File

@@ -0,0 +1,55 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#include "types.hpp"
#include "memops.hpp"
#ifndef OX_USE_STDLIB
#define ox_inhibit_loop_to_libcall __attribute__((__optimize__("-fno-tree-loop-distribute-patterns")))
extern "C" {
void *ox_inhibit_loop_to_libcall memcpy(void *dest, const void *src, std::size_t size) {
return ox_memcpy(dest, src, size);
}
void *ox_inhibit_loop_to_libcall memmove(void *dest, const void *src, std::size_t size) {
return ox_memcpy(dest, src, size);
}
void *ox_inhibit_loop_to_libcall memset(void *ptr, int val, std::size_t size) {
return ox_memset(ptr, val, size);
}
int ox_inhibit_loop_to_libcall memcmp(const void *ptr1, const void *ptr2, std::size_t size) noexcept {
int retval = 0;
auto block1 = reinterpret_cast<const uint8_t*>(ptr1);
auto block2 = reinterpret_cast<const uint8_t*>(ptr2);
for (std::size_t i = 0; i < size; i++) {
if (block1[i] < block2[i]) {
retval = -1;
break;
} else if (block1[i] > block2[i]) {
retval = 1;
break;
}
}
return retval;
}
}
#undef ox_inhibit_loop_to_libcall
#endif
int ox_memcmp(const void *ptr1, const void *ptr2, std::size_t size) noexcept {
return memcmp(ptr1, ptr2, size);
}

94
deps/ox/src/ox/std/memops.hpp vendored Normal file
View File

@@ -0,0 +1,94 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "defines.hpp"
#include "types.hpp"
#include "typetraits.hpp"
#if __has_include(<cstring>)
#include<cstring>
#else
extern "C" {
void *memcpy(void *dest, const void *src, std::size_t size);
void *memmove(void *dest, const void *src, std::size_t size);
void *memset(void *ptr, int val, std::size_t size);
int memcmp(const void *ptr1, const void *ptr2, std::size_t size) noexcept;
}
#endif
int ox_memcmp(const void *ptr1, const void *ptr2, std::size_t size) noexcept;
constexpr void *ox_memcpy(void *dest, const void *src, std::size_t size) noexcept {
if (std::is_constant_evaluated() || !ox::defines::UseStdLib) {
auto srcBuf = static_cast<const char*>(src);
auto dstBuf = static_cast<char*>(dest);
for (std::size_t i = 0; i < size; ++i) {
dstBuf[i] = static_cast<char>(srcBuf[i]);
}
return dest;
} else {
return memcpy(dest, src, size);
}
}
constexpr void *ox_memmove(void *dest, const void *src, std::size_t size) noexcept {
if (std::is_constant_evaluated() || !ox::defines::UseStdLib) {
auto srcBuf = static_cast<const char *>(src);
auto dstBuf = static_cast<char *>(dest);
for (std::size_t i = 0; i < size; ++i) {
dstBuf[i] = static_cast<char>(srcBuf[i]);
}
return dest;
} else {
return memmove(dest, src, size);
}
}
constexpr void *ox_memset(void *ptr, int val, std::size_t size) noexcept {
if (std::is_constant_evaluated() || !ox::defines::UseStdLib) {
auto buf = static_cast<uint8_t*>(ptr);
for (std::size_t i = 0; i < size; ++i) {
buf[i] = static_cast<uint8_t>(val);
}
return ptr;
} else {
return memset(ptr, val, size);
}
}
namespace ox {
constexpr void *memmove(void *dest, const void *src, std::size_t size) {
return ox_memmove(dest, src, size);
}
constexpr void *memset(void *ptr, int val, std::size_t size) noexcept {
return ox_memset(ptr, val, size);
}
constexpr void *memcpy(void *dest, const void *src, std::size_t size) noexcept {
return ox_memcpy(dest, src, size);
}
inline int memcmp(const void *ptr1, const void *ptr2, std::size_t size) noexcept {
return ox_memcmp(ptr1, ptr2, size);
}
template<typename T>
void *memsetElements(T *ptr, T val, std::size_t elements) noexcept {
return memset(ptr, val, elements * sizeof(T));
}
}

291
deps/ox/src/ox/std/memory.hpp vendored Normal file
View File

@@ -0,0 +1,291 @@
/*
* 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
#if __has_include(<memory>)
#include <memory>
#else
#include "utility.hpp"
namespace std {
template<class T>
struct allocator {
[[nodiscard]]
constexpr T *allocate(size_t n) {
return static_cast<T*>(::operator new(n * sizeof(T)));
}
constexpr void deallocate(T *p, std::size_t) {
::operator delete(p);
}
};
template<typename T, typename... Args>
constexpr T *construct_at(T *p, Args &&...args ) {
return new (p) T(ox::forward<Args>(args)...);
}
}
#endif
#include "utility.hpp"
namespace ox {
/*
* safeDelete exists because deleting an incomplete type will simply
* free the memory without running the destructor.
*/
template<typename T>
void safeDelete(T *val) requires(sizeof(T) >= 1) {
delete val;
}
template<typename T>
void safeDeleteArray(T *val) requires(sizeof(T) >= 1) {
delete[] val;
}
struct DefaultDelete {
constexpr void operator()(auto *p) noexcept {
safeDelete(p);
}
};
template<typename T, typename Deleter = DefaultDelete>
class SharedPtr {
private:
T *m_t = nullptr;
int *m_refCnt = nullptr;
public:
explicit constexpr SharedPtr(T *t = nullptr) noexcept: m_t(t), m_refCnt(new int) {
}
constexpr SharedPtr(SharedPtr &other) {
m_t = other.m_t;
m_refCnt = other.m_refCnt;
++*m_refCnt;
}
constexpr SharedPtr(const SharedPtr&) = delete;
template<typename U>
constexpr SharedPtr(SharedPtr<U> &&other) noexcept {
m_t = other.m_t;
m_refCnt = other.m_refCnt;
other.m_refCnt = nullptr;
}
~SharedPtr() {
if (m_refCnt) {
--*m_refCnt;
if (!*m_refCnt) {
Deleter()(m_t);
safeDelete(m_refCnt);
}
}
}
[[nodiscard]]
constexpr T *get() const noexcept {
return m_t;
}
constexpr T *reset() noexcept {
if (m_refCnt) {
--*m_refCnt;
if (!*m_refCnt) {
safeDelete(m_refCnt);
Deleter()(m_t);
}
}
}
template<typename U>
constexpr void reset(U *other) {
reset();
m_t = other;
m_refCnt = new int(1);
}
template<typename U>
constexpr SharedPtr &operator=(SharedPtr<U> &&other) {
reset(std::move(other));
return *this;
}
constexpr T *operator->() const noexcept {
return m_t;
}
constexpr T &operator*() const noexcept {
return *m_t;
}
constexpr operator bool() const noexcept {
return m_t;
}
};
template<typename T>
constexpr bool operator==(const SharedPtr<T> &p1, const SharedPtr<T> &p2) noexcept {
return p1.get() == p2.get();
}
template<typename T>
constexpr bool operator==(const SharedPtr<T> &p1, std::nullptr_t) noexcept {
return p1.get();
}
template<typename T>
constexpr bool operator==(std::nullptr_t, const SharedPtr<T> &p2) noexcept {
return p2.get();
}
template<typename T>
constexpr bool operator!=(const SharedPtr<T> &p1, const SharedPtr<T> &p2) noexcept {
return p1.get() != p2.get();
}
template<typename T>
constexpr bool operator!=(const SharedPtr<T> &p1, std::nullptr_t) noexcept {
return !p1.get();
}
template<typename T>
constexpr bool operator!=(std::nullptr_t, const SharedPtr<T> &p2) noexcept {
return !p2.get();
}
template<typename T, typename Deleter = DefaultDelete>
class UniquePtr {
private:
T *m_t = nullptr;
public:
explicit constexpr UniquePtr(T *t = nullptr) noexcept: m_t(t) {
}
constexpr UniquePtr(UniquePtr&) = delete;
constexpr UniquePtr(const UniquePtr&) = delete;
template<typename U, typename UDeleter>
constexpr UniquePtr(UniquePtr<U, UDeleter> &&other) noexcept {
m_t = other.release();
}
constexpr ~UniquePtr() {
Deleter()(m_t);
}
constexpr T *release() noexcept {
auto t = m_t;
m_t = nullptr;
return t;
}
[[nodiscard]]
constexpr T *get() const noexcept {
return m_t;
}
template<typename U, typename UDeleter>
constexpr void reset(UniquePtr<U, UDeleter> &&other = UniquePtr()) {
auto t = m_t;
m_t = other.release();
Deleter()(t);
}
constexpr UniquePtr &operator=(UniquePtr const&other) = delete;
template<typename U, typename UDeleter>
constexpr UniquePtr &operator=(UniquePtr<U, UDeleter> const&other) = delete;
constexpr UniquePtr &operator=(UniquePtr<T> &&other) noexcept {
reset(std::move(other));
return *this;
}
template<typename U, typename UDeleter>
constexpr UniquePtr &operator=(UniquePtr<U, UDeleter> &&other) noexcept {
reset(std::move(other));
return *this;
}
constexpr T *operator->() const noexcept {
return m_t;
}
constexpr T &operator*() const noexcept {
return *m_t;
}
constexpr operator bool() const noexcept {
return m_t;
}
};
template<typename T, typename Deleter = DefaultDelete>
using UPtr = UniquePtr<T, Deleter>;
template<typename T>
constexpr bool operator==(const UniquePtr<T> &p1, const UniquePtr<T> &p2) noexcept {
return p1.get() == p2.get();
}
template<typename T>
constexpr bool operator==(const UniquePtr<T> &p1, std::nullptr_t) noexcept {
return p1.get();
}
template<typename T>
constexpr bool operator==(std::nullptr_t, const UniquePtr<T> &p2) noexcept {
return p2.get();
}
template<typename T>
constexpr bool operator!=(const UniquePtr<T> &p1, const UniquePtr<T> &p2) noexcept {
return p1.get() != p2.get();
}
template<typename T>
constexpr bool operator!=(const UniquePtr<T> &p1, std::nullptr_t) noexcept {
return !p1.get();
}
template<typename T>
constexpr bool operator!=(std::nullptr_t, const UniquePtr<T> &p2) noexcept {
return !p2.get();
}
template<typename T, typename U = T, typename ...Args>
[[nodiscard]]
constexpr auto make_unique(Args&&... args) {
return UniquePtr<U>(new T(ox::forward<Args>(args)...));
}
}

171
deps/ox/src/ox/std/new.hpp vendored Normal file
View File

@@ -0,0 +1,171 @@
/*
* 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 "error.hpp"
#include "defines.hpp"
#include "types.hpp"
#include "utility.hpp"
#if defined(_MSC_VER)
#include <malloc.h>
#elif OX_USE_STDLIB
#include <cstdlib>
#endif
#if __has_include(<new>)
#include <new>
#else
constexpr void *operator new(std::size_t, void *addr) noexcept {
return addr;
}
constexpr void *operator new[](std::size_t, void *addr) noexcept {
return addr;
}
#endif
namespace ox {
template<typename T, typename U = T, typename ...Args>
[[nodiscard]]
constexpr U *make(Args &&...args) noexcept {
#ifdef __cpp_exceptions
try {
return new T(ox::forward<Args>(args)...);
} catch (std::exception const&ex) {
oxPanic(OxError(1, ex.what()), ex.what());
return nullptr;
} catch (...) {
oxPanic(OxError(2, "Allocation or constructor failed"), "Allocation or constructor failed");
return nullptr;
}
#else
return new T(ox::forward<Args>(args)...);
#endif
}
template<typename T, typename ...Args>
[[nodiscard]]
constexpr Result<T*> makeCatch(Args &&...args) noexcept {
#ifdef __cpp_exceptions
try {
return new T(ox::forward<Args>(args)...);
} catch (const ox::Exception &ex) {
return ex.toError();
} catch (...) {
return OxError(1, "Allocation or constructor failed");
}
#else
return new T(ox::forward<Args>(args)...);
#endif
}
constexpr auto MallocaStackLimit = defines::UseStdLib ? 1024 : 0;
/**
* MallocaPtr will automatically cleanup the pointed to address upon
* destruction if the size of the allocation is greater than MallocaStackLimit.
*/
template<typename T>
class MallocaPtr {
private:
bool m_onHeap = false;
T *m_val = nullptr;
public:
constexpr MallocaPtr() noexcept = default;
constexpr MallocaPtr(MallocaPtr &other) = delete;
constexpr MallocaPtr(const MallocaPtr &other) = delete;
constexpr MallocaPtr(MallocaPtr &&other) noexcept {
m_onHeap = other.m_onHeap;
m_val = other.m_val;
other.m_onHeap = false;
other.m_val = nullptr;
}
constexpr MallocaPtr(bool onHeap, T *val) noexcept {
m_onHeap = onHeap;
m_val = val;
}
constexpr ~MallocaPtr() noexcept {
if (m_onHeap && m_val) {
delete[] reinterpret_cast<uint8_t*>(m_val);
}
}
constexpr const T *get() const noexcept {
return reinterpret_cast<T*>(m_val);
}
constexpr T *get() noexcept {
return reinterpret_cast<T*>(m_val);
}
constexpr MallocaPtr &operator=(MallocaPtr &other) = delete;
constexpr MallocaPtr &operator=(const MallocaPtr &other) = delete;
constexpr MallocaPtr &operator=(MallocaPtr &&other) noexcept {
if (m_onHeap && m_val) {
delete[] reinterpret_cast<uint8_t*>(m_val);
}
m_onHeap = other.m_onHeap;
m_val = other.m_val;
other.m_onHeap = false;
other.m_val = nullptr;
return *this;
}
constexpr const T *operator->() const noexcept {
return reinterpret_cast<T*>(m_val);
}
constexpr T *operator->() noexcept {
return reinterpret_cast<T*>(m_val);
}
constexpr explicit operator const T*() const noexcept {
return reinterpret_cast<T*>(m_val);
}
constexpr explicit operator T*() noexcept {
return reinterpret_cast<T*>(m_val);
}
constexpr const T &operator*() const noexcept {
return *reinterpret_cast<T*>(m_val);
}
constexpr T &operator*() noexcept {
return *reinterpret_cast<T*>(m_val);
}
constexpr bool operator==(std::nullptr_t) const noexcept {
return m_val == nullptr;
}
constexpr bool operator==(const MallocaPtr<T> &other) const noexcept {
return m_val == other.m_val && m_onHeap == other.m_onHeap;
}
constexpr bool operator!=(const MallocaPtr<T> &other) const noexcept {
return m_val != other.m_val || m_onHeap != other.m_onHeap;
}
};
}

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

@@ -0,0 +1,170 @@
/*
* 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 "bit.hpp"
#include "initializerlist.hpp"
#include "iterator.hpp"
#include "memory.hpp"
#include "new.hpp"
#include "types.hpp"
#include "utility.hpp"
namespace ox {
template<typename T, std::size_t buffSize = sizeof(T)>
class Optional {
private:
T *m_ptr = nullptr;
AllocAlias<T> m_data = {};
public:
constexpr Optional() noexcept = default;
template<typename ...Args>
explicit constexpr Optional(ox::in_place_t, Args &&... args);
constexpr Optional(const Optional &other) {
if (other.m_ptr) {
m_ptr = std::construct_at<T>(m_data.data(), *other.m_ptr);
}
}
constexpr Optional(Optional &&other) noexcept {
if (other.m_ptr) {
m_ptr = std::construct_at<T>(m_data.data(), std::move(*other.m_ptr));
}
}
constexpr ~Optional() {
if (m_ptr) {
reset();
}
}
constexpr T &value() & noexcept {
return *m_ptr;
}
constexpr const T &value() const & noexcept {
return *m_ptr;
}
constexpr T &&value() && noexcept {
return *m_ptr;
}
constexpr const T &&value() const && noexcept {
return *m_ptr;
}
constexpr T &operator*() & noexcept {
return *m_ptr;
}
constexpr const T &operator*() const & noexcept {
return *m_ptr;
}
constexpr T &&operator*() && noexcept {
return *m_ptr;
}
constexpr const T &&operator*() const && noexcept {
return *m_ptr;
}
constexpr T *operator->() noexcept {
return m_ptr;
}
constexpr const T *operator->() const noexcept {
return m_ptr;
}
constexpr Optional &operator=(const Optional &other) {
if (this == &other) {
return *this;
}
if (other.m_ptr) {
if (!m_ptr) {
emplace();
}
*m_ptr = *other.m_ptr;
} else {
reset();
}
return *this;
}
constexpr Optional &operator=(Optional &&other) noexcept {
if (this == &other) {
return *this;
}
if (other.m_ptr) {
if (!m_ptr) {
emplace();
}
*m_ptr = std::move(*other.m_ptr);
} else {
reset();
}
return *this;
}
template<class... Args>
constexpr T &emplace(Args &&...args) {
reset();
if (std::is_constant_evaluated()) {
m_ptr = new T(ox::forward<Args>(args)...);
} else {
m_ptr = std::construct_at<T>(reinterpret_cast<T*>(m_data.data()), ox::forward<Args>(args)...);
}
return *m_ptr;
}
template<typename U, class... Args>
constexpr T &emplace_subclass(Args &&...args) {
static_assert(sizeof(U) <= buffSize, "Subclass is too large for this Optional");
reset();
if (std::is_constant_evaluated()) {
m_ptr = new U(ox::forward<Args>(args)...);
} else {
m_ptr = std::construct_at<U>(reinterpret_cast<U*>(m_data.data()), ox::forward<Args>(args)...);
}
return *m_ptr;
}
[[nodiscard]]
constexpr bool has_value() const noexcept {
return m_ptr;
}
explicit constexpr operator bool() const noexcept {
return m_ptr;
}
constexpr void reset() {
if (std::is_constant_evaluated()) {
ox::safeDelete(m_ptr);
} else if (has_value()) {
value().~T();
}
m_ptr = nullptr;
}
};
template<typename T, std::size_t buffSize>
template<typename... Args>
constexpr Optional<T, buffSize>::Optional(ox::in_place_t, Args &&... args) {
emplace(ox::forward<Args>(args)...);
}
}

195
deps/ox/src/ox/std/point.hpp vendored Normal file
View File

@@ -0,0 +1,195 @@
/*
* Copyright 2015 - 2023 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <ox/model/def.hpp>
#include <ox/std/error.hpp>
namespace ox {
class Point {
public:
static constexpr auto TypeName = "net.drinkingtea.ox.Point";
static constexpr auto TypeVersion = 1;
int x = 0;
int y = 0;
constexpr Point() noexcept = default;
constexpr Point(int x, int y) noexcept;
constexpr Point operator+(const Point &p) const noexcept;
constexpr Point operator-(const Point &p) const noexcept;
constexpr Point operator*(const Point &p) const noexcept;
constexpr Point operator/(const Point &p) const noexcept;
constexpr Point operator+=(const Point &p) noexcept;
constexpr Point operator-=(const Point &p) noexcept;
constexpr Point operator*=(const Point &p) noexcept;
constexpr Point operator/=(const Point &p) noexcept;
constexpr Point operator+(int i) const noexcept;
constexpr Point operator-(int i) const noexcept;
constexpr Point operator*(int i) const noexcept;
constexpr Point operator/(int i) const noexcept;
constexpr Point operator+=(int i) noexcept;
constexpr Point operator-=(int i) noexcept;
constexpr Point operator*=(int i) noexcept;
constexpr Point operator/=(int i) noexcept;
constexpr bool operator==(const Point&) const noexcept;
constexpr bool operator!=(const Point&) const noexcept;
};
constexpr Point::Point(int x, int y) noexcept {
this->x = x;
this->y = y;
}
constexpr Point Point::operator+(const Point &p) const noexcept {
auto out = *this;
out.x += p.x;
out.y += p.y;
return out;
}
constexpr Point Point::operator-(const Point &p) const noexcept {
auto out = *this;
out.x -= p.x;
out.y -= p.y;
return out;
}
constexpr Point Point::operator*(const Point &p) const noexcept {
auto out = *this;
out.x *= p.x;
out.y *= p.y;
return out;
}
constexpr Point Point::operator/(const Point &p) const noexcept {
auto out = *this;
out.x /= p.x;
out.y /= p.y;
return out;
}
constexpr Point Point::operator+=(const Point &p) noexcept {
x += p.x;
y += p.y;
return *this;
}
constexpr Point Point::operator-=(const Point &p) noexcept {
x -= p.x;
y -= p.y;
return *this;
}
constexpr Point Point::operator*=(const Point &p) noexcept {
x *= p.x;
y *= p.y;
return *this;
}
constexpr Point Point::operator/=(const Point &p) noexcept {
x /= p.x;
y /= p.y;
return *this;
}
constexpr Point Point::operator+(int i) const noexcept {
auto out = *this;
out.x += i;
out.y += i;
return out;
}
constexpr Point Point::operator-(int i) const noexcept {
auto out = *this;
out.x -= i;
out.y -= i;
return out;
}
constexpr Point Point::operator*(int i) const noexcept {
auto out = *this;
out.x *= i;
out.y *= i;
return out;
}
constexpr Point Point::operator/(int i) const noexcept {
auto out = *this;
out.x /= i;
out.y /= i;
return out;
}
constexpr Point Point::operator+=(int i) noexcept {
x += i;
y += i;
return *this;
}
constexpr Point Point::operator-=(int i) noexcept {
x -= i;
y -= i;
return *this;
}
constexpr Point Point::operator*=(int i) noexcept {
x *= i;
y *= i;
return *this;
}
constexpr Point Point::operator/=(int i) noexcept {
x /= i;
y /= i;
return *this;
}
constexpr bool Point::operator==(const Point &p) const noexcept {
return x == p.x && y == p.y;
}
constexpr bool Point::operator!=(const Point &p) const noexcept {
return x != p.x || y != p.y;
}
template<typename T>
constexpr Error model(T *io, ox::CommonPtrWith<Point> auto *obj) noexcept {
oxReturnError(io->template setTypeInfo<Point>());
oxReturnError(io->field("x", &obj->x));
oxReturnError(io->field("y", &obj->y));
return {};
}
}

15
deps/ox/src/ox/std/random.cpp vendored Normal file
View File

@@ -0,0 +1,15 @@
/*
* Copyright 2015 - 2023 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 http://mozilla.org/MPL/2.0/.
*/
#include "bit.hpp"
#include "random.hpp"
namespace ox {
}

53
deps/ox/src/ox/std/random.hpp vendored Normal file
View File

@@ -0,0 +1,53 @@
/*
* Copyright 2015 - 2023 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "bit.hpp"
#include "stddef.hpp"
#include "types.hpp"
namespace ox {
using RandomSeed = uint64_t[2];
// An implementation of the Xoroshiro128+ algorithm
class OX_PACKED Random {
private:
RandomSeed m_seed = {540932923848, 540932540932};
public:
constexpr Random() noexcept = default;
explicit constexpr Random(const RandomSeed &seed) noexcept;
constexpr void seed(const RandomSeed &seed) noexcept;
constexpr uint64_t gen() noexcept;
};
constexpr Random::Random(const RandomSeed &seed) noexcept: m_seed{seed[0], seed[1]} {
}
constexpr void Random::seed(const RandomSeed &seed) noexcept {
m_seed[0] = seed[0];
m_seed[1] = seed[1];
}
constexpr uint64_t Random::gen() noexcept {
auto s0 = m_seed[0];
auto s1 = m_seed[1];
const auto retval = s0 + s1;
// reseed for next number
s1 ^= s0;
m_seed[0] = rotl(s0, 55) ^ s1 ^ (s1 << 14);
m_seed[1] = rotl(s1, 36);
return retval;
}
}

25
deps/ox/src/ox/std/range.hpp vendored Normal file
View File

@@ -0,0 +1,25 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
namespace ox {
template<typename T>
class range {
private:
T m_begin = 0;
T m_end = 0;
public:
constexpr range(T begin, T end) noexcept: m_begin(begin), m_end(end) {
}
};
}

35
deps/ox/src/ox/std/ranges.hpp vendored Normal file
View File

@@ -0,0 +1,35 @@
/*
* Copyright 2015 - 2023 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
namespace ox {
[[nodiscard]]
constexpr bool all_of(auto begin, auto end, auto pred) noexcept {
while (begin != end) {
if (!pred(*begin)) {
return false;
}
++begin;
}
return true;
}
[[nodiscard]]
constexpr bool any_of(auto begin, auto end, auto pred) noexcept {
while (begin != end) {
if (pred(*begin)) {
return true;
}
++begin;
}
return false;
}
}

59
deps/ox/src/ox/std/reader.cpp vendored Normal file
View File

@@ -0,0 +1,59 @@
/*
* Copyright 2015 - 2023 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 http://mozilla.org/MPL/2.0/.
*/
#ifdef OX_USE_STDLIB
#include <cstdio>
#include "array.hpp"
#include "reader.hpp"
namespace ox {
[[nodiscard]]
constexpr int sdMap(ox::ios_base::seekdir in) noexcept {
switch (in) {
case ox::ios_base::beg:
return SEEK_SET;
case ox::ios_base::end:
return SEEK_END;
case ox::ios_base::cur:
return SEEK_CUR;
}
return -1;
}
ox::Result<char> FileReader::peek() const noexcept {
auto const c = fgetc(m_file);
auto const ok = c != EOF;
if (ok && ungetc(c, m_file)) [[unlikely]] {
return OxError(1, "Unable to unget character");
}
return {static_cast<char>(c), OxError(!ok, "File peek failed")};
}
ox::Result<std::size_t> FileReader::read(char *v, std::size_t cnt) noexcept {
return fread(v, 1, cnt, m_file);
}
ox::Error FileReader::seekg(std::size_t p) noexcept {
return OxError(fseek(m_file, static_cast<int64_t>(p), SEEK_CUR) != 0);
}
ox::Error FileReader::seekg(int64_t p, ios_base::seekdir sd) noexcept {
return OxError(fseek(m_file, p, sdMap(sd)) != 0);
}
ox::Result<std::size_t> FileReader::tellg() noexcept {
const auto sz = ftell(m_file);
return {static_cast<std::size_t>(sz), OxError(sz == -1)};
}
}
#endif

96
deps/ox/src/ox/std/reader.hpp vendored Normal file
View File

@@ -0,0 +1,96 @@
/*
* Copyright 2015 - 2023 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
#ifdef OX_USE_STDLIB
#include <cstdio>
#endif
#include "concepts.hpp"
#include "error.hpp"
#include "types.hpp"
#include "writer.hpp"
namespace ox {
template<typename T>
concept Reader_c = requires(T v) {
{v.peek()} -> ox::same_as<ox::Result<char>>;
{v.read(static_cast<char*>(nullptr), static_cast<std::size_t>(0))} -> ox::same_as<ox::Result<std::size_t>>;
{v.seekg(static_cast<int64_t>(0))} -> ox::same_as<ox::Error>;
{v.seekg(static_cast<std::size_t>(0), ios_base::beg)} -> ox::same_as<ox::Error>;
{v.tellg()} -> ox::same_as<ox::Result<std::size_t>>;
};
class Reader_v {
public:
virtual constexpr ~Reader_v() noexcept = default;
[[nodiscard]]
virtual constexpr ox::Result<char> peek() const noexcept = 0;
virtual constexpr ox::Result<std::size_t> read(char*, std::size_t) noexcept = 0;
virtual constexpr ox::Result<std::size_t> tellg() noexcept = 0;
virtual constexpr ox::Error seekg(std::size_t) noexcept = 0;
virtual constexpr ox::Error seekg(int64_t, ios_base::seekdir) = 0;
};
template<Reader_c T>
class ReaderT: public Reader_v {
private:
T m_reader{};
public:
template<typename ...Args>
constexpr explicit ReaderT(Args&&... args) noexcept: m_reader(args...) {
}
constexpr ox::Result<char> peek() const noexcept override {
return m_reader.peek();
}
constexpr ox::Result<std::size_t> read(char *v, std::size_t cnt) noexcept override {
return m_reader.read(v, cnt);
}
constexpr ox::Error seekg(std::size_t p) noexcept override {
return m_reader.seekg(p);
}
constexpr ox::Error seekg(int64_t p, ios_base::seekdir sd) noexcept override {
return m_reader.seekg(p, sd);
}
constexpr ox::Result<std::size_t> tellg() noexcept override {
return m_reader.tellg();
}
};
#ifdef OX_USE_STDLIB
class FileReader: public Reader_v {
private:
FILE *m_file = nullptr;
public:
constexpr explicit FileReader(FILE *file) noexcept: m_file(file) {}
ox::Result<char> peek() const noexcept override;
ox::Result<std::size_t> read(char *v, std::size_t cnt) noexcept override;
ox::Error seekg(std::size_t p) noexcept override;
ox::Error seekg(int64_t p, ios_base::seekdir sd) noexcept override;
ox::Result<std::size_t> tellg() noexcept override;
};
#endif
/**
* Allocates the specified amount of data at the end of the current read stream.
* @param reader
* @param sz
* @return
*/
constexpr ox::Result<std::size_t> allocate(Reader_c auto *reader, std::size_t sz) noexcept {
const auto p = reader->tellg();
oxReturnError(reader->seekg(0, ios_base::end));
const auto out = reader->tellg();
oxReturnError(reader->read(nullptr, sz));
oxReturnError(reader->seekg(p));
return out;
}
}

15
deps/ox/src/ox/std/realstd.hpp vendored Normal file
View File

@@ -0,0 +1,15 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
#if __has_include(<cassert>)
#include <cassert>
#else
#define assert(e) while (1);
#endif

95
deps/ox/src/ox/std/serialize.hpp vendored Normal file
View File

@@ -0,0 +1,95 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "array.hpp"
#include "buffer.hpp"
#include "types.hpp"
#include "typetraits.hpp"
#include "writer.hpp"
namespace ox {
template<typename PlatSpec>
struct VectorMemMap {
const std::size_t smallVecSize = 0; // not a map value
uint8_t allocator = 0;
typename PlatSpec::size_t size = 0;
typename PlatSpec::size_t cap = 0;
typename PlatSpec::PtrType items = 0;
};
template<typename PlatSpec>
[[nodiscard]]
constexpr auto sizeOf(const VectorMemMap<PlatSpec> *t) noexcept {
constexpr auto padding = [](std::size_t size, std::size_t al) {
return size % al;
};
std::size_t size = 0;
if (t->smallVecSize) {
size += t->smallVecSize;
size += padding(size, PlatSpec::alignOf(t->allocator));
}
size += sizeof(t->allocator);
size += padding(size, PlatSpec::alignOf(t->size));
size += sizeof(t->size);
size += padding(size, PlatSpec::alignOf(t->cap));
size += sizeof(t->cap);
size += padding(size, PlatSpec::alignOf(t->items));
size += sizeof(t->items);
return size;
}
template<typename PlatSpec, std::size_t SmallVecSize = 0>
[[nodiscard]]
constexpr auto alignOf(const VectorMemMap<PlatSpec>&) noexcept {
const typename PlatSpec::size_t i = 0;
return PlatSpec::alignOf(i);
}
template<typename PlatSpec, typename T>
constexpr ox::Error pad(Writer_c auto *w, const T *v) noexcept {
const auto a = PlatSpec::alignOf(*v);
const auto excess = w->tellp() % a;
if (excess) {
return w->write(nullptr, a - excess);
} else {
return {};
}
}
template<typename PlatSpec>
constexpr ox::Error serialize(Writer_c auto *buff, const VectorMemMap<PlatSpec> &vm) noexcept {
oxReturnError(buff->write(nullptr, vm.smallVecSize));
oxReturnError(serialize(buff, PlatSpec::correctEndianness(vm.allocator)));
oxReturnError(pad<PlatSpec>(buff, &vm.size));
oxReturnError(serialize(buff, PlatSpec::correctEndianness(vm.size)));
oxReturnError(serialize(buff, PlatSpec::correctEndianness(vm.cap)));
oxReturnError(serialize(buff, PlatSpec::correctEndianness(vm.items)));
return {};
}
template<typename T>
constexpr ox::Error serialize(Writer_c auto *buff, T val) noexcept requires(is_integer_v<T>) {
ox::Array<char, sizeof(T)> tmp;
for (auto i = 0u; i < sizeof(T); ++i) {
tmp[i] = static_cast<char>((val >> i * 8) & 255);
}
return buff->write(tmp.data(), tmp.size());
};
template<typename T>
constexpr ox::Result<ox::Array<char, sizeof(T)>> serialize(const T &in) noexcept {
ox::Array<char, sizeof(T)> out = {};
CharBuffWriter w(out);
oxReturnError(serialize(&w, in));
return out;
};
}

196
deps/ox/src/ox/std/size.hpp vendored Normal file
View File

@@ -0,0 +1,196 @@
/*
* Copyright 2015 - 2023 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <ox/std/error.hpp>
#include <ox/std/concepts.hpp>
namespace ox {
class Size {
public:
static constexpr auto TypeName = "net.drinkingtea.ox.Size";
static constexpr auto TypeVersion = 1;
int width = 0;
int height = 0;
constexpr Size() noexcept = default;
constexpr Size(int width, int height) noexcept;
constexpr Size operator+(Size p) const noexcept;
constexpr Size operator-(Size p) const noexcept;
constexpr Size operator*(Size p) const noexcept;
constexpr Size operator/(Size p) const noexcept;
constexpr Size operator+=(Size p) noexcept;
constexpr Size operator-=(Size p) noexcept;
constexpr Size operator*=(Size p) noexcept;
constexpr Size operator/=(Size p) noexcept;
constexpr Size operator+(int i) const noexcept;
constexpr Size operator-(int i) const noexcept;
constexpr Size operator*(int i) const noexcept;
constexpr Size operator/(int i) const noexcept;
constexpr Size operator+=(int i) noexcept;
constexpr Size operator-=(int i) noexcept;
constexpr Size operator*=(int i) noexcept;
constexpr Size operator/=(int i) noexcept;
constexpr bool operator==(const Size&) const noexcept;
constexpr bool operator!=(const Size&) const noexcept;
};
constexpr Size::Size(int width, int height) noexcept {
this->width = width;
this->height = height;
}
constexpr Size Size::operator+(Size p) const noexcept {
p.width += width;
p.height += height;
return p;
}
constexpr Size Size::operator-(Size p) const noexcept {
auto out = *this;
out.width -= p.width;
out.height -= p.height;
return out;
}
constexpr Size Size::operator*(Size p) const noexcept {
p.width *= width;
p.height *= height;
return p;
}
constexpr Size Size::operator/(Size p) const noexcept {
auto out = *this;
out.width /= p.width;
out.height /= p.height;
return out;
}
constexpr Size Size::operator+=(Size p) noexcept {
width += p.width;
height += p.height;
return *this;
}
constexpr Size Size::operator-=(Size p) noexcept {
width -= p.width;
height -= p.height;
return *this;
}
constexpr Size Size::operator*=(Size p) noexcept {
width *= p.width;
height *= p.height;
return *this;
}
constexpr Size Size::operator/=(Size p) noexcept {
width /= p.width;
height /= p.height;
return *this;
}
constexpr Size Size::operator+(int i) const noexcept {
auto out = *this;
out.width += i;
out.height += i;
return out;
}
constexpr Size Size::operator-(int i) const noexcept {
auto out = *this;
out.width -= i;
out.height -= i;
return out;
}
constexpr Size Size::operator*(int i) const noexcept {
auto out = *this;
out.width *= i;
out.height *= i;
return out;
}
constexpr Size Size::operator/(int i) const noexcept {
auto out = *this;
out.width /= i;
out.height /= i;
return out;
}
constexpr Size Size::operator+=(int i) noexcept {
width += i;
height += i;
return *this;
}
constexpr Size Size::operator-=(int i) noexcept {
width -= i;
height -= i;
return *this;
}
constexpr Size Size::operator*=(int i) noexcept {
width *= i;
height *= i;
return *this;
}
constexpr Size Size::operator/=(int i) noexcept {
width /= i;
height /= i;
return *this;
}
constexpr bool Size::operator==(const Size &p) const noexcept {
return width == p.width && height == p.height;
}
constexpr bool Size::operator!=(const Size &p) const noexcept {
return width != p.width || height != p.height;
}
template<typename T>
constexpr Error model(T *io, ox::CommonPtrWith<Size> auto *obj) noexcept {
oxReturnError(io->template setTypeInfo<Size>());
oxReturnError(io->field("width", &obj->width));
oxReturnError(io->field("height", &obj->height));
return {};
}
}

241
deps/ox/src/ox/std/span.hpp vendored Normal file
View File

@@ -0,0 +1,241 @@
/*
* Copyright 2015 - 2023 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "bit.hpp"
#include "iterator.hpp"
#include "vector.hpp"
namespace ox {
template<typename T>
class SpanView {
private:
const T *m_items{};
const std::size_t m_size{};
public:
using value_type = T;
using size_type = std::size_t;
template<typename RefType = T const&, typename PtrType = T const*, bool reverse = false>
using iterator = SpanIterator<T, RefType, PtrType, reverse>;
constexpr SpanView() noexcept {}
template<std::size_t sz>
constexpr SpanView(ox::Array<T, sz> const&a) noexcept:
m_items(a.data()),
m_size(a.size()) {
}
template<std::size_t sz, typename Allocator>
constexpr SpanView(ox::Vector<T, sz, Allocator> const&v) noexcept:
m_items(v.data()),
m_size(v.size()) {
}
template<std::size_t sz>
constexpr SpanView(const T a[sz]) noexcept:
m_items(a),
m_size(sz) {
}
constexpr SpanView(const T *a, std::size_t sz) noexcept:
m_items(a),
m_size(sz) {
}
constexpr iterator<> begin() noexcept {
return iterator<>(m_items, 0, m_size);
}
constexpr iterator<> end() noexcept {
return iterator<>(m_items, m_size, m_size);
}
[[nodiscard]]
constexpr iterator<const T&, const T*> begin() const noexcept {
return iterator<const T&, const T*>(m_items, 0, m_size);
}
[[nodiscard]]
constexpr iterator<const T&, const T*> end() const noexcept {
return iterator<const T&, const T*>(m_items, m_size, m_size);
}
[[nodiscard]]
constexpr iterator<const T&, const T*> cbegin() const noexcept {
return iterator<const T&, const T*>(m_items, 0, m_size);
}
[[nodiscard]]
constexpr iterator<const T&, const T*> cend() const noexcept {
return iterator<const T&, const T*>(m_items, m_size, m_size);
}
[[nodiscard]]
constexpr iterator<const T&, const T*, true> crbegin() const noexcept {
return iterator<const T&, const T*, true>(m_items, m_size - 1, m_size);
}
[[nodiscard]]
constexpr iterator<const T&, const T*, true> crend() const noexcept {
return iterator<const T&, const T*, true>(m_items, MaxValue<size_type>, m_size);
}
[[nodiscard]]
constexpr iterator<const T&, const T*, true> rbegin() const noexcept {
return iterator<const T&, const T*, true>(m_items, m_size - 1, m_size);
}
[[nodiscard]]
constexpr iterator<const T&, const T*, true> rend() const noexcept {
return iterator<const T&, const T*, true>(m_items, MaxValue<size_type>, m_size);
}
constexpr const T &operator[](std::size_t i) const noexcept {
return m_items[i];
}
[[nodiscard]]
constexpr T const*data() const noexcept {
return m_items;
}
[[nodiscard]]
constexpr std::size_t size() const noexcept {
return m_size;
}
[[nodiscard]]
constexpr bool empty() const noexcept {
return m_size == 0;
}
};
template<typename T>
class Span {
private:
T *m_items{};
const std::size_t m_size{};
public:
using value_type = T;
using size_type = std::size_t;
template<typename RefType = T&, typename PtrType = T*, bool reverse = false>
using iterator = SpanIterator<T, RefType, PtrType, reverse>;
template<std::size_t sz>
constexpr Span(ox::Array<T, sz> &a) noexcept:
m_items(a.data()),
m_size(a.size()) {
}
template<std::size_t sz, typename Allocator>
constexpr Span(ox::Vector<T, sz, Allocator> &v) noexcept:
m_items(v.data()),
m_size(v.size()) {
}
template<std::size_t sz>
constexpr Span(T a[sz]) noexcept:
m_items(a),
m_size(sz) {
}
constexpr Span(T *a, std::size_t sz) noexcept:
m_items(a),
m_size(sz) {
}
constexpr iterator<> begin() noexcept {
return iterator<>(m_items, 0, m_size);
}
constexpr iterator<> end() noexcept {
return iterator<>(m_items, m_size, m_size);
}
[[nodiscard]]
constexpr iterator<const T&, const T*> begin() const noexcept {
return iterator<const T&, const T*>(m_items, 0, m_size);
}
[[nodiscard]]
constexpr iterator<const T&, const T*> end() const noexcept {
return iterator<const T&, const T*>(m_items, m_size, m_size);
}
[[nodiscard]]
constexpr iterator<const T&, const T*> cbegin() const noexcept {
return iterator<const T&, const T*>(m_items, 0, m_size);
}
[[nodiscard]]
constexpr iterator<const T&, const T*> cend() const noexcept {
return iterator<const T&, const T*>(m_items, m_size, m_size);
}
[[nodiscard]]
constexpr iterator<T&, T*, true> rbegin() noexcept {
return iterator<T&, T*, true>(m_items, m_size - 1, m_size);
}
[[nodiscard]]
constexpr iterator<T&, T*, true> rend() noexcept {
return iterator<T&, T*, true>(m_items, MaxValue<size_type>, m_size);
}
[[nodiscard]]
constexpr iterator<const T&, const T*, true> crbegin() const noexcept {
return iterator<const T&, const T*, true>(m_items, m_size - 1, m_size);
}
[[nodiscard]]
constexpr iterator<const T&, const T*, true> crend() const noexcept {
return iterator<const T&, const T*, true>(m_items, MaxValue<size_type>, m_size);
}
[[nodiscard]]
constexpr iterator<const T&, const T*, true> rbegin() const noexcept {
return iterator<const T&, const T*, true>(m_items, m_size - 1, m_size);
}
[[nodiscard]]
constexpr iterator<const T&, const T*, true> rend() const noexcept {
return iterator<const T&, const T*, true>(m_items, MaxValue<size_type>, m_size);
}
constexpr const T &operator[](std::size_t i) const noexcept {
return m_items[i];
}
[[nodiscard]]
constexpr auto data() const noexcept {
return m_items;
}
[[nodiscard]]
constexpr std::size_t size() const noexcept {
return m_size;
}
[[nodiscard]]
constexpr bool empty() const noexcept {
return m_size == 0;
}
};
}

80
deps/ox/src/ox/std/stacktrace.cpp vendored Normal file
View File

@@ -0,0 +1,80 @@
/*
* Copyright 2015 - 2023 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 http://mozilla.org/MPL/2.0/.
*/
#if defined(OX_USE_STDLIB) && __has_include(<unistd.h>)
#if __has_include(<execinfo.h>)
#include <execinfo.h>
#include <dlfcn.h>
#endif
#if __has_include(<cxxabi.h>)
#include <cxxabi.h>
#endif
#endif
#include "defines.hpp"
#include "string.hpp"
#include "trace.hpp"
#include "vector.hpp"
namespace ox {
#if defined(OX_USE_STDLIB) && __has_include(<unistd.h>)
[[nodiscard]]
static auto symbolicate([[maybe_unused]]void **frames,
[[maybe_unused]]std::size_t frameCnt,
[[maybe_unused]]const char *linePrefix) {
using StrT = BasicString<100>;
Vector<StrT, 30> out;
#if __has_include(<cxxabi.h>) && __has_include(<execinfo.h>)
#ifdef OX_OS_FreeBSD
using FrameCnt_t = unsigned;
#else
using FrameCnt_t = signed;
#endif
const auto mangledSymbols = backtrace_symbols(frames, static_cast<FrameCnt_t>(frameCnt));
for (auto i = 0u; i < frameCnt; ++i) {
Dl_info info;
if (dladdr(frames[i], &info) && info.dli_sname) {
int status = -1;
const auto name = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status);
if (status == 0) {
out.emplace_back(sfmt<StrT>("{}: {}", i, name));
continue;
}
}
out.emplace_back(sfmt<StrT>("{}: {}", i, mangledSymbols[i]));
}
free(mangledSymbols);
#endif // __has_include(<cxxabi.h>)
return out;
}
#endif // defined(OX_USE_STDLIB) && __has_include(<unistd.h>)
void printStackTrace([[maybe_unused]]unsigned shave) noexcept {
#if defined(OX_USE_STDLIB) && __has_include(<unistd.h>) && __has_include(<execinfo.h>)
constexpr auto FrameCnt = 100;
Vector<void*, FrameCnt> frames(FrameCnt);
#ifdef OX_OS_FreeBSD
using FrameCnt_t = unsigned;
#else
using FrameCnt_t = signed;
#endif
frames.resize(static_cast<std::size_t>(backtrace(frames.data(), static_cast<FrameCnt_t>(frames.size()))));
if (frames.size() - shave > 2) {
const auto symbolicatedStacktrace = symbolicate(frames.data() + shave, frames.size() - shave, "\t");
oxErr("Stacktrace:\n");
for (const auto &s : symbolicatedStacktrace) {
oxErrf("\t{}\n", s);
}
}
#endif
}
}

20
deps/ox/src/ox/std/stacktrace.hpp vendored Normal file
View File

@@ -0,0 +1,20 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
namespace ox {
/**
* Prints a stack trace to stderr.
*
* @param shave number of call levels to shave off the top
*/
void printStackTrace(unsigned shave = 1) noexcept;
}

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

@@ -0,0 +1,53 @@
/*
* 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 "array.hpp"
#include "assert.hpp"
#include "bit.hpp"
#include "bounds.hpp"
#include "bstring.hpp"
#include "byteswap.hpp"
#include "concepts.hpp"
#include "cstringview.hpp"
#include "cstrops.hpp"
#include "def.hpp"
#include "defer.hpp"
#include "defines.hpp"
#include "error.hpp"
#include "fmt.hpp"
#include "hardware.hpp"
#include "hashmap.hpp"
#include "heapmgr.hpp"
#include "iterator.hpp"
#include "math.hpp"
#include "memops.hpp"
#include "memory.hpp"
#include "new.hpp"
#include "optional.hpp"
#include "point.hpp"
#include "random.hpp"
#include "realstd.hpp"
#include "serialize.hpp"
#include "size.hpp"
#include "stacktrace.hpp"
#include "stddef.hpp"
#include "string.hpp"
#include "stringliteral.hpp"
#include "stringview.hpp"
#include "strongint.hpp"
#include "strops.hpp"
#include "trace.hpp"
#include "typeinfo.hpp"
#include "types.hpp"
#include "typetraits.hpp"
#include "units.hpp"
#include "uuid.hpp"
#include "vec.hpp"
#include "vector.hpp"

39
deps/ox/src/ox/std/stddef.hpp vendored Normal file
View File

@@ -0,0 +1,39 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "types.hpp"
#if __has_include(<cstddef>)
#include <cstddef>
#else
#define offsetof(type, member) __builtin_offsetof(type, member)
namespace std {
using ptrdiff_t = uintptr_t;
}
#endif
#ifdef _MSC_VER
#define OX_PACKED
#else
#define OX_PACKED __attribute__((packed))
#endif
#ifdef _MSC_VER
#define OX_ALIGN4
#else
#define OX_ALIGN4 __attribute__((aligned(4)))
#endif
#ifdef _MSC_VER
#define OX_ALIGN8
#else
#define OX_ALIGN8 __attribute__((aligned(8)))
#endif

20
deps/ox/src/ox/std/string.cpp vendored Normal file
View File

@@ -0,0 +1,20 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#include "string.hpp"
namespace ox {
template class BasicString<8>;
static_assert(StringView("Write") != String(""));
static_assert(String("Write") != StringView(""));
static_assert(String("Write") == StringView("Write"));
static_assert(String(StringView("Write")) == StringView("Write"));
}

583
deps/ox/src/ox/std/string.hpp vendored Normal file
View File

@@ -0,0 +1,583 @@
/*
* Copyright 2015 - 2023 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(<string>)
#include <string>
#endif
#include "algorithm.hpp"
#include "memops.hpp"
#include "serialize.hpp"
#include "stringview.hpp"
#include "strops.hpp"
#include "vector.hpp"
namespace ox {
template<std::size_t SmallStringSize_v>
class BasicString {
private:
Vector<char, SmallStringSize_v> m_buff;
public:
static constexpr auto SmallStringSize = SmallStringSize_v;
constexpr BasicString() noexcept;
constexpr explicit BasicString(std::size_t cap) noexcept;
constexpr explicit BasicString(const char *str) noexcept;
constexpr explicit BasicString(const char8_t *str) noexcept;
constexpr BasicString(const char *str, std::size_t size) noexcept;
constexpr explicit BasicString(CRStringView str) noexcept;
constexpr explicit BasicString(BasicString const&) noexcept;
constexpr BasicString(BasicString&&) noexcept;
[[nodiscard]]
constexpr auto begin() noexcept {
return m_buff.begin();
}
[[nodiscard]]
constexpr auto end() noexcept {
return m_buff.end();
}
[[nodiscard]]
constexpr auto begin() const noexcept {
return m_buff.begin();
}
[[nodiscard]]
constexpr auto end() const noexcept {
return m_buff.end();
}
[[nodiscard]]
constexpr auto cbegin() const noexcept {
return m_buff.begin();
}
[[nodiscard]]
constexpr auto cend() const noexcept {
return m_buff.end();
}
[[nodiscard]]
constexpr auto rbegin() noexcept {
return m_buff.rbegin();
}
[[nodiscard]]
constexpr auto rend() noexcept {
return m_buff.rend();
}
[[nodiscard]]
constexpr auto rbegin() const noexcept {
return m_buff.rbegin();
}
[[nodiscard]]
constexpr auto rend() const noexcept {
return m_buff.rend();
}
[[nodiscard]]
constexpr auto crbegin() const noexcept {
return m_buff.rbegin();
}
[[nodiscard]]
constexpr auto crend() const noexcept {
return m_buff.rend();
}
constexpr BasicString &operator=(const char *str) noexcept;
constexpr BasicString &operator=(char c) noexcept;
constexpr BasicString &operator=(int i) noexcept;
constexpr BasicString &operator=(int64_t i) noexcept;
constexpr BasicString &operator=(uint64_t i) noexcept;
constexpr BasicString &operator=(const 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+=(char *str) noexcept;
constexpr BasicString &operator+=(char c) noexcept;
constexpr BasicString &operator+=(Integer_c auto i) noexcept;
constexpr BasicString &operator+=(StringView src) noexcept;
constexpr BasicString &operator+=(BasicString const&src) noexcept;
constexpr BasicString operator+(const char *str) const noexcept;
constexpr BasicString operator+(char *str) const noexcept;
constexpr BasicString operator+(char c) const noexcept;
constexpr BasicString operator+(Integer_c auto i) const noexcept;
constexpr BasicString operator+(CRStringView src) const noexcept;
constexpr BasicString operator+(BasicString const&src) const noexcept;
constexpr bool operator==(const char *other) const noexcept;
constexpr bool operator==(OxString_c auto const&other) const noexcept;
constexpr bool operator!=(const char *other) const noexcept;
constexpr bool operator!=(OxString_c auto const&other) const noexcept;
constexpr bool operator<(BasicString const&other) const noexcept;
constexpr bool operator>(BasicString const&other) const noexcept;
constexpr bool operator<=(BasicString const&other) const noexcept;
constexpr bool operator>=(BasicString const&other) const noexcept;
constexpr char operator[](std::size_t i) const noexcept;
constexpr char &operator[](std::size_t i) noexcept;
constexpr Error append(const char *str, std::size_t strLen) noexcept {
auto currentLen = len();
m_buff.resize(m_buff.size() + strLen);
ox_memcpy(&m_buff[currentLen], str, strLen);
// make sure last element is a null terminator
m_buff[currentLen + strLen] = 0;
// this can't fail, but it returns an Error to match BString::append
return OxError(0);
}
[[nodiscard]]
constexpr BasicString substr(std::size_t pos) const noexcept;
[[nodiscard]]
constexpr BasicString substr(std::size_t begin, std::size_t end) const noexcept;
[[nodiscard]]
constexpr const char *data() const noexcept {
return m_buff.data();
}
[[nodiscard]]
constexpr char *data() noexcept {
return m_buff.data();
}
[[nodiscard]]
constexpr const char *c_str() const noexcept {
return static_cast<const char*>(m_buff.data());
}
[[nodiscard]]
inline explicit operator const char*() const {
return c_str();
}
#if __has_include(<string>)
[[nodiscard]]
inline std::string toStdString() const {
return c_str();
}
[[nodiscard]]
inline explicit operator std::string() const {
return c_str();
}
#endif
/**
* Returns the number of characters in this string.
*/
[[nodiscard]]
constexpr std::size_t len() const noexcept;
/**
* Returns the number of bytes used for this string.
*/
[[nodiscard]]
constexpr std::size_t bytes() const noexcept;
private:
constexpr void set(CRStringView str) noexcept;
constexpr void set(const char8_t *str) noexcept;
};
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v>::BasicString() noexcept {
if (!m_buff.empty()) {
m_buff[0] = 0;
} else {
m_buff.push_back(0);
}
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v>::BasicString(std::size_t cap) noexcept: m_buff(cap + 1) {
// GCC complains if you don't do this pretty unnecessary size check
if (!m_buff.empty()) {
m_buff[0] = 0;
}
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v>::BasicString(const char *str) noexcept {
if (!m_buff.empty()) {
m_buff[0] = 0;
} else {
m_buff.push_back(0);
}
set(str);
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v>::BasicString(const char8_t *str) noexcept {
if (!m_buff.empty()) {
m_buff[0] = 0;
} else {
m_buff.push_back(0);
}
set(str);
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v>::BasicString(const char *str, std::size_t size) noexcept {
m_buff.resize(size + 1);
memcpy(m_buff.data(), str, size);
m_buff[size] = 0;
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v>::BasicString(CRStringView str) noexcept {
if (m_buff.empty()) {
m_buff.push_back(0);
} else {
m_buff[0] = 0;
}
set(str);
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v>::BasicString(const BasicString &other) noexcept {
m_buff = other.m_buff;
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v>::BasicString(BasicString &&other) noexcept: m_buff(std::move(other.m_buff)) {
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(const char *str) noexcept {
set(str);
return *this;
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(char c) noexcept {
ox::Array<char, 2> str{c, 0};
set(str.data());
return *this;
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(int i) noexcept {
this->operator=(static_cast<int64_t>(i));
return *this;
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(int64_t i) noexcept {
ox::Array<char, 65> str{};
ox_itoa(i, str.data());
set(str.data());
return *this;
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(uint64_t i) noexcept {
ox::Array<char, 65> str{};
ox_itoa(i, str.data());
set(str.data());
return *this;
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(const BasicString &src) noexcept {
if (this != &src) {
set(src);
}
return *this;
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(BasicString &&src) noexcept {
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;
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(const char *str) noexcept {
std::size_t strLen = ox_strlen(str);
oxIgnoreError(append(str, strLen));
return *this;
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(char *str) noexcept {
return *this += static_cast<const char*>(str);
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(char c) noexcept {
const char str[] = {c, 0};
return this->operator+=(str);
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(Integer_c auto i) noexcept {
char str[65] = {};
ox_itoa(i, str);
return this->operator+=(str);
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(StringView s) noexcept {
std::size_t strLen = s.bytes();
oxIgnoreError(append(s.data(), strLen));
return *this;
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(BasicString const&src) noexcept {
oxIgnoreError(append(src.c_str(), src.len()));
return *this;
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(const char *str) const noexcept {
const std::size_t strLen = ox_strlen(str);
const auto currentLen = len();
BasicString<SmallStringSize_v> cpy(currentLen + strLen);
cpy.m_buff.resize(m_buff.size() + strLen);
memcpy(&cpy.m_buff[0], m_buff.data(), currentLen);
memcpy(&cpy.m_buff[currentLen], str, strLen);
// make sure last element is a null terminator
cpy.m_buff[currentLen + strLen] = 0;
return cpy;
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(char *str) const noexcept {
return *this + static_cast<const char*>(str);
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(char c) const noexcept {
const char str[] = {c, 0};
return *this + str;
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(Integer_c auto i) const noexcept {
char str[65] = {};
ox_itoa(i, str);
return *this + str;
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(CRStringView src) const noexcept {
const std::size_t strLen = src.len();
const auto currentLen = len();
BasicString<SmallStringSize_v> cpy(currentLen + strLen);
cpy.m_buff.resize(m_buff.size() + strLen);
memcpy(&cpy.m_buff[0], m_buff.data(), currentLen);
memcpy(&cpy.m_buff[currentLen], src.data(), strLen + 1);
return cpy;
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(BasicString const&src) const noexcept {
const std::size_t strLen = src.len();
const auto currentLen = len();
BasicString<SmallStringSize_v> cpy(currentLen + strLen);
cpy.m_buff.resize(m_buff.size() + strLen);
memcpy(&cpy.m_buff[0], m_buff.data(), currentLen);
memcpy(&cpy.m_buff[currentLen], src.data(), strLen + 1);
return cpy;
}
template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::operator==(const char *other) const noexcept {
bool retval = true;
for (auto i = 0u; i < m_buff.size() && (m_buff[i] || other[i]); ++i) {
if (m_buff[i] != other[i]) {
retval = false;
break;
}
}
return retval;
}
template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::operator==(OxString_c auto const&other) const noexcept {
return ox::StringView(*this) == ox::StringView(other);
}
template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::operator!=(const char *other) const noexcept {
return !operator==(other);
}
template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::operator!=(OxString_c auto const&other) const noexcept {
return !operator==(other);
}
template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::operator<(BasicString const&other) const noexcept {
return ox_strcmp(c_str(), other.c_str()) < 0;
}
template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::operator>(BasicString const&other) const noexcept {
return ox_strcmp(c_str(), other.c_str()) > 0;
}
template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::operator<=(BasicString const&other) const noexcept {
return ox_strcmp(c_str(), other.c_str()) < 1;
}
template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::operator>=(BasicString const&other) const noexcept {
return ox_strcmp(c_str(), other.c_str()) > -1;
}
template<std::size_t SmallStringSize_v>
constexpr char BasicString<SmallStringSize_v>::operator[](std::size_t i) const noexcept {
return m_buff[i];
}
template<std::size_t SmallStringSize_v>
constexpr char &BasicString<SmallStringSize_v>::operator[](std::size_t i) noexcept {
return m_buff[i];
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::substr(std::size_t pos) const noexcept {
return BasicString(m_buff.data() + pos, m_buff.size() - pos);
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::substr(std::size_t begin, std::size_t end) const noexcept {
const auto src = m_buff.data() + begin;
const auto size = end - begin;
BasicString<SmallStringSize_v> out(size);
const auto buff = out.data();
memcpy(buff, src, size);
buff[size] = 0;
return out;
}
template<std::size_t SmallStringSize_v>
constexpr std::size_t BasicString<SmallStringSize_v>::bytes() const noexcept {
std::size_t i;
for (i = 0; i < m_buff.size() && m_buff[i]; ++i);
return i + 1; // add one for null terminator
}
template<std::size_t SmallStringSize_v>
constexpr std::size_t BasicString<SmallStringSize_v>::len() const noexcept {
std::size_t length = 0;
for (const auto c : m_buff) {
const auto b = static_cast<uint8_t>(c);
if (b) {
// normal ASCII character or start of UTF-8 character
if ((b & 128) == 0 || (b & (256 << 6)) == (256 << 6)) {
++length;
}
} else {
break;
}
}
return length;
}
template<std::size_t SmallStringSize_v>
constexpr void BasicString<SmallStringSize_v>::set(CRStringView str) noexcept {
std::size_t const strBytes = str.bytes();
m_buff.resize(strBytes + 1);
copy_n(str.data(), strBytes, m_buff.data());
*m_buff.back().value = 0;
}
template<std::size_t SmallStringSize_v>
constexpr void BasicString<SmallStringSize_v>::set(const char8_t *str) noexcept {
std::size_t strBytes = ox_strlen(str) + 1;
m_buff.resize(strBytes);
memcpy(m_buff.data(), str, strBytes);
*m_buff.back().value = 0;
}
extern template class BasicString<8>;
using String = BasicString<8>;
using CRString = String const&;
[[nodiscard]]
constexpr ox::String toString(ox::CRStringView sv) noexcept {
return ox::String(sv);
}
template<typename PlatSpec, std::size_t SmallStringSize_v>
[[nodiscard]]
constexpr auto sizeOf(const ox::BasicString<SmallStringSize_v>*) noexcept {
VectorMemMap<PlatSpec> v{.smallVecSize = SmallStringSize_v};
return sizeOf<PlatSpec>(&v);
}
template<typename PlatSpec, std::size_t SmallStringSize_v>
[[nodiscard]]
constexpr auto alignOf(const ox::BasicString<SmallStringSize_v>&) noexcept {
VectorMemMap<PlatSpec> v{.smallVecSize = SmallStringSize_v};
return alignOf<PlatSpec>(&v);
}
}

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

@@ -0,0 +1,51 @@
/*
* 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;
}
[[nodiscard]]
constexpr const char *c_str() const noexcept {
return data();
}
};
}

20
deps/ox/src/ox/std/stringview.cpp vendored Normal file
View File

@@ -0,0 +1,20 @@
/*
* 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/.
*/
#include "stringview.hpp"
static_assert(ox::StringView("Read").bytes() == 4);
static_assert(ox::StringView("Read") == ox::StringView("Read"));
static_assert(ox::StringView("Read") != ox::StringView("Write"));
static_assert(ox::StringView("Write") != ox::StringView("Read"));
static_assert(ox::StringView("Write") != ox::StringView(""));
static_assert(ox::StringView("") != ox::StringView("Read"));
static_assert(ox::StringView("") == ox::StringView(""));
static_assert(ox::StringView("") == "");
static_assert("Read" == ox::StringView("Read"));
static_assert(ox::StringView("Read") == ox::StringView("Read"));

131
deps/ox/src/ox/std/stringview.hpp vendored Normal file
View File

@@ -0,0 +1,131 @@
/*
* Copyright 2015 - 2023 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
#ifdef OX_USE_STDLIB
#include <string_view>
#endif
#include "basestringview.hpp"
#include "cstrops.hpp"
#include "writer.hpp"
namespace ox {
template<std::size_t buffLen>
class BString;
template<std::size_t buffLen>
class BasicString;
class StringView: public detail::BaseStringView {
public:
constexpr StringView() noexcept = default;
constexpr StringView(const StringView &sv) noexcept = default;
#ifdef OX_USE_STDLIB
constexpr StringView(const std::string_view &sv) noexcept: BaseStringView(sv.data(), sv.size()) {}
#endif
constexpr StringView(BaseStringView const&str) noexcept: BaseStringView(str.data(), str.bytes()) {}
template<std::size_t SmallStrSz>
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(const char *str) noexcept: BaseStringView(str) {}
constexpr StringView(const char *str, std::size_t len) noexcept: BaseStringView(str, len) {}
constexpr auto &operator=(StringView const&other) noexcept {
if (&other != this) {
set(other.data(), other.len());
}
return *this;
}
};
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;
}
}
constexpr auto write(Writer_c auto &writer, ox::CRStringView sv) noexcept {
return writer.write(sv.data(), sv.bytes());
}
#ifdef OX_USE_STDLIB
constexpr auto toStdStringView(CRStringView sv) noexcept {
return std::string_view(sv.data(), sv.bytes());
}
#endif
// Maybe StringView. If T is a string type, MaybeType::type/MaybeSV_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>>
struct MaybeSV {
using type = T;
};
template<typename T>
struct MaybeSV<T, true> {
using type = ox::StringView;
};
template<typename T>
using MaybeSV_t = typename MaybeSV<T>::type;
}
constexpr ox::Result<int> ox_atoi(ox::CRStringView str) noexcept {
int total = 0;
int multiplier = 1;
for (auto i = static_cast<int64_t>(str.len()) - 1; i != -1; --i) {
auto s = static_cast<std::size_t>(i);
if (str[s] >= '0' && str[s] <= '9') {
total += (str[s] - '0') * multiplier;
multiplier *= 10;
} else {
return OxError(1);
}
}
return total;
}

308
deps/ox/src/ox/std/strongint.hpp vendored Normal file
View File

@@ -0,0 +1,308 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "types.hpp"
namespace ox {
struct BaseInteger {
constexpr BaseInteger() noexcept = default;
constexpr BaseInteger(const BaseInteger&) noexcept = default;
constexpr BaseInteger &operator=(const BaseInteger&) noexcept = default;
};
/**
* Integer is a strongly typed integer wrapper used to create strongly typed
* integers.
*/
template<typename T, typename Base = BaseInteger>
class Integer: public Base {
private:
T m_i;
public:
constexpr Integer() noexcept = default;
constexpr explicit Integer(T i) noexcept;
constexpr Integer(const Integer<T, Base> &i) noexcept;
constexpr Integer<T, Base> operator=(Integer<T, Base> i) noexcept;
constexpr Integer<T, Base> operator==(Integer<T, Base> i) const noexcept;
constexpr Integer<T, Base> operator!=(Integer<T, Base> i) const noexcept;
constexpr Integer<T, Base> operator<(Integer<T, Base> i) const noexcept;
constexpr Integer<T, Base> operator>(Integer<T, Base> i) const noexcept;
constexpr Integer<T, Base> operator<=(Integer<T, Base> i) const noexcept;
constexpr Integer<T, Base> operator>=(Integer<T, Base> i) const noexcept;
constexpr Integer<T, Base> operator+(Integer<T, Base> i) const noexcept;
constexpr Integer<T, Base> operator+=(Integer<T, Base> i) noexcept;
constexpr Integer<T, Base> operator-(Integer<T, Base> i) const noexcept;
constexpr Integer<T, Base> operator-=(Integer<T, Base> i) noexcept;
constexpr Integer<T, Base> operator*(Integer<T, Base> i) const noexcept;
constexpr Integer<T, Base> operator*=(Integer<T, Base> i) noexcept;
constexpr Integer<T, Base> operator/(Integer<T, Base> i) const noexcept;
constexpr Integer<T, Base> operator/=(Integer<T, Base> i) noexcept;
constexpr Integer<T, Base> operator%(Integer<T, Base> i) const noexcept;
constexpr Integer<T, Base> operator%=(Integer<T, Base> i) noexcept;
constexpr Integer<T, Base> operator>>(int i) const noexcept;
constexpr Integer<T, Base> operator>>=(int i) noexcept;
constexpr Integer<T, Base> operator<<(int i) const noexcept;
constexpr Integer<T, Base> operator<<=(int i) noexcept;
constexpr Integer<T, Base> operator|(Integer<T, Base> i) const noexcept;
constexpr Integer<T, Base> operator|=(Integer<T, Base> i) noexcept;
constexpr Integer<T, Base> operator&(Integer<T, Base> i) const noexcept;
constexpr Integer<T, Base> operator&=(Integer<T, Base> i) noexcept;
constexpr Integer<T, Base> operator^(Integer<T, Base> i) const noexcept;
constexpr Integer<T, Base> operator^=(Integer<T, Base> i) noexcept;
constexpr Integer<T, Base> operator~() const noexcept;
// Prefix increment
constexpr Integer<T, Base> operator++() noexcept;
// Postfix increment
constexpr Integer<T, Base> operator++(int) noexcept;
// Prefix decrement
constexpr Integer<T, Base> operator--() noexcept;
// Postfix decrement
constexpr Integer<T, Base> operator--(int) noexcept;
constexpr explicit operator T() const noexcept;
constexpr operator bool() const noexcept;
};
template<typename T, class Base>
constexpr Integer<T, Base>::Integer(T i) noexcept {
m_i = i;
}
template<typename T, class Base>
constexpr Integer<T, Base>::Integer(const Integer<T, Base> &i) noexcept: Base(i), m_i(i.m_i) {
}
template<typename T, class Base>
constexpr Integer<T, Base> Integer<T, Base>::operator=(Integer<T, Base> i) noexcept {
// needed in case T has nodiscard
constexpr auto ignore = [](Base) {};
ignore(Base::operator=(i));
m_i = i.m_i;
return *this;
}
template<typename T, class Base>
constexpr Integer<T, Base> Integer<T, Base>::operator==(Integer<T, Base> i) const noexcept {
return Integer<T, Base>(m_i == i.m_i);
}
template<typename T, class Base>
constexpr Integer<T, Base> Integer<T, Base>::operator!=(Integer<T, Base> i) const noexcept {
return Integer<T, Base>(m_i != i.m_i);
}
template<typename T, class Base>
constexpr Integer<T, Base> Integer<T, Base>::operator<(Integer<T, Base> i) const noexcept {
return Integer<T, Base>(m_i < i.m_i);
}
template<typename T, class Base>
constexpr Integer<T, Base> Integer<T, Base>::operator>(Integer<T, Base> i) const noexcept {
return Integer<T, Base>(m_i > i.m_i);
}
template<typename T, class Base>
constexpr Integer<T, Base> Integer<T, Base>::operator<=(Integer<T, Base> i) const noexcept {
return Integer<T, Base>(m_i <= i.m_i);
}
template<typename T, class Base>
constexpr Integer<T, Base> Integer<T, Base>::operator>=(Integer<T, Base> i) const noexcept {
return Integer<T, Base>(m_i >= i.m_i);
}
template<typename T, class Base>
constexpr Integer<T, Base> Integer<T, Base>::operator+(Integer<T, Base> i) const noexcept {
return Integer<T, Base>(m_i + i.m_i);
}
template<typename T, class Base>
constexpr Integer<T, Base> Integer<T, Base>::operator+=(Integer<T, Base> i) noexcept {
return Integer<T, Base>(m_i += i.m_i);
}
template<typename T, class Base>
constexpr Integer<T, Base> Integer<T, Base>::operator-(Integer<T, Base> i) const noexcept {
return Integer<T, Base>(m_i - i.m_i);
}
template<typename T, class Base>
constexpr Integer<T, Base> Integer<T, Base>::operator-=(Integer<T, Base> i) noexcept {
return Integer<T, Base>(m_i -= i.m_i);
}
template<typename T, class Base>
constexpr Integer<T, Base> Integer<T, Base>::operator*(Integer<T, Base> i) const noexcept {
return Integer<T, Base>(m_i * i.m_i);
}
template<typename T, class Base>
constexpr Integer<T, Base> Integer<T, Base>::operator*=(Integer<T, Base> i) noexcept {
return Integer<T, Base>(m_i *= i.m_i);
}
template<typename T, class Base>
constexpr Integer<T, Base> Integer<T, Base>::operator/(Integer<T, Base> i) const noexcept {
return Integer<T, Base>(m_i / i.m_i);
}
template<typename T, class Base>
constexpr Integer<T, Base> Integer<T, Base>::operator/=(Integer<T, Base> i) noexcept {
return Integer<T, Base>(m_i /= i.m_i);
}
template<typename T, class Base>
constexpr Integer<T, Base> Integer<T, Base>::operator%(Integer<T, Base> i) const noexcept {
return Integer<T, Base>(m_i % i.m_i);
}
template<typename T, class Base>
constexpr Integer<T, Base> Integer<T, Base>::operator%=(Integer<T, Base> i) noexcept {
return Integer<T, Base>(m_i %= i.m_i);
}
template<typename T, class Base>
constexpr Integer<T, Base> Integer<T, Base>::operator>>(int i) const noexcept {
return Integer<T, Base>(m_i >> i);
}
template<typename T, class Base>
constexpr Integer<T, Base> Integer<T, Base>::operator>>=(int i) noexcept {
return Integer<T, Base>(m_i >>= i);
}
template<typename T, class Base>
constexpr Integer<T, Base> Integer<T, Base>::operator<<(int i) const noexcept {
return Integer<T, Base>(m_i << i);
}
template<typename T, class Base>
constexpr Integer<T, Base> Integer<T, Base>::operator<<=(int i) noexcept {
return Integer<T, Base>(m_i <<= i);
}
template<typename T, class Base>
constexpr Integer<T, Base> Integer<T, Base>::operator|(Integer<T, Base> i) const noexcept {
return Integer<T, Base>(m_i | i.m_i);
}
template<typename T, class Base>
constexpr Integer<T, Base> Integer<T, Base>::operator|=(Integer<T, Base> i) noexcept {
return Integer<T, Base>(m_i |= i.m_i);
}
template<typename T, class Base>
constexpr Integer<T, Base> Integer<T, Base>::operator&(Integer<T, Base> i) const noexcept {
return Integer<T, Base>(m_i & i.m_i);
}
template<typename T, class Base>
constexpr Integer<T, Base> Integer<T, Base>::operator&=(Integer<T, Base> i) noexcept {
return Integer<T, Base>(m_i &= i.m_i);
}
template<typename T, class Base>
constexpr Integer<T, Base> Integer<T, Base>::operator^(Integer<T, Base> i) const noexcept {
return Integer<T, Base>(m_i ^ i.m_i);
}
template<typename T, class Base>
constexpr Integer<T, Base> Integer<T, Base>::operator^=(Integer<T, Base> i) noexcept {
return Integer<T, Base>(m_i ^= i.m_i);
}
template<typename T, class Base>
constexpr inline Integer<T, Base> Integer<T, Base>::operator~() const noexcept {
return Integer<T, Base>(~m_i);
}
// Prefix increment
template<typename T, class Base>
constexpr inline Integer<T, Base> Integer<T, Base>::operator++() noexcept {
return Integer<T, Base>(++m_i);
}
// Postfix increment
template<typename T, class Base>
constexpr inline Integer<T, Base> Integer<T, Base>::operator++(int) noexcept {
return Integer<T, Base>(m_i++);
}
// Prefix decrement
template<typename T, class Base>
constexpr inline Integer<T, Base> Integer<T, Base>::operator--() noexcept {
return Integer<T, Base>(--m_i);
}
// Postfix decrement
template<typename T, class Base>
constexpr inline Integer<T, Base> Integer<T, Base>::operator--(int) noexcept {
return Integer<T, Base>(m_i--);
}
template<typename T, class Base>
constexpr Integer<T, Base>::operator T() const noexcept {
return m_i;
}
template<typename T, class Base>
constexpr Integer<T, Base>::operator bool() const noexcept {
return m_i;
}
using Int8 = Integer<int8_t>;
using Int16 = Integer<int16_t>;
using Int32 = Integer<int32_t>;
using Int64 = Integer<int64_t>;
using Uint8 = Integer<uint8_t>;
using Uint16 = Integer<uint16_t>;
using Uint32 = Integer<uint32_t>;
using Uint64 = Integer<uint64_t>;
}

41
deps/ox/src/ox/std/strops.cpp vendored Normal file
View File

@@ -0,0 +1,41 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#include "strops.hpp"
static_assert(ox_strcmp("asdf", "hijk") < 0, "asdf < hijk");
static_assert(ox_strcmp("hijk", "asdf") > 0, "hijk > asdf");
static_assert(ox_strcmp("resize", "read") > 0, "resize > read");
static_assert(ox_strcmp("read", "resize") < 0, "read < resize");
static_assert(ox_strcmp("resize", "resize") == 0, "resize == resize");
static_assert(ox_strcmp("", "") == 0, "\"\" == \"\"");
static_assert([] {
auto testStr = "asdf";
return ox_strchr(testStr, 0, 4) == &testStr[4];
}(), "ox_strchr 0");
static_assert([] {
int retval = 0;
auto testStr = "aaaa";
// test the const and non-const versions of ox_lastIndexOf
retval |= !(ox_lastIndexOf(const_cast<char*>(testStr), 'a', ox_strlen(testStr)) == 3);
retval |= !(ox_lastIndexOf(testStr, 'a', ox_strlen(testStr)) == 3);
return retval == 0;
}(), "ox_lastIndexOf aaaa a");
#ifndef OX_USE_STDLIB
extern "C"
std::size_t strlen(const char *str) {
std::size_t len = 0;
for (; str[len]; len++);
return len;
}
#endif

146
deps/ox/src/ox/std/strops.hpp vendored Normal file
View File

@@ -0,0 +1,146 @@
/*
* Copyright 2015 - 2023 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 "cstrops.hpp"
#include "error.hpp"
#include "math.hpp"
#include "stringview.hpp"
#include "types.hpp"
#include "vector.hpp"
#include "writer.hpp"
namespace ox {
template<OxString_c Str>
[[nodiscard]]
constexpr ox::StringView 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 ox::StringView 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>
constexpr ox::Error itoa(Integer v, ox::Writer_c auto &writer) noexcept {
if (v) {
ox::ResizedInt_t<Integer, 64> mod = 1000000000000000000;
ox::ResizedInt_t<Integer, 64> val = v;
constexpr auto base = 10;
auto it = 0;
if (val < 0) {
oxReturnError(writer.put('-'));
++it;
}
while (mod) {
auto digit = val / mod;
val %= mod;
mod /= base;
if (it || digit) {
ox::ResizedInt_t<Integer, 64> start = '0';
if (digit >= 10) {
start = 'a';
digit -= 10;
}
oxReturnError(writer.put(static_cast<char>(start + digit)));
++it;
}
}
} else {
// 0 is a special case
oxReturnError(writer.put('0'));
}
return {};
}
[[nodiscard]]
constexpr bool beginsWith(CRStringView base, CRStringView beginning) noexcept {
const auto beginningLen = ox::min(beginning.len(), base.len());
return base.len() >= beginning.len() && ox_strncmp(base.data(), beginning, beginningLen) == 0;
}
[[nodiscard]]
constexpr bool endsWith(CRStringView base, CRStringView ending) noexcept {
const auto endingLen = ending.len();
return base.len() >= endingLen && ox_strcmp(base.data() + (base.len() - endingLen), ending) == 0;
}
constexpr std::size_t find(CRStringView str, char search) noexcept {
std::size_t i = 0;
for (; i < str.len(); ++i) {
if (str[i] == search) {
break;
}
}
return i;
}
constexpr std::size_t find(CRStringView str, CRStringView search) noexcept {
std::size_t i = 0;
for (; i < str.len(); ++i) {
if (beginsWith(substr(str, i), search)) {
break;
}
}
return i;
}
template<std::size_t smallSz = 0>
constexpr ox::Vector<ox::StringView, smallSz> split(CRStringView str, char del) noexcept {
ox::Vector<ox::StringView, smallSz> out;
constexpr auto nextSeg = [](CRStringView current, char del) {
return substr(current, find(current, del) + 1);
};
for (auto current = str; current.len(); current = nextSeg(current, del)) {
const auto next = find(current, del);
if (const auto s = substr(current, 0, next); s.len()) {
out.emplace_back(s);
}
current = substr(current, next);
}
return out;
}
template<std::size_t smallSz = 0>
constexpr ox::Vector<ox::StringView, smallSz> split(CRStringView str, CRStringView del) noexcept {
ox::Vector<ox::StringView, smallSz> out;
constexpr auto nextSeg = [](CRStringView current, CRStringView del) {
return substr(current, find(current, del) + del.len());
};
for (auto current = str; current.len(); current = nextSeg(current, del)) {
const auto next = find(current, del);
if (const auto s = substr(current, 0, next); s.len()) {
out.emplace_back(s);
}
current = substr(current, next);
}
return out;
}
[[nodiscard]]
constexpr ox::Result<std::size_t> lastIndexOf(ox::CRStringView str, int character) noexcept {
ox::Result<std::size_t> retval = OxError(1, "Character not found");
for (auto i = static_cast<int>(str.bytes() - 1); i >= 0; --i) {
if (str[static_cast<std::size_t>(i)] == character) {
retval = static_cast<std::size_t>(i);
}
}
return retval;
}
}

25
deps/ox/src/ox/std/substitutes.cpp vendored Normal file
View File

@@ -0,0 +1,25 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#ifndef OX_USE_STDLIB
// weak link panic to ensure that it exists, but allow it to be overriden by
// platform specific code
void __attribute__((weak)) panic(const char*) {
while (1);
}
extern "C" {
void __cxa_pure_virtual() {
panic("Missing virtual function");
}
}
#endif

26
deps/ox/src/ox/std/test/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,26 @@
cmake_minimum_required(VERSION 3.10)
add_executable(
StdTest
tests.cpp
)
target_link_libraries(StdTest OxStd)
add_test("[ox/std] ox_memcmp ABCDEFG != HIJKLMN" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "ABCDEFG != HIJKLMN")
add_test("[ox/std] ox_memcmp HIJKLMN != ABCDEFG" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "HIJKLMN != 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] itoa" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "itoa")
add_test("[ox/std] BString" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "BString")
add_test("[ox/std] String" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "String")
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] HeapMgr" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest malloc)
add_test("[ox/std] Serialize-Int" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "Serialize-Int")
add_test("[ox/std] BufferWriter" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "BufferWriter")
add_test("[ox/std] StringSplit" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "StringSplit")
add_test("[ox/std] FromHex" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "FromHex")
add_test("[ox/std] ToHex" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "ToHex")
add_test("[ox/std] UUID" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "UUID")
add_test("[ox/std] UUID::generate" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "UUID::generate")

327
deps/ox/src/ox/std/test/tests.cpp vendored Normal file
View File

@@ -0,0 +1,327 @@
/*
* Copyright 2015 - 2023 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 http://mozilla.org/MPL/2.0/.
*/
#undef NDEBUG
#include <map>
#include <ox/std/uuid.hpp>
#include <ox/std/std.hpp>
static std::map<ox::StringView, ox::Error(*)()> tests = {
{
"malloc",
[] {
ox::Buffer buff(ox::units::MB);
ox::heapmgr::initHeap(&buff[0], &buff[buff.size()-1]);
auto a1 = 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(a2 >= buff.front().unwrap() && a2 < buff.back().unwrap() && a2 > a1 + 5, "malloc is broken");
return OxError(0);
}
},
{
"itoa",
[]() {
ox::Array<char, 10> buff;
ox::CharBuffWriter bw(buff);
oxAssert(ox::itoa(5, bw), "ox::itoa returned Error");
oxExpect(ox::StringView(buff.data()), ox::StringView("5"));
oxReturnError(bw.seekp(0));
oxAssert(ox::itoa(50, bw), "ox::itoa returned Error");
oxExpect(ox::StringView(buff.data()), ox::StringView("50"));
oxReturnError(bw.seekp(0));
oxAssert(ox::itoa(500, bw), "ox::itoa returned Error");
oxExpect(ox::StringView(buff.data()), ox::StringView("500"));
return ox::Error{};
}
},
{
"ABCDEFG != HIJKLMN",
[]() {
return OxError(ox_memcmp("ABCDEFG", "HIJKLMN", 7) >= 0);
}
},
{
"HIJKLMN != ABCDEFG",
[]() {
return OxError(ox_memcmp("HIJKLMN", "ABCDEFG", 7) <= 0);
}
},
{
"ABCDEFG == ABCDEFG",
[]() {
return OxError(ox_memcmp("ABCDEFG", "ABCDEFG", 7) != 0);
}
},
{
"ABCDEFGHI == ABCDEFG",
[]() {
return OxError(ox_memcmp("ABCDEFGHI", "ABCDEFG", 7) != 0);
}
},
{
"BString",
[]() {
ox::BString<5> s;
s += "A";
s += "B";
s += 9;
s += "C";
oxAssert(s == "AB9C", "BString append broken");
s = "asdf";
oxAssert(s == "asdf", "String assign broken");
oxAssert(s != "aoeu", "String assign broken");
oxAssert(s.len() == 4, "String assign broken");
return OxError(0);
}
},
{
"String",
[]() {
ox::String s;
s += "A";
s += "B";
s += 9;
s += "C";
oxAssert(s == "AB9C", "String append broken");
s = "asdf";
oxAssert(s == "asdf", "String assign broken");
s += "aoeu";
oxAssert(s == "asdfaoeu", "String append broken");
const ox::StringView str = "asdf";
oxAssert(beginsWith(str, "as"), "String beginsWith is broken");
oxAssert(beginsWith(str, "asd"), "String beginsWith is broken");
oxAssert(beginsWith(str, "asdf"), "String beginsWith is broken");
oxAssert(!beginsWith(str, "aa"), "String beginsWith is broken");
oxAssert(!beginsWith(str, "aaaaaaa"), "String beginsWith is broken");
oxAssert(!beginsWith(str, "li"), "String beginsWith is broken");
oxAssert(!beginsWith(str, "afoif"), "String beginsWith is broken");
oxAssert(endsWith(str, "df"), "String endsWith is broken");
oxAssert(!endsWith(str, "awefawe"), "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);
}
},
{
"Vector",
[] {
ox::Vector<int> v;
oxAssert(v.size() == 0, "Initial Vector size not 0");
oxAssert(v.empty(), "Vector::empty() is broken");
auto insertTest = [&v](int val, [[maybe_unused]] std::size_t size) {
v.push_back(val);
oxReturnError(OxError(v.size() != size, "Vector size incorrect"));
oxReturnError(OxError(v[v.size() - 1] != val, "Vector value wrong"));
return OxError(0);
};
oxAssert(insertTest(42, 1), "Vector insertion failed");
oxAssert(insertTest(100, 2), "Vector insertion failed");
oxAssert(insertTest(102, 3), "Vector insertion failed");
return OxError(0);
}
},
{
"HashMap",
[] {
ox::HashMap<const char*, int> si;
si["asdf"] = 42;
si["aoeu"] = 100;
oxAssert(si["asdf"] == 42, "asdf != 42");
oxAssert(si["aoeu"] == 100, "aoeu != 100");
ox::HashMap<int, int> ii;
ii[4] = 42;
ii[5] = 100;
oxAssert(ii[4] == 42, "4 != 42");
oxAssert(ii[5] == 100, "5 != 100");
return OxError(0);
}
},
{
"Serialize-Int",
[] {
using BA = ox::Array<char, 4>;
const auto actual = ox::serialize<uint32_t>(256).unwrap();
oxOutf("[{}, {}, {}, {}]", static_cast<int>(actual[0]), static_cast<int>(actual[1]), static_cast<int>(actual[2]), static_cast<int>(actual[3]));
oxExpect(ox::serialize<int32_t>(4).unwrap(), BA({4, 0, 0, 0}));
oxExpect(ox::serialize<int32_t>(256).unwrap(), BA({0, 1, 0, 0}));
oxExpect(ox::serialize<int32_t>(257).unwrap(), BA({1, 1, 0, 0}));
oxExpect(ox::serialize<uint32_t>(4).unwrap(), BA({4, 0, 0, 0}));
oxExpect(ox::serialize<uint32_t>(256).unwrap(), BA({0, 1, 0, 0}));
oxExpect(ox::serialize<uint32_t>(257).unwrap(), BA({1, 1, 0, 0}));
constexpr auto neg1 = static_cast<char>(-1); // ARM64 Linux assumes -1 literals are ints...
oxExpect(ox::serialize<uint32_t>(0xffff'ffff).unwrap(), BA({neg1, neg1, neg1, neg1}));
return OxError(0);
}
},
{
"BufferWriter",
[] {
ox::Buffer b;
ox::BufferWriter w(&b);
oxAssert(w.write("asdf", 4), "write failed");
oxExpect(b.size(), 4u);
oxAssert(w.write("aoeu", 4), "write failed");
oxExpect(b.size(), 8u);
oxExpect(ox::StringView(b.data(), b.size()), "asdfaoeu");
ox::StringView constexpr qwerty = "qwerty";
oxAssert(w.write(qwerty.data(), qwerty.bytes()), "write failed");
oxExpect(b.size(), 14u);
oxExpect(ox::StringView(b.data(), b.size()), "asdfaoeuqwerty");
return OxError(0);
}
},
{
"FromHex",
[] {
oxExpect(ox::detail::fromHex("01").unwrap(), 0x01);
oxExpect(ox::detail::fromHex("02").unwrap(), 0x02);
oxExpect(ox::detail::fromHex("03").unwrap(), 0x03);
oxExpect(ox::detail::fromHex("04").unwrap(), 0x04);
oxExpect(ox::detail::fromHex("05").unwrap(), 0x05);
oxExpect(ox::detail::fromHex("06").unwrap(), 0x06);
oxExpect(ox::detail::fromHex("07").unwrap(), 0x07);
oxExpect(ox::detail::fromHex("08").unwrap(), 0x08);
oxExpect(ox::detail::fromHex("0d").unwrap(), 0x0d);
oxExpect(ox::detail::fromHex("0e").unwrap(), 0x0e);
oxExpect(ox::detail::fromHex("0f").unwrap(), 0x0f);
oxExpect(ox::detail::fromHex("0F").unwrap(), 0x0f);
oxExpect(ox::detail::fromHex("fF").unwrap(), 0xff);
oxExpect(ox::detail::fromHex("ff").unwrap(), 0xff);
oxExpect(ox::detail::fromHex("a0").unwrap(), 0xa0);
oxExpect(ox::detail::fromHex("93").unwrap(), 0x93);
oxExpect(ox::detail::fromHex("40").unwrap(), 0x40);
return OxError(0);
}
},
{
"ToHex",
[] {
oxExpect(ox::detail::toHex(0x01), "01");
oxExpect(ox::detail::toHex(0x02), "02");
oxExpect(ox::detail::toHex(0x03), "03");
oxExpect(ox::detail::toHex(0x04), "04");
oxExpect(ox::detail::toHex(0x05), "05");
oxExpect(ox::detail::toHex(0x06), "06");
oxExpect(ox::detail::toHex(0x07), "07");
oxExpect(ox::detail::toHex(0x08), "08");
oxExpect(ox::detail::toHex(0x0d), "0d");
oxExpect(ox::detail::toHex(0x0e), "0e");
oxExpect(ox::detail::toHex(0x0f), "0f");
oxExpect(ox::detail::toHex(0x93), "93");
oxExpect(ox::detail::toHex(0x40), "40");
oxExpect(ox::detail::toHex(0xf0), "f0");
return OxError(0);
}
},
{
"UUID",
[] {
constexpr ox::StringView uuidStr = "8d814442-f46e-4cc3-8edc-ca3c01cc86db";
oxRequire(uuid, ox::UUID::fromString(uuidStr));
oxExpect(uuid.toString(), uuidStr);
oxExpect(ox::UUID{}.isNull(), true);
oxExpect(ox::UUID::fromString(uuidStr).value.isNull(), false);
return OxError(0);
}
},
{
"UUID::generate",
[] {
ox::UUID::seedGenerator({1234, 4321});
oxExpect(ox::UUID::generate().unwrap().toString(), "5c3f4b5e-ccbf-4727-7f03-3053dedc8827");
oxExpect(ox::UUID::generate().unwrap().toString(), "90d0274a-2774-4afa-88e5-0c1d60ba3abf");
oxExpect(ox::UUID::generate().unwrap().toString(), "7df77910-841c-48ba-ea2e-44521ac47c2e");
return OxError(0);
}
},
{
"StringSplit",
[] {
ox::StringView sv = "ab.cd";
auto list = ox::split(sv, ".");
oxExpect(list.size(), 2u);
oxExpect(list[0], "ab");
oxExpect(list[1], "cd");
sv = "ab.cd.fg";
list = ox::split(sv, ".");
oxExpect(list.size(), 3u);
oxExpect(list[0], "ab");
oxExpect(list[1], "cd");
oxExpect(list[2], "fg");
sv = "ab.cd.";
list = ox::split(sv, ".");
oxExpect(list.size(), 2u);
oxExpect(list[0], "ab");
oxExpect(list[1], "cd");
sv = ".ab.cd.";
list = ox::split(sv, ".");
oxExpect(list.size(), 2u);
oxExpect(list[0], "ab");
oxExpect(list[1], "cd");
sv = ".";
list = ox::split(sv, ".");
oxExpect(list.size(), 0u);
sv = ".";
list = ox::split(sv, ".");
oxExpect(list.size(), 0u);
sv = "";
list = ox::split(sv, ".");
oxExpect(list.size(), 0u);
// split by single char
sv = "ab.cd";
list = ox::split(sv, '.');
oxExpect(list.size(), 2u);
oxExpect(list[0], "ab");
oxExpect(list[1], "cd");
sv = "ab.cd.fg";
list = ox::split(sv, '.');
oxExpect(list.size(), 3u);
oxExpect(list[0], "ab");
oxExpect(list[1], "cd");
oxExpect(list[2], "fg");
sv = "ab.cd.";
list = ox::split(sv, '.');
oxExpect(list.size(), 2u);
oxExpect(list[0], "ab");
oxExpect(list[1], "cd");
sv = ".ab.cd.";
list = ox::split(sv, '.');
oxExpect(list.size(), 2u);
oxExpect(list[0], "ab");
oxExpect(list[1], "cd");
sv = ".";
list = ox::split(sv, '.');
oxExpect(list.size(), 0u);
sv = ".";
list = ox::split(sv, '.');
oxExpect(list.size(), 0u);
sv = "";
list = ox::split(sv, '.');
oxExpect(list.size(), 0u);
return OxError(0);
}
},
};
int main(int argc, const char **args) {
if (argc < 2) {
oxError("Must specify test to run");
}
auto const testName = args[1];
auto const func = tests.find(testName);
if (func != tests.end()) {
oxAssert(func->second(), "Test returned Error");
return 0;
}
return -1;
}

43
deps/ox/src/ox/std/trace.cpp vendored Normal file
View File

@@ -0,0 +1,43 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#include "trace.hpp"
namespace ox::trace {
void init() {
oxTraceInitHook();
}
void init(Logger *logger) {
oxTraceInitHook();
setLogger(logger);
}
class NullLogger: public Logger {
public:
ox::Error send(const TraceMsg&) noexcept final {
return {};
}
ox::Error sendInit(const InitTraceMsg&) noexcept final {
return {};
}
};
static NullLogger defaultLogger;
static Logger *logger = &defaultLogger;
void setLogger(Logger *logger) noexcept {
trace::logger = logger;
}
void send(const TraceMsg &msg) noexcept {
oxIgnoreError(logger->send(msg));
}
}

290
deps/ox/src/ox/std/trace.hpp vendored Normal file
View File

@@ -0,0 +1,290 @@
/*
* Copyright 2015 - 2023 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
#ifdef OX_USE_STDLIB
#include <array>
#endif
#include "bstring.hpp"
#include "def.hpp"
#include "fmt.hpp"
#include "hashmap.hpp"
#include "string.hpp"
#include "typetraits.hpp"
#include "units.hpp"
extern "C" {
void oxTraceInitHook();
void oxTraceHook(const char *file, int line, const char *ch, const char *msg);
}
namespace ox::trace {
enum class MsgId: char {
Init = 2,
TraceEvent = 1,
Json = '{',
};
struct TraceMsgRcv {
static constexpr auto TypeName = "net.drinkingtea.ox.trace.TraceMsg";
static constexpr auto TypeVersion = 1;
BasicString<50> file{""};
int line = 0;
uint64_t time = 0;
BasicString<50> ch{""};
BasicString<100> msg;
};
template<typename T>
constexpr Error model(T *io, ox::CommonPtrWith<TraceMsgRcv> auto *obj) noexcept {
oxReturnError(io->template setTypeInfo<TraceMsgRcv>());
oxReturnError(io->field("file", &obj->file));
oxReturnError(io->field("line", &obj->line));
oxReturnError(io->field("time", &obj->time));
oxReturnError(io->field("ch", &obj->ch));
oxReturnError(io->field("msg", &obj->msg));
return {};
}
struct TraceMsg {
static constexpr auto TypeName = "net.drinkingtea.ox.trace.TraceMsg";
static constexpr auto TypeVersion = 1;
const char *file = "";
int line = 0;
uint64_t time = 0;
const char *ch = "";
BasicString<100> msg;
};
template<typename T>
constexpr Error model(T *io, ox::CommonPtrWith<TraceMsg> auto *obj) noexcept {
oxReturnError(io->template setTypeInfo<TraceMsg>());
oxReturnError(io->fieldCString("file", &obj->file));
oxReturnError(io->field("line", &obj->line));
oxReturnError(io->field("time", &obj->time));
oxReturnError(io->fieldCString("ch", &obj->ch));
oxReturnError(io->field("msg", &obj->msg));
return {};
}
struct InitTraceMsgRcv {
static constexpr auto TypeName = "net.drinkingtea.ox.trace.InitTraceMsg";
static constexpr auto TypeVersion = 1;
ox::String appName;
};
template<typename T>
constexpr Error model(T *io, ox::CommonPtrWith<InitTraceMsgRcv> auto *obj) noexcept {
oxReturnError(io->template setTypeInfo<InitTraceMsgRcv>());
oxReturnError(io->field("appName", &obj->appName));
return {};
}
struct InitTraceMsg {
static constexpr auto TypeName = "net.drinkingtea.ox.trace.InitTraceMsg";
static constexpr auto TypeVersion = 2;
ox::BasicString<128> appName;
};
template<typename T>
constexpr Error model(T *io, ox::CommonPtrWith<InitTraceMsg> auto *obj) noexcept {
oxReturnError(io->template setTypeInfo<InitTraceMsg>());
oxReturnError(io->field("appName", &obj->appName));
return {};
}
class Logger {
public:
constexpr virtual ~Logger() noexcept = default;
virtual ox::Error send(const TraceMsg&) noexcept = 0;
virtual ox::Error sendInit(const InitTraceMsg&) noexcept = 0;
};
/**
* @param logger pointer to the new logger, does NOT take ownership
*/
void setLogger(Logger *logger) noexcept;
void send(const TraceMsg &msg) noexcept;
class OutStream {
protected:
const char *m_delimiter = " ";
TraceMsg m_msg;
public:
constexpr OutStream(const char *file, int line, const char *ch, const StringView &msg) noexcept {
m_msg.file = file;
m_msg.line = line;
m_msg.ch = ch;
m_msg.msg = BasicString<100>(msg);
}
constexpr OutStream(const char *file, int line, const char *ch, const char *msg = "") noexcept {
m_msg.file = file;
m_msg.line = line;
m_msg.ch = ch;
m_msg.msg = msg;
}
template<std::size_t fmtSegmentCnt, typename ...Args>
constexpr OutStream(const char *file, int line, const char *ch, detail::Fmt<fmtSegmentCnt> fmtSegments, Args const&...elements) noexcept {
static_assert(sizeof...(elements) == fmtSegmentCnt - 1, "Wrong number of trace arguments for format.");
m_msg.file = file;
m_msg.line = line;
m_msg.ch = ch;
const auto &firstSegment = fmtSegments.segments[0];
oxIgnoreError(m_msg.msg.append(firstSegment.str, firstSegment.length));
//const detail::FmtArg elements[sizeof...(args)] = {args...};
for (size_t i = 0; auto const&e : std::initializer_list<detail::FmtArg>{elements...}) {
m_msg.msg += e.out;
const auto &s = fmtSegments.segments[i + 1];
oxIgnoreError(m_msg.msg.append(s.str, s.length));
++i;
}
}
inline ~OutStream() noexcept {
oxTraceHook(m_msg.file, m_msg.line, m_msg.ch, m_msg.msg.c_str());
send(m_msg);
}
constexpr OutStream &operator<<(Integer_c auto v) noexcept;
constexpr OutStream &operator<<(char v) noexcept {
if (m_msg.msg.len()) {
m_msg.msg += m_delimiter;
}
m_msg.msg += v;
return *this;
}
constexpr OutStream &operator<<(const char *v) noexcept {
if (m_msg.msg.len()) {
m_msg.msg += m_delimiter;
}
m_msg.msg += v;
return *this;
}
template<std::size_t sz>
constexpr OutStream &operator<<(const BString<sz> &v) noexcept {
return operator<<(v.c_str());
}
template<std::size_t sz>
constexpr OutStream &operator<<(const BasicString<sz> &v) noexcept {
return operator<<(v.c_str());
}
constexpr OutStream &operator<<(const Error &err) noexcept {
return appendSignedInt(static_cast<int64_t>(err));
}
/**
* del sets the delimiter between log segments.
*/
constexpr OutStream &del(const char *delimiter) noexcept {
m_delimiter = delimiter;
return *this;
}
private:
constexpr OutStream &appendSignedInt(int64_t v) noexcept {
if (m_msg.msg.len()) {
m_msg.msg += m_delimiter;
}
m_msg.msg += static_cast<int64_t>(v);
return *this;
}
constexpr OutStream &appendUnsignedInt(uint64_t v) noexcept {
if (m_msg.msg.len()) {
m_msg.msg += m_delimiter;
}
m_msg.msg += static_cast<int64_t>(v);
return *this;
}
};
constexpr OutStream &OutStream::operator<<(Integer_c auto v) noexcept {
if (m_msg.msg.len()) {
m_msg.msg += m_delimiter;
}
m_msg.msg += v;
return *this;
}
class NullStream {
public:
constexpr NullStream(const char*, int, const char*, const StringView&) noexcept {
}
constexpr NullStream(const char*, int, const char*, const char* = "") noexcept {
}
template<std::size_t fmtSegmentCnt, typename ...Args>
constexpr NullStream(const char*, int, const char*, detail::Fmt<fmtSegmentCnt>, Args const&...elements) noexcept {
static_assert(sizeof...(elements) == fmtSegmentCnt - 1, "Wrong number of trace arguments for format.");
}
template<typename T>
constexpr const NullStream &operator<<(const T&) const noexcept {
return *this;
}
constexpr const NullStream &del(const char*) const noexcept {
return *this;
}
};
#if defined(DEBUG)
using TraceStream = OutStream;
#else
using TraceStream = NullStream;
#endif
inline void logError(const char *file, int line, const char *fmt, const Error &err) noexcept {
if (err) {
TraceStream trc(file, line, "ox::error");
if (err.file != nullptr) {
trc << "Error: (" << err.file << ":" << err.line << "):";
} else {
trc << "Error:";
}
trc << ox::sfmt<BasicString<100>>(fmt, static_cast<uint64_t>(err));
}
}
inline void logError(const char *file, int line, const Error &err) noexcept {
if (err) {
TraceStream trc(file, line, "ox::error");
trc << "Error:" << err;
if (err.file != nullptr) {
trc << "(" << err.file << ":" << err.line << ")";
}
}
}
void init();
void init(Logger *logger);
}

102
deps/ox/src/ox/std/tracehook.cpp vendored Normal file
View File

@@ -0,0 +1,102 @@
/*
* Copyright 2015 - 2023 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 http://mozilla.org/MPL/2.0/.
*/
#if defined(OX_USE_STDLIB)
#include <iomanip>
#include <iostream>
static const auto OxPrintTrace = std::getenv("OXTRACE") != nullptr;
#endif
#include "strops.hpp"
#include "math.hpp"
#include "stringview.hpp"
#include "types.hpp"
#define REG_MGBA_DEBUG_ENABLE *reinterpret_cast<volatile uint16_t*>(0x4FFF780)
#define REG_MGBA_DEBUG_FLAGS *reinterpret_cast<volatile uint16_t*>(0x4FFF700)
#define REG_MGBA_DEBUG_STRING (reinterpret_cast<char*>(0x4FFF600))
inline void nullLog(ox::CRStringView) {}
inline void (*infoLog)(ox::CRStringView) = nullLog;
inline void (*debugLog)(ox::CRStringView) = nullLog;
inline void (*errorLog)(ox::CRStringView) = nullLog;
namespace mgba {
enum LogChan {
Fatal = 0,
Error = 1,
Warn = 2,
Info = 3,
Debug = 4,
};
template<LogChan chan>
static void log(ox::CRStringView str) {
const auto sz = ox::min<std::size_t>(0x100, str.bytes());
ox_strncpy(REG_MGBA_DEBUG_STRING, str.data(), sz);
REG_MGBA_DEBUG_FLAGS = chan | 0x100;
}
void initConsole() {
REG_MGBA_DEBUG_ENABLE = 0xC0DE;
if (REG_MGBA_DEBUG_ENABLE == 0x1DEA) {
infoLog = log<LogChan::Info>;
debugLog = log<LogChan::Info>; // use INFO because mGBA disables DEBUG on start
errorLog = log<LogChan::Info>;
}
}
}
extern "C" {
void oxTraceInitHook() {
}
void oxTraceHook([[maybe_unused]] const char *file, [[maybe_unused]] int line,
[[maybe_unused]] const char *ch, [[maybe_unused]] const char *msg) {
#if defined(OX_USE_STDLIB)
if (OxPrintTrace) {
std::cout << std::setw(53) << std::left << ch << "| ";
std::cout << std::setw(65) << std::left << msg << '|';
std::cout << " " << file << ':' << line << "\n";
} else if (ox_strcmp(ch, "debug") == 0 || ox_strcmp(ch, "info") == 0) {
printf("%s\n", msg);
fflush(stdout);
} else if (ox_strcmp(ch, "stdout") == 0) {
printf("%s", msg);
fflush(stdout);
} else if (ox_strcmp(ch, "stderr") == 0) {
printf("%s", msg);
fflush(stdout);
} else if (ox_strcmp(ch, "error") == 0) {
//std::cerr << "\033[31;1;1mERROR:\033[0m (" << file << ':' << line << "): " << msg << '\n';
fprintf(stderr, "\033[31;1;1mERROR:\033[0m (%s:%d): %s\n", file, line, msg);
fflush(stderr);
}
#else
if (ox_strcmp(ch, "info") == 0) {
infoLog(msg);
} else if (ox_strcmp(ch, "debug") == 0) {
debugLog(msg);
} else if (ox_strcmp(ch, "stdout") == 0) {
infoLog(msg);
} else if (ox_strcmp(ch, "stderr") == 0) {
errorLog(msg);
} else if (ox_strcmp(ch, "error") == 0) {
errorLog(msg);
}
#endif
}
}

34
deps/ox/src/ox/std/typeinfo.hpp vendored Normal file
View File

@@ -0,0 +1,34 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
#if __has_include(<typeinfo>)
#include <typeinfo>
#else
namespace std {
// this is not at all guaranteed to work, and does not even fully comply with
// what little the standard does define
struct type_info {
private:
const char *m_name = "";
protected:
explicit type_info(const char *name): m_name(name) {
}
const char *name() {
return m_name;
}
};
}
#endif

177
deps/ox/src/ox/std/types.hpp vendored Normal file
View File

@@ -0,0 +1,177 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
namespace std {
using nullptr_t = decltype(nullptr);
using size_t = decltype(alignof(int));
}
using size_t = decltype(alignof(int));
#if __has_include(<cstdint>)
#include <cstdint>
#else
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef short int16_t;
typedef unsigned short uint16_t;
typedef int int32_t;
typedef unsigned int uint32_t;
typedef unsigned uint_t;
#if defined(__arm__) || defined(__ppc__)
typedef long long int64_t;
typedef unsigned long long uint64_t;
typedef __INTMAX_TYPE__ intmax_t;
typedef __UINTMAX_TYPE__ uintmax_t;
#else
typedef long int64_t;
typedef unsigned long uint64_t;
typedef int64_t intmax_t;
typedef uint64_t uintmax_t;
#endif
#if defined(_LP64) || defined(__ppc64__) || defined(__aarch64__)
typedef long intptr_t;
typedef unsigned long uintptr_t;
#elif defined(_WIN64)
typedef int64_t intptr_t;
typedef uint64_t uintptr_t;
#elif defined(_LP32) || defined(__ppc__) || defined(_WIN32) || defined(__arm__)
typedef int32_t intptr_t;
typedef uint32_t uintptr_t;
#else
#error intptr_t, and uintptr_t undefined
#endif
#endif
using uint_t = unsigned;
namespace ox {
/**
* Aliases type T in size and alignment to allow allocating space for a T
* without running the constructor.
*/
template<typename T, std::size_t sz = sizeof(T)>
struct alignas(alignof(T)) AllocAlias {
char buff[sz];
constexpr AllocAlias() noexcept = default;
[[nodiscard]]
auto data() noexcept {
return reinterpret_cast<T*>(this);
}
[[nodiscard]]
auto data() const noexcept {
return reinterpret_cast<const T*>(this);
}
};
template<std::size_t sz>
struct SignedType {
};
template<>
struct SignedType<8> {
using type = int8_t;
};
template<>
struct SignedType<16> {
using type = int16_t;
};
template<>
struct SignedType<32> {
using type = int32_t;
};
template<>
struct SignedType<64> {
using type = int64_t;
};
template<std::size_t sz>
struct UnsignedType {
};
template<>
struct UnsignedType<8> {
using type = uint8_t;
};
template<>
struct UnsignedType<16> {
using type = uint16_t;
};
template<>
struct UnsignedType<32> {
using type = uint32_t;
};
template<>
struct UnsignedType<64> {
using type = uint64_t;
};
template<std::size_t bits>
using Int = typename SignedType<bits>::type;
template<std::size_t bits>
using Uint = typename UnsignedType<bits>::type;
template<typename T>
using Signed = Int<sizeof(T) * 8>;
template<typename T>
using Unsigned = Uint<sizeof(T) * 8>;
// ResizedInt retains the sign while granting a new size
template<typename T, std::size_t bits, bool si = static_cast<T>(-1) < static_cast<T>(0)>
struct ResizedInt {
};
template<typename T, std::size_t bits>
struct ResizedInt<T, bits, true> {
using type = typename SignedType<bits>::type;
};
template<typename T, std::size_t bits>
struct ResizedInt<T, bits, false> {
using type = typename UnsignedType<bits>::type;
};
template<typename T, std::size_t bits>
using ResizedInt_t = typename ResizedInt<T, bits>::type;
using ssize_t = Signed<std::size_t>;
}
static_assert(sizeof(int8_t) == 1, "int8_t is wrong size");
static_assert(sizeof(int16_t) == 2, "int16_t is wrong size");
static_assert(sizeof(int32_t) == 4, "int32_t is wrong size");
static_assert(sizeof(int64_t) == 8, "int64_t is wrong size");
static_assert(sizeof(intptr_t) == sizeof(void*), "intptr_t is wrong size");
static_assert(sizeof(uint8_t) == 1, "uint8_t is wrong size");
static_assert(sizeof(uint16_t) == 2, "uint16_t is wrong size");
static_assert(sizeof(uint32_t) == 4, "uint32_t is wrong size");
static_assert(sizeof(uint64_t) == 8, "uint64_t is wrong size");
static_assert(sizeof(uintptr_t) == sizeof(void*), "uintptr_t is wrong size");

25
deps/ox/src/ox/std/typetraits.cpp vendored Normal file
View File

@@ -0,0 +1,25 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#include "typetraits.hpp"
namespace ox {
template<bool moveable, bool copyable>
struct ConstructableTest {
constexpr ConstructableTest(int) noexcept {}
constexpr ConstructableTest(ConstructableTest&) noexcept requires(copyable) {}
constexpr ConstructableTest(ConstructableTest&&) noexcept requires(moveable) {}
};
static_assert(!is_move_constructible_v<ConstructableTest<false, false>>);
static_assert(is_move_constructible_v<ConstructableTest<true, false>>);
static_assert(!is_move_constructible_v<ConstructableTest<false, true>>);
static_assert(is_move_constructible_v<ConstructableTest<true, true>>);
}

313
deps/ox/src/ox/std/typetraits.hpp vendored Normal file
View File

@@ -0,0 +1,313 @@
/*
* 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 "types.hpp"
#if __has_include(<type_traits>)
#include <type_traits>
#else
namespace std {
template<typename T>
constexpr bool is_union_v = __is_union(T);
constexpr bool is_constant_evaluated() noexcept {
return __builtin_is_constant_evaluated();
}
}
#endif
namespace ox {
template<class T, T v>
struct integral_constant {
using value_type = T;
using type = integral_constant;
static constexpr T value = v;
constexpr operator value_type() const noexcept {
return value;
}
constexpr value_type operator()() const noexcept {
return value;
}
};
using false_type = integral_constant<bool, false>;
using true_type = integral_constant<bool, true>;
// is_const /////////////////////////////////////////////////////////////////
template<typename T>
constexpr bool is_const_v = false;
template<typename T>
constexpr bool is_const_v<const T> = true;
// is_integral /////////////////////////////////////////////////////////////////
template<typename T> struct is_integral: false_type {};
template<> struct is_integral<bool> : true_type {};
template<> struct is_integral<wchar_t> : true_type {};
template<> struct is_integral<int8_t> : true_type {};
template<> struct is_integral<uint8_t> : true_type {};
template<> struct is_integral<int16_t> : true_type {};
template<> struct is_integral<uint16_t>: true_type {};
template<> struct is_integral<int32_t> : true_type {};
template<> struct is_integral<uint32_t>: true_type {};
template<> struct is_integral<const bool> : true_type {};
template<> struct is_integral<const wchar_t> : true_type {};
template<> struct is_integral<const int8_t> : true_type {};
template<> struct is_integral<const uint8_t> : true_type {};
template<> struct is_integral<const int16_t> : true_type {};
template<> struct is_integral<const uint16_t>: true_type {};
template<> struct is_integral<const int32_t> : true_type {};
template<> struct is_integral<const uint32_t>: true_type {};
// some of these need to be done with the actual language syntax because no one
// can agree on what an (u)int64_t is...
template<> struct is_integral<long>: true_type {};
template<> struct is_integral<long long>: true_type {};
template<> struct is_integral<unsigned long>: true_type {};
template<> struct is_integral<unsigned long long>: true_type {};
template<> struct is_integral<const long>: true_type {};
template<> struct is_integral<const long long>: true_type {};
template<> struct is_integral<const unsigned long>: true_type {};
template<> struct is_integral<const unsigned long long>: true_type {};
template<typename T>
constexpr bool is_integral_v = is_integral<T>::value;
// is_integer /////////////////////////////////////////////////////////////////
template<typename T> struct is_integer: false_type {};
template<> struct is_integer<int8_t> : true_type {};
template<> struct is_integer<uint8_t> : true_type {};
template<> struct is_integer<int16_t> : true_type {};
template<> struct is_integer<uint16_t>: true_type {};
template<> struct is_integer<int32_t> : true_type {};
template<> struct is_integer<uint32_t>: true_type {};
// some of these need to be done with the actual language syntax because no one
// can agree on what an (u)int64_t is...
template<> struct is_integer<long>: true_type {};
template<> struct is_integer<long long>: true_type {};
template<> struct is_integer<unsigned long>: true_type {};
template<> struct is_integer<unsigned long long>: true_type {};
template<typename T>
constexpr bool is_integer_v = is_integral<T>::value;
template<typename T>
concept Integer_c = is_integer<T>::value;
template<typename T> struct is_char: false_type {};
template<> struct is_char<char> : true_type {};
template<typename T>
constexpr bool is_char_v = is_char<T>::value;
template<typename T> struct is_bool: false_type {};
template<> struct is_bool<bool> : true_type {};
template<typename T>
constexpr bool is_bool_v = is_bool<T>::value;
template<typename T> struct is_union: integral_constant<bool, std::is_union_v<T>> {};
template<typename T>
constexpr bool is_union_v = is_union<T>();
// indicates the type can have members, but not that it necessarily does
template<typename T>
constexpr bool memberable(int T::*) { return true; }
template<typename T>
constexpr bool memberable(...) { return false; }
template<typename T>
struct is_class: integral_constant<bool, !is_union<T>::value && memberable<T>(0)> {};
namespace test {
struct TestClass {int i;};
union TestUnion {int i;};
static_assert(is_class<TestClass>::value == true);
static_assert(is_class<TestUnion>::value == false);
static_assert(is_class<int>::value == false);
}
template<typename T>
constexpr bool is_class_v = is_class<T>();
template<typename T>
constexpr bool is_signed_v = integral_constant<bool, T(-1) < T(0)>::value;
template<typename T, std::size_t bits>
concept Signed_c = is_signed_v<T> && sizeof(T) == 8 * bits;
template<typename T, std::size_t bits>
concept Unsigned_c = !is_signed_v<T> && sizeof(T) == 8 * bits;
template<typename T, typename U>
struct is_same: false_type {};
template<typename T>
struct is_same<T, T>: true_type {};
template<typename T, typename U>
constexpr auto is_same_v = is_same<T, U>::value;
// enable_if ///////////////////////////////////////////////////////////////////
template<bool B, class T = void>
struct enable_if {
};
template<class T>
struct enable_if<true, T> {
using type = T;
};
template<typename T>
struct is_pointer {
static constexpr bool value = false;
};
template<typename T>
struct is_pointer<T*> {
static constexpr bool value = true;
};
template<typename T>
struct is_pointer<const T*> {
static constexpr bool value = true;
};
template<typename T>
constexpr bool is_pointer_v = is_pointer<T>::value;
template<typename T>
struct remove_pointer {
using type = T;
};
template<typename T>
struct remove_pointer<T*> {
using type = T;
};
template<typename T>
struct remove_pointer<T* const> {
using type = T;
};
template<typename T>
struct remove_pointer<T* volatile> {
using type = T;
};
template<typename T>
struct remove_pointer<T* const volatile> {
using type = T;
};
template<typename T>
struct remove_reference {
using type = T;
};
template<typename T>
struct remove_reference<T&> {
using type = T;
};
template<typename T>
struct remove_reference<T&&> {
using type = T;
};
template<typename T>
using remove_reference_t = typename remove_reference<T>::type;
namespace detail {
template<typename T>
T &&declval();
template<typename T, typename = decltype(T(declval<T>()))>
constexpr bool is_move_constructible(int) {
return true;
}
template<typename T>
constexpr bool is_move_constructible(bool) {
return false;
}
}
template<class T>
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 CStringView;
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 CStringView*) 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));
}

20
deps/ox/src/ox/std/units.hpp vendored Normal file
View File

@@ -0,0 +1,20 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "types.hpp"
namespace ox::units {
constexpr uint64_t KB = 1024;
constexpr uint64_t MB = 1024 * KB;
constexpr uint64_t GB = 1024 * MB;
constexpr uint64_t TB = 1024 * GB;
}

43
deps/ox/src/ox/std/utility.hpp vendored Normal file
View File

@@ -0,0 +1,43 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "typetraits.hpp"
namespace ox {
struct in_place_t {
explicit constexpr in_place_t() = default;
};
inline constexpr ox::in_place_t in_place;
template<class T>
constexpr T &&forward(remove_reference_t<T> &t) noexcept {
return static_cast<T&&>(t);
}
template<class T>
constexpr T &&forward(remove_reference_t<T> &&t) noexcept {
return static_cast<T&&>(t);
}
}
#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

40
deps/ox/src/ox/std/uuid.cpp vendored Normal file
View File

@@ -0,0 +1,40 @@
/*
* Copyright 2015 - 2023 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 http://mozilla.org/MPL/2.0/.
*/
#include "uuid.hpp"
namespace ox {
bool UUID::s_seeded = false;
Random UUID::s_rand;
void UUID::seedGenerator(const RandomSeed &seed) noexcept {
s_seeded = true;
s_rand.seed(seed);
}
// UUID v4
Result<UUID> UUID::generate() noexcept {
if (!s_seeded) {
return OxError(1, "UUID generator not seeded.");
}
UUID out;
for (auto &v : out.m_value) {
// shift away 4 lowest bits, as Xoroshiro128+ randomness is weaker there
const auto rand = s_rand.gen() >> 4;
v = static_cast<uint8_t>(rand % 255);
}
out.m_value[6] &= 0x0f;
out.m_value[6] |= 4 << 4;
return out;
}
static_assert(UUID{}.isNull());
static_assert(!UUID::fromString("34af4809-043d-4348-b720-2b454e5678c7").value.isNull());
}

191
deps/ox/src/ox/std/uuid.hpp vendored Normal file
View File

@@ -0,0 +1,191 @@
/*
* Copyright 2015 - 2023 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 "array.hpp"
#include "bstring.hpp"
#include "buffer.hpp"
#include "random.hpp"
#include "ranges.hpp"
#include "stringview.hpp"
namespace ox {
using UUIDStr = ox::BString<36>;
namespace detail {
[[nodiscard]]
constexpr auto isHexChar(char c) noexcept {
return (c >= '0' && c <= '9')
|| (c >= 'a' && c <= 'f')
|| (c >= 'A' && c <= 'F');
}
constexpr ox::Result<uint8_t> fromHex(ox::CRStringView v) noexcept {
constexpr auto valMap = [] {
ox::Array<uint8_t, 128> out;
out['A'] = out['a'] = 10;
out['B'] = out['b'] = 11;
out['C'] = out['c'] = 12;
out['D'] = out['d'] = 13;
out['E'] = out['e'] = 14;
out['F'] = out['f'] = 15;
out['0'] = 0;
out['1'] = 1;
out['2'] = 2;
out['3'] = 3;
out['4'] = 4;
out['5'] = 5;
out['6'] = 6;
out['7'] = 7;
out['8'] = 8;
out['9'] = 9;
return out;
}();
if (!detail::isHexChar(v[0]) || !detail::isHexChar(v[1])) {
return OxError(1, "Invalid UUID");
}
if (v.len() != 2) {
return OxError(2);
}
uint8_t out = 0;
out += static_cast<uint8_t>(valMap[static_cast<unsigned char>(v[0])] * 16);
out += valMap[static_cast<unsigned char>(v[1])];
return out;
}
constexpr ox::BString<2> toHex(uint8_t v) noexcept {
constexpr ox::Array<char, 16> valMap {
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'a',
'b',
'c',
'd',
'e',
'f',
};
ox::Array<char, 3> out;
out[0] = valMap[static_cast<unsigned>((v & 0xf0) / 16)];
out[1] = valMap[static_cast<unsigned>(v & 0x0f)];
out[2] = 0;
return out.data();
}
}
class UUID {
template<typename T>
friend constexpr Error model(T *io, ox::CommonPtrWith<UUID> auto *obj) noexcept;
protected:
static bool s_seeded;
static Random s_rand;
ox::Array<uint8_t, 16> m_value{};
public:
static void seedGenerator(const RandomSeed &seed) noexcept;
static ox::Result<UUID> generate() noexcept;
[[nodiscard]]
constexpr auto value() const noexcept {
return m_value;
}
[[nodiscard]]
constexpr auto isNull() const noexcept {
if (std::is_constant_evaluated()) {
if (ox::all_of(m_value.begin(), m_value.end(), [](auto v) { return v == 0; })) {
return true;
}
return false;
} else {
constexpr uint64_t zero = 0;
return ox::memcmp(&zero, m_value.data() + 0, 8) == 0
&& ox::memcmp(&zero, m_value.data() + 8, 8) == 0;
}
}
static constexpr ox::Result<ox::UUID> fromString(ox::CRStringView s) noexcept {
if (s.len() < 36) {
return OxError(1, "Insufficient data to contain a complete UUID");
}
UUID out;
auto valueI = 0u;
for (size_t i = 0; i < s.len();) {
if (s[i] == '-') {
++i;
continue;
}
const auto seg = substr(s, i, i + 2);
if (seg.len() != 2) {
return OxError(1, "Invalid UUID");
}
oxRequire(val, detail::fromHex(seg));
out.m_value[valueI] = val;
i += 2;
++valueI;
}
return out;
}
[[nodiscard]]
constexpr ox::Error toString(Writer_c auto &writer) const noexcept {
auto valueI = 0u;
constexpr auto printChars = [](
Writer_c auto &writer,
const Array<uint8_t, 16> &value,
std::size_t cnt,
unsigned &valueI) {
for (auto i = 0u; i < cnt; ++i) {
const auto v = value[valueI];
const auto h = detail::toHex(v);
oxIgnoreError(writer.write(h.c_str(), h.len()));
++valueI;
}
};
printChars(writer, m_value, 4, valueI);
oxReturnError(writer.put('-'));
printChars(writer, m_value, 2, valueI);
oxReturnError(writer.put('-'));
printChars(writer, m_value, 2, valueI);
oxReturnError(writer.put('-'));
printChars(writer, m_value, 2, valueI);
oxReturnError(writer.put('-'));
printChars(writer, m_value, 6, valueI);
return {};
}
[[nodiscard]]
constexpr UUIDStr toString() const noexcept {
UUIDStr out;
ox::CharBuffWriter bw(out.data(), out.cap());
oxIgnoreError(toString(bw));
out[out.cap()] = 0;
return out;
}
};
template<typename T>
constexpr Error model(T *io, ox::CommonPtrWith<UUID> auto *obj) noexcept {
oxReturnError(io->template setTypeInfo<UUID>());
oxReturnError(io->field("value", &obj->m_value));
return {};
}
}

20
deps/ox/src/ox/std/vec.cpp vendored Normal file
View File

@@ -0,0 +1,20 @@
/*
* Copyright 2015 - 2023 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 http://mozilla.org/MPL/2.0/.
*/
#include <ox/std/defines.hpp>
#include "vec.hpp"
namespace ox {
static_assert([] {
Vec2 v(1, 2);
return v.x == 1 && v.y == 2 && v[0] == 1 && v[1] == 2 && v.size() == 2;
}());
}

271
deps/ox/src/ox/std/vec.hpp vendored Normal file
View File

@@ -0,0 +1,271 @@
/*
* Copyright 2015 - 2023 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
#if __has_include(<imgui.h>)
#include <imgui.h>
#endif
#include <ox/model/def.hpp>
#include <ox/std/assert.hpp>
#include <ox/std/bit.hpp>
#include <ox/std/def.hpp>
#include <ox/std/error.hpp>
#include <ox/std/iterator.hpp>
#include <ox/std/math.hpp>
#include <ox/std/types.hpp>
namespace ox {
template<typename T>
struct Vec {
public:
using value_type = T;
using size_type = std::size_t;
static constexpr auto TypeName = "net.drinkingtea.ox.Point";
static constexpr auto TypeVersion = 1;
T x = 0;
T y = 0;
template<typename RefType = value_type&, typename PtrType = value_type*, bool reverse = false>
struct iterator: public ox::Iterator<std::bidirectional_iterator_tag, value_type> {
private:
PtrType m_t = nullptr;
size_type m_offset = 0;
size_type m_max = 0;
public:
constexpr iterator() noexcept = default;
constexpr iterator(PtrType t, size_type offset, size_type max) noexcept {
m_t = t;
m_offset = offset;
m_max = max;
}
[[nodiscard]]
constexpr auto offset() const noexcept {
return m_offset;
}
constexpr iterator operator+(size_type s) const noexcept {
if constexpr(reverse) {
return iterator(m_t, ox::max<size_type>(m_offset - s, 0), m_max);
} else {
return iterator(m_t, ox::min<size_type>(m_offset + s, m_max), m_max);
}
}
constexpr typename ox::Iterator<std::bidirectional_iterator_tag, value_type>::difference_type
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-(size_type s) const noexcept {
if constexpr(reverse) {
return iterator(m_t, ox::min<size_type>(m_offset + s, m_max), m_max);
} else {
return iterator(m_t, ox::max<size_type>(m_offset - s, 0), m_max);
}
}
constexpr iterator &operator+=(size_type s) noexcept {
if constexpr(reverse) {
m_offset = ox::max<size_type>(m_offset - s, 0);
} else {
m_offset = ox::min(m_offset + s, m_max);
}
return *this;
}
constexpr iterator &operator-=(size_type s) noexcept {
if constexpr(reverse) {
m_offset = ox::min(m_offset + s, m_max);
} else {
m_offset = ox::max<size_type>(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[](size_type 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;
}
};
constexpr Vec() noexcept = default;
template<typename ...Args>
constexpr Vec(T pX, T pY) noexcept: x(pX), y(pY) {
}
#if __has_include(<imgui.h>)
explicit constexpr Vec(const ImVec2 &v) noexcept: Vec(v.x, v.y) {
}
explicit inline operator ImVec2() const noexcept {
return {x, y};
}
#endif
[[nodiscard]]
constexpr iterator<> begin() noexcept {
return {start(), 0, size()};
}
[[nodiscard]]
constexpr iterator<> end() noexcept {
return {start(), size(), size()};
}
[[nodiscard]]
constexpr iterator<const value_type&, const value_type*> begin() const noexcept {
return {start(), 0, size()};
}
[[nodiscard]]
constexpr iterator<const value_type&, const value_type*> end() const noexcept {
return {start(), size(), size()};
}
[[nodiscard]]
constexpr iterator<value_type&, value_type*, true> rbegin() noexcept {
return {start(), size() - 1, size()};
}
[[nodiscard]]
constexpr iterator<value_type&, value_type*, true> rend() noexcept {
return {start(), ox::MaxValue<size_type>, size()};
}
[[nodiscard]]
constexpr iterator<const value_type&, const value_type*, true> rbegin() const noexcept {
return {start(), size() - 1, size()};
}
[[nodiscard]]
constexpr iterator<const value_type&, const value_type*, true> rend() const noexcept {
return {start(), ox::MaxValue<size_type>, size()};
}
constexpr auto &operator[](std::size_t i) noexcept {
if (std::is_constant_evaluated()) {
switch (i) {
case 0:
return x;
case 1:
return y;
default:
oxAssert(false, "Read past end of Vec2");
return y;
}
} else {
return start()[i];
}
}
constexpr const auto &operator[](std::size_t i) const noexcept {
if (std::is_constant_evaluated()) {
switch (i) {
case 0:
return x;
case 1:
return y;
default:
oxAssert(false, "Read past end of Vec2");
return y;
}
} else {
return start()[i];
}
}
constexpr auto operator==(const Vec &v) const noexcept {
for (auto i = 0u; i < v.size(); ++i) {
if ((*this)[i] != v[i]) {
return false;
}
}
return true;
}
constexpr auto operator!=(const Vec &v) const noexcept {
return !operator==(v);
}
[[nodiscard]]
constexpr std::size_t size() const noexcept {
return 2;
}
protected:
[[nodiscard]]
constexpr T *start() noexcept {
return &x;
}
[[nodiscard]]
constexpr const T *start() const noexcept {
return &x;
}
};
using Vec2 = Vec<float>;
template<typename T>
constexpr Error model(T *io, ox::CommonPtrWith<Vec2> auto *obj) noexcept {
oxReturnError(io->template setTypeInfo<Vec2>());
oxReturnError(io->field("x", &obj->x));
oxReturnError(io->field("y", &obj->y));
return {};
}
}

695
deps/ox/src/ox/std/vector.hpp vendored Normal file
View File

@@ -0,0 +1,695 @@
/*
* Copyright 2015 - 2023 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "array.hpp"
#include "concepts.hpp"
#include "bit.hpp"
#include "error.hpp"
#include "initializerlist.hpp"
#include "iterator.hpp"
#include "math.hpp"
#include "memory.hpp"
#include "stringview.hpp"
#include "types.hpp"
#include "utility.hpp"
namespace ox {
namespace detail {
template<typename T, typename Allocator, std::size_t Size = 1>
struct VectorAllocator {
static_assert(sizeof(AllocAlias<T>) == sizeof(T));
static_assert(alignof(AllocAlias<T>) == alignof(T));
private:
ox::Array<AllocAlias<T>, Size> m_data = {};
Allocator m_allocator;
protected:
constexpr VectorAllocator() noexcept = default;
constexpr VectorAllocator(const VectorAllocator&) noexcept = default;
constexpr VectorAllocator(VectorAllocator&&) noexcept = default;
constexpr void allocate(T **items, std::size_t cap) noexcept {
// small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr
if (std::is_constant_evaluated() || cap > Size) {
*items = m_allocator.allocate(cap);
} else {
*items = reinterpret_cast<T*>(m_data.data());
}
}
constexpr void moveConstructItemsFrom(
T **items,
VectorAllocator *src,
const std::size_t count,
const std::size_t cap) noexcept {
// this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM,
// try removing it later
if (cap <= m_data.size() && count <= m_data.size()) {
for (auto i = 0u; i < count; ++i) {
const auto dstItem = reinterpret_cast<T*>(&m_data[i]);
const auto srcItem = reinterpret_cast<T*>(&src->m_data[i]);
std::construct_at<T>(dstItem, std::move(*srcItem));
}
*items = reinterpret_cast<T*>(m_data.data());
}
}
constexpr void moveItemsFrom(
T **items,
VectorAllocator *src,
const std::size_t count,
const std::size_t cap) noexcept {
// this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM,
// try removing it later
if (cap <= m_data.size() && count <= m_data.size()) {
for (std::size_t i = 0; i < count; ++i) {
const auto dstItem = reinterpret_cast<T*>(&m_data[i]);
const auto srcItem = reinterpret_cast<T*>(&src->m_data[i]);
*dstItem = std::move(*srcItem);
}
*items = reinterpret_cast<T*>(m_data.data());
}
}
constexpr void deallocate(T *items, std::size_t cap) noexcept {
// small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr
if (std::is_constant_evaluated() || (items && static_cast<void*>(items) != static_cast<void*>(m_data.data()))) {
m_allocator.deallocate(items, cap);
}
}
};
template<typename T, typename Allocator>
struct VectorAllocator<T, Allocator, 0> {
private:
Allocator m_allocator;
protected:
constexpr VectorAllocator() noexcept = default;
constexpr VectorAllocator(const VectorAllocator&) noexcept = default;
constexpr VectorAllocator(VectorAllocator&&) noexcept = default;
constexpr void allocate(T **items, std::size_t cap) noexcept {
*items = m_allocator.allocate(cap);
}
[[maybe_unused]]
constexpr void moveConstructItemsFrom(
T**,
VectorAllocator*,
const std::size_t,
const std::size_t) noexcept {
}
[[maybe_unused]]
constexpr void moveItemsFrom(T**, VectorAllocator*, const std::size_t, const std::size_t) noexcept {
}
constexpr void deallocate(T *items, std::size_t cap) noexcept {
if (items) {
m_allocator.deallocate(items, cap);
}
}
};
}
template<typename T, std::size_t SmallVectorSize = 0, typename Allocator = std::allocator<T>>
class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
public:
using value_type = T;
using size_type = std::size_t;
template<typename RefType = T&, typename PtrType = T*, bool reverse = false>
using iterator = SpanIterator<T, RefType, PtrType, reverse>;
private:
static constexpr auto initialCap = SmallVectorSize > 0 ? SmallVectorSize : 50;
static constexpr auto useNoexcept = ox::is_integral_v<T> || ox::is_pointer_v<T>;
std::size_t m_size = 0;
std::size_t m_cap = 0;
T *m_items = nullptr;
public:
constexpr Vector() noexcept = default;
explicit constexpr Vector(std::size_t size) noexcept;
constexpr Vector(std::initializer_list<T> list) noexcept;
constexpr Vector(const Vector &other) noexcept(useNoexcept);
constexpr Vector(Vector &&other) noexcept;
constexpr ~Vector();
constexpr iterator<> begin() noexcept {
return iterator<>(m_items, 0, m_size);
}
constexpr iterator<> end() noexcept {
return iterator<>(m_items, m_size, m_size);
}
[[nodiscard]]
constexpr iterator<const T&, const T*> begin() const noexcept {
return iterator<const T&, const T*>(m_items, 0, m_size);
}
[[nodiscard]]
constexpr iterator<const T&, const T*> end() const noexcept {
return iterator<const T&, const T*>(m_items, m_size, m_size);
}
[[nodiscard]]
constexpr iterator<const T&, const T*> cbegin() const noexcept {
return iterator<const T&, const T*>(m_items, 0, m_size);
}
[[nodiscard]]
constexpr iterator<const T&, const T*> cend() const noexcept {
return iterator<const T&, const T*>(m_items, m_size, m_size);
}
[[nodiscard]]
constexpr iterator<T&, T*, true> rbegin() noexcept {
return iterator<T&, T*, true>(m_items, m_size - 1, m_size);
}
[[nodiscard]]
constexpr iterator<T&, T*, true> rend() noexcept {
return iterator<T&, T*, true>(m_items, MaxValue<size_type>, m_size);
}
[[nodiscard]]
constexpr iterator<const T&, const T*, true> crbegin() const noexcept {
return iterator<const T&, const T*, true>(m_items, m_size - 1, m_size);
}
[[nodiscard]]
constexpr iterator<const T&, const T*, true> crend() const noexcept {
return iterator<const T&, const T*, true>(m_items, MaxValue<size_type>, m_size);
}
[[nodiscard]]
constexpr iterator<const T&, const T*, true> rbegin() const noexcept {
return iterator<const T&, const T*, true>(m_items, m_size - 1, m_size);
}
[[nodiscard]]
constexpr iterator<const T&, const T*, true> rend() const noexcept {
return iterator<const T&, const T*, true>(m_items, MaxValue<size_type>, m_size);
}
constexpr bool operator==(const Vector &other) const noexcept(useNoexcept);
constexpr Vector &operator=(const Vector &other) noexcept(useNoexcept);
constexpr Vector &operator=(Vector &&other) noexcept;
constexpr T &operator[](std::size_t i) noexcept;
constexpr const T &operator[](std::size_t i) const noexcept;
[[nodiscard]]
constexpr Result<T*> front() noexcept;
[[nodiscard]]
constexpr Result<const T*> front() const noexcept;
[[nodiscard]]
constexpr Result<T*> back() noexcept;
[[nodiscard]]
constexpr Result<const T*> back() const noexcept;
[[nodiscard]]
constexpr std::size_t size() const noexcept;
[[nodiscard]]
constexpr bool empty() const noexcept;
constexpr void clear() noexcept(useNoexcept);
constexpr void resize(std::size_t size) noexcept(useNoexcept);
[[nodiscard]]
constexpr T *data() noexcept {
return m_items;
}
[[nodiscard]]
constexpr const T *data() const noexcept {
return m_items;
}
[[nodiscard]]
constexpr bool contains(MaybeSV_t<T> const&) const noexcept(useNoexcept);
constexpr iterator<T&, T*, false> insert(
std::size_t pos, std::size_t cnt, MaybeSV_t<T> const&val) noexcept(useNoexcept);
constexpr iterator<T&, T*, false> insert(std::size_t pos, MaybeSV_t<T> const&val) noexcept(useNoexcept);
template<typename... Args>
constexpr iterator<T&, T*, false> emplace(std::size_t pos, Args&&... args) noexcept(useNoexcept);
template<typename... Args>
constexpr T &emplace_back(Args&&... args) noexcept(useNoexcept);
constexpr void push_back(T &&item) noexcept(useNoexcept);
constexpr void push_back(MaybeSV_t<T> const&item) noexcept(useNoexcept);
constexpr void pop_back() noexcept(useNoexcept);
/**
* Removes an item from the Vector.
* @param pos iterator at the point to remove
* @return Error if index is out of bounds
*/
constexpr Result<iterator<T&, T*, false>> erase(const iterator<> &pos) noexcept(useNoexcept);
/**
* Removes an item from the Vector.
* @param pos position of item to remove
* @return Error if index is out of bounds
*/
constexpr Result<iterator<T&, T*, false>> erase(std::size_t pos) noexcept(useNoexcept);
/**
* Moves the last item in the Vector to position pos and decrements the
* size by 1.
* @param pos position of item to remove
* @return Error if index is out of bounds
*/
constexpr Error unordered_erase(std::size_t pos) noexcept(useNoexcept);
constexpr void reserve(std::size_t cap) noexcept(useNoexcept);
private:
constexpr void reserveInsert(
std::size_t cap, std::size_t pos, std::size_t offset = 1) noexcept(useNoexcept);
};
template<typename T, std::size_t SmallVectorSize, typename Allocator, typename RefType, bool reverse>
using VectorIt = typename Vector<T, SmallVectorSize, Allocator>::template iterator<RefType, reverse>;
template<typename T, std::size_t SmallVectorSize, typename Allocator, typename RefType, bool reverse>
constexpr VectorIt<T, SmallVectorSize, Allocator, RefType, reverse> operator+(
std::size_t n,
const VectorIt<T, SmallVectorSize, Allocator, RefType, reverse> &a) {
return a + n;
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr Vector<T, SmallVectorSize, Allocator>::Vector(std::size_t size) noexcept {
m_size = size;
m_cap = m_size;
this->allocate(&m_items, m_cap);
for (std::size_t i = 0; i < size; ++i) {
std::construct_at(&m_items[i]);
}
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr Vector<T, SmallVectorSize, Allocator>::Vector(std::initializer_list<T> list) noexcept {
for (auto &item : list) {
emplace_back(std::move(item));
}
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr Vector<T, SmallVectorSize, Allocator>::Vector(const Vector &other) noexcept(useNoexcept) {
m_size = other.m_size;
m_cap = other.m_cap;
this->allocate(&m_items, other.m_cap);
for (std::size_t i = 0; i < m_size; ++i) {
std::construct_at(&m_items[i], other.m_items[i]);
}
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr Vector<T, SmallVectorSize, Allocator>::Vector(Vector &&other) noexcept {
m_size = other.m_size;
m_cap = other.m_cap;
m_items = other.m_items;
this->moveConstructItemsFrom(&m_items, &other, m_size, m_cap);
other.m_size = 0;
other.m_cap = 0;
other.m_items = nullptr;
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr Vector<T, SmallVectorSize, Allocator>::~Vector() {
clear();
this->deallocate(m_items, m_cap);
m_items = nullptr;
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr bool Vector<T, SmallVectorSize, Allocator>::operator==(
const Vector &other) const noexcept(useNoexcept) {
if (m_size != other.m_size) {
return false;
}
for (std::size_t i = 0; i < m_size; i++) {
if (!(m_items[i] == other.m_items[i])) {
return false;
}
}
return true;
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr Vector<T, SmallVectorSize, Allocator> &Vector<T, SmallVectorSize, Allocator>::operator=(
const Vector &other) noexcept(useNoexcept) {
if (this != &other) {
clear();
this->deallocate(m_items, m_cap);
m_items = nullptr;
m_size = other.m_size;
m_cap = other.m_cap;
this->allocate(&m_items, other.m_cap);
for (std::size_t i = 0; i < m_size; i++) {
std::construct_at(&m_items[i], other.m_items[i]);
}
}
return *this;
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr Vector<T, SmallVectorSize, Allocator> &Vector<T, SmallVectorSize, Allocator>::operator=(
Vector &&other) noexcept {
if (this != &other) {
clear();
this->deallocate(m_items, m_cap);
m_size = other.m_size;
m_cap = other.m_cap;
m_items = other.m_items;
this->moveItemsFrom(&m_items, &other, m_size, m_cap);
other.m_size = 0;
other.m_cap = 0;
other.m_items = nullptr;
}
return *this;
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr T &Vector<T, SmallVectorSize, Allocator>::operator[](std::size_t i) noexcept {
return m_items[i];
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr const T &Vector<T, SmallVectorSize, Allocator>::operator[](std::size_t i) const noexcept {
return m_items[i];
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr Result<T*> Vector<T, SmallVectorSize, Allocator>::front() noexcept {
if (!m_size) {
return {nullptr, OxError(1)};
}
return &m_items[0];
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr Result<const T*> Vector<T, SmallVectorSize, Allocator>::front() const noexcept {
if (!m_size) {
return {nullptr, OxError(1)};
}
return &m_items[0];
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr Result<T*> Vector<T, SmallVectorSize, Allocator>::back() noexcept {
if (!m_size) {
return {nullptr, OxError(1)};
}
return &m_items[m_size - 1];
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr Result<const T*> Vector<T, SmallVectorSize, Allocator>::back() const noexcept {
if (!m_size) {
return {nullptr, OxError(1)};
}
return &m_items[m_size - 1];
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr std::size_t Vector<T, SmallVectorSize, Allocator>::size() const noexcept {
return m_size;
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr bool Vector<T, SmallVectorSize, Allocator>::empty() const noexcept {
return !m_size;
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::clear() noexcept(useNoexcept) {
if constexpr(is_class<T>()) {
for (std::size_t i = 0; i < m_size; ++i) {
m_items[i].~T();
}
}
m_size = 0;
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::resize(std::size_t size) noexcept(useNoexcept) {
if (m_cap < size) {
reserve(size * 2);
}
if (m_size < size) {
for (std::size_t i = m_size; i < size; i++) {
std::construct_at(&m_items[i]);
}
} else {
for (std::size_t i = size; i < m_size; i++) {
m_items[i].~T();
}
}
m_size = size;
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr bool Vector<T, SmallVectorSize, Allocator>::contains(MaybeSV_t<T> const&v) const noexcept(useNoexcept) {
for (std::size_t i = 0; i < m_size; i++) {
if (m_items[i] == v) {
return true;
}
}
return false;
}
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, MaybeSV_t<T> const&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;
} else {
for (auto i = 0u; i < cnt; ++i) {
std::construct_at(&m_items[pos + i], val);
}
}
} else {
if (pos < m_size) {
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;
} else {
for (auto i = 0u; i < cnt; ++i) {
std::construct_at(&m_items[pos + i], val);
}
}
}
++m_size;
return begin() + pos;
}
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, MaybeSV_t<T> const&val) noexcept(useNoexcept) {
if (m_size == m_cap) {
reserveInsert(m_cap ? m_cap * 2 : initialCap, pos);
if (pos < m_size) {
m_items[pos] = val;
} else {
std::construct_at(&m_items[pos], val);
}
} 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;
} else {
std::construct_at(&m_items[pos], val);
}
}
++m_size;
return begin() + pos;
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
template<typename... Args>
constexpr typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false>
Vector<T, SmallVectorSize, Allocator>::emplace(std::size_t pos, Args&&... args) noexcept(useNoexcept) {
if (m_size == m_cap) {
reserveInsert(m_cap ? m_cap * 2 : initialCap, pos);
if (pos < m_size) {
m_items[pos].~T();
}
std::construct_at(&m_items[pos], ox::forward<Args>(args)...);
} 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].~T();
}
std::construct_at(&m_items[pos], ox::forward<Args>(args)...);
}
++m_size;
return begin() + pos;
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
template<typename... Args>
constexpr T &Vector<T, SmallVectorSize, Allocator>::emplace_back(Args&&... args) noexcept(useNoexcept) {
if (m_size == m_cap) {
reserve(m_cap ? m_cap * 2 : initialCap);
}
auto out = std::construct_at(&m_items[m_size], ox::forward<Args>(args)...);
++m_size;
return *out;
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T &&item) noexcept(useNoexcept) {
if (m_size == m_cap) {
reserve(m_cap ? m_cap * 2 : initialCap);
}
std::construct_at(&m_items[m_size], std::move(item));
++m_size;
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(MaybeSV_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;
m_items[m_size].~T();
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr Result<typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false>>
Vector<T, SmallVectorSize, Allocator>::erase(const iterator<> &pos) noexcept(useNoexcept) {
return erase(pos.offset());
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr Result<typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false>>
Vector<T, SmallVectorSize, Allocator>::erase(std::size_t pos) noexcept(useNoexcept) {
if (pos >= m_size) {
return OxError(1, "Vector::erase failed: pos is greater than Vector size");
}
--m_size;
for (auto i = pos; i < m_size; ++i) {
m_items[i] = std::move(m_items[i + 1]);
}
m_items[m_size].~T();
return begin() + pos;
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr Error Vector<T, SmallVectorSize, Allocator>::unordered_erase(std::size_t pos)
noexcept(useNoexcept) {
if (pos >= m_size) {
return OxError(1);
}
--m_size;
m_items[pos] = std::move(m_items[m_size]);
m_items[m_size].~T();
return OxError(0);
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::reserve(std::size_t cap) noexcept(useNoexcept) {
if (cap <= m_cap) {
return;
}
const auto oldItems = m_items;
const auto oldCap = m_cap;
m_cap = cap;
this->allocate(&m_items, cap);
if (oldItems) { // move over old items
const auto itRange = ox::min(cap, m_size);
for (std::size_t i = 0; i < itRange; ++i) {
std::construct_at(&m_items[i], std::move(oldItems[i]));
oldItems[i].~T();
}
this->deallocate(oldItems, oldCap);
}
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::reserveInsert(
std::size_t cap,
std::size_t pos,
std::size_t offset) noexcept(useNoexcept) {
if (cap <= m_cap) {
return;
}
const auto oldItems = m_items;
const auto oldCap = m_cap;
m_cap = cap;
this->allocate(&m_items, cap);
if (oldItems) { // move over old items
auto itRange = ox::min(m_size, pos);
for (std::size_t i = 0; i < itRange; ++i) {
std::construct_at(&m_items[i], std::move(oldItems[i]));
oldItems[i].~T();
}
itRange = m_size;
for (std::size_t i = pos; i < itRange; ++i) {
std::construct_at(&m_items[i + offset], std::move(oldItems[i]));
oldItems[i].~T();
}
this->deallocate(oldItems, oldCap);
}
}
template<typename PlatSpec, typename T>
[[nodiscard]]
constexpr auto alignOf(const Vector<T>&) noexcept {
const typename PlatSpec::size_t i = 0;
return PlatSpec::alignOf(i);
}
}

84
deps/ox/src/ox/std/writer.hpp vendored Normal file
View File

@@ -0,0 +1,84 @@
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "concepts.hpp"
#include "error.hpp"
#include "types.hpp"
namespace ox {
namespace ios_base {
enum seekdir {
beg,
end,
cur,
};
}
template<typename T>
concept Writer_c = requires(T v) {
{v.put(static_cast<char>(0))} -> ox::same_as<ox::Error>;
{v.write(static_cast<const char*>(""), static_cast<std::size_t>(0))} -> ox::same_as<ox::Error>;
{v.seekp(static_cast<std::size_t>(0))} -> ox::same_as<ox::Error>;
{v.seekp(static_cast<std::size_t>(0), ios_base::beg)} -> ox::same_as<ox::Error>;
{v.tellp()} -> ox::same_as<std::size_t>;
};
class Writer_v {
public:
virtual constexpr ~Writer_v() noexcept = default;
virtual constexpr auto put(char) noexcept -> ox::Error = 0;
virtual constexpr auto write(const char*, std::size_t) noexcept -> ox::Error = 0;
virtual constexpr auto seekp(std::size_t) noexcept -> ox::Error = 0;
virtual constexpr auto seekp(int, ios_base::seekdir) -> ox::Error = 0;
virtual constexpr auto tellp() noexcept -> std::size_t = 0;
};
template<Writer_c T>
class WriterT: public Writer_v {
private:
T m_writer{};
public:
template<typename ...Args>
constexpr explicit WriterT(Args&&... args) noexcept: m_writer(args...) {
}
constexpr auto put(char v) noexcept -> ox::Error override {
return m_writer.put(v);
}
constexpr auto write(const char *v, std::size_t cnt) noexcept -> ox::Error override {
return m_writer.write(v, cnt);
}
constexpr auto seekp(std::size_t p) noexcept -> ox::Error override {
return m_writer.seekp(p);
}
constexpr auto seekp(int p, ios_base::seekdir sd) noexcept -> ox::Error override {
return m_writer.seekp(p, sd);
}
constexpr auto tellp() noexcept -> std::size_t override {
return m_writer.tellp();
}
};
/**
* Allocates the specified amount of data at the end of the current write stream.
* @param writer
* @param sz
* @return
*/
constexpr ox::Result<std::size_t> allocate(Writer_c auto *writer, std::size_t sz) noexcept {
const auto p = writer->tellp();
oxReturnError(writer->seekp(0, ios_base::end));
const auto out = writer->tellp();
oxReturnError(writer->write(nullptr, sz));
oxReturnError(writer->seekp(p));
return out;
}
}