Squashed 'deps/nostalgia/' content from commit 9cb6bd4a
git-subtree-dir: deps/nostalgia git-subtree-split: 9cb6bd4a32e9f39a858f72443ff5c6d40489fe22
This commit is contained in:
145
deps/ox/src/ox/std/CMakeLists.txt
vendored
Normal file
145
deps/ox/src/ox/std/CMakeLists.txt
vendored
Normal 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
43
deps/ox/src/ox/std/algorithm.hpp
vendored
Normal 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
195
deps/ox/src/ox/std/array.hpp
vendored
Normal 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
34
deps/ox/src/ox/std/assert.cpp
vendored
Normal 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
96
deps/ox/src/ox/std/assert.hpp
vendored
Normal 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
217
deps/ox/src/ox/std/basestringview.hpp
vendored
Normal 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
23
deps/ox/src/ox/std/bit.cpp
vendored
Normal 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
61
deps/ox/src/ox/std/bit.hpp
vendored
Normal 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
138
deps/ox/src/ox/std/bounds.hpp
vendored
Normal 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
281
deps/ox/src/ox/std/bstring.hpp
vendored
Normal 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
20
deps/ox/src/ox/std/buffer.cpp
vendored
Normal 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
240
deps/ox/src/ox/std/buffer.hpp
vendored
Normal 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
46
deps/ox/src/ox/std/buildinfo.cpp
vendored
Normal 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
17
deps/ox/src/ox/std/buildinfo.hpp
vendored
Normal 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
58
deps/ox/src/ox/std/byteswap.cpp
vendored
Normal 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
211
deps/ox/src/ox/std/byteswap.hpp
vendored
Normal 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
23
deps/ox/src/ox/std/concepts.cpp
vendored
Normal 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
32
deps/ox/src/ox/std/concepts.hpp
vendored
Normal 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
53
deps/ox/src/ox/std/cstringview.hpp
vendored
Normal 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
145
deps/ox/src/ox/std/cstrops.hpp
vendored
Normal 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
86
deps/ox/src/ox/std/def.hpp
vendored
Normal 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
37
deps/ox/src/ox/std/defer.hpp
vendored
Normal 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
85
deps/ox/src/ox/std/defines.hpp
vendored
Normal 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
286
deps/ox/src/ox/std/error.hpp
vendored
Normal 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
74
deps/ox/src/ox/std/fmt.cpp
vendored
Normal 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
218
deps/ox/src/ox/std/fmt.hpp
vendored
Normal 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
38
deps/ox/src/ox/std/hardware.hpp
vendored
Normal 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
269
deps/ox/src/ox/std/hashmap.hpp
vendored
Normal 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
144
deps/ox/src/ox/std/heapmgr.cpp
vendored
Normal 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
36
deps/ox/src/ox/std/heapmgr.hpp
vendored
Normal 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
46
deps/ox/src/ox/std/initializerlist.hpp
vendored
Normal 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
165
deps/ox/src/ox/std/iterator.hpp
vendored
Normal 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
23
deps/ox/src/ox/std/math.cpp
vendored
Normal 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
61
deps/ox/src/ox/std/math.hpp
vendored
Normal 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
55
deps/ox/src/ox/std/memops.cpp
vendored
Normal 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
94
deps/ox/src/ox/std/memops.hpp
vendored
Normal 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
291
deps/ox/src/ox/std/memory.hpp
vendored
Normal 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
171
deps/ox/src/ox/std/new.hpp
vendored
Normal 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
170
deps/ox/src/ox/std/optional.hpp
vendored
Normal 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
195
deps/ox/src/ox/std/point.hpp
vendored
Normal 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
15
deps/ox/src/ox/std/random.cpp
vendored
Normal 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
53
deps/ox/src/ox/std/random.hpp
vendored
Normal 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
25
deps/ox/src/ox/std/range.hpp
vendored
Normal 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
35
deps/ox/src/ox/std/ranges.hpp
vendored
Normal 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
59
deps/ox/src/ox/std/reader.cpp
vendored
Normal 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
96
deps/ox/src/ox/std/reader.hpp
vendored
Normal 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
15
deps/ox/src/ox/std/realstd.hpp
vendored
Normal 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
95
deps/ox/src/ox/std/serialize.hpp
vendored
Normal 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
196
deps/ox/src/ox/std/size.hpp
vendored
Normal 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
241
deps/ox/src/ox/std/span.hpp
vendored
Normal 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
80
deps/ox/src/ox/std/stacktrace.cpp
vendored
Normal 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
20
deps/ox/src/ox/std/stacktrace.hpp
vendored
Normal 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
53
deps/ox/src/ox/std/std.hpp
vendored
Normal 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
39
deps/ox/src/ox/std/stddef.hpp
vendored
Normal 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
20
deps/ox/src/ox/std/string.cpp
vendored
Normal 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
583
deps/ox/src/ox/std/string.hpp
vendored
Normal 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
51
deps/ox/src/ox/std/stringliteral.hpp
vendored
Normal 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
20
deps/ox/src/ox/std/stringview.cpp
vendored
Normal 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
131
deps/ox/src/ox/std/stringview.hpp
vendored
Normal 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
308
deps/ox/src/ox/std/strongint.hpp
vendored
Normal 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
41
deps/ox/src/ox/std/strops.cpp
vendored
Normal 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
146
deps/ox/src/ox/std/strops.hpp
vendored
Normal 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
25
deps/ox/src/ox/std/substitutes.cpp
vendored
Normal 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
26
deps/ox/src/ox/std/test/CMakeLists.txt
vendored
Normal 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
327
deps/ox/src/ox/std/test/tests.cpp
vendored
Normal 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
43
deps/ox/src/ox/std/trace.cpp
vendored
Normal 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
290
deps/ox/src/ox/std/trace.hpp
vendored
Normal 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
102
deps/ox/src/ox/std/tracehook.cpp
vendored
Normal 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
34
deps/ox/src/ox/std/typeinfo.hpp
vendored
Normal 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
177
deps/ox/src/ox/std/types.hpp
vendored
Normal 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
25
deps/ox/src/ox/std/typetraits.cpp
vendored
Normal 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
313
deps/ox/src/ox/std/typetraits.hpp
vendored
Normal 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
20
deps/ox/src/ox/std/units.hpp
vendored
Normal 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
43
deps/ox/src/ox/std/utility.hpp
vendored
Normal 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
40
deps/ox/src/ox/std/uuid.cpp
vendored
Normal 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
191
deps/ox/src/ox/std/uuid.hpp
vendored
Normal 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
20
deps/ox/src/ox/std/vec.cpp
vendored
Normal 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
271
deps/ox/src/ox/std/vec.hpp
vendored
Normal 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
695
deps/ox/src/ox/std/vector.hpp
vendored
Normal 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
84
deps/ox/src/ox/std/writer.hpp
vendored
Normal 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;
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user