Squashed 'deps/nostalgia/' changes from 3c7652ef..161640fa

161640fa [nostalgia] Cleanup
e42126c9 [nostalgia/core] Improve TileSheet validation, add repair
36942cca [nostalgia,olympic] Replace SpanView with Span<const T>
b14f1d50 [ox] Replace SpanView with Span<const T>
1bf4f246 [applib] Make run take args as a SpanView
edda8e01 [ox/clargs] Add constructor that takes a SpanView
3308b4dd [ox/std] Add missing + and += operators to Span
27f4703a [teagba] Suppress warnings for unsafe buffers
6af00d9a [nostalgia] Enable warnings for unsafe buffers
86b9f931 [olympic] Enable warnings for unsafe buffers
a0ed1b3f [ox/std] Fix Span raw array constructor
8dad624b [studio/applib] Cleanup
dc6605fd [keel] Add missing error checking to pack
c78d3cf6 [ox] Add more unsafe buffer exceptions
cee4f65d [ox/std] Replace an unsafe buffer
cd3eeeef [ox/fs] Suppress unsafe buffer warnings
287d42f2 [ox/clargs] Cleanup
dbbaaa46 [ox/clargs] Enable unsafe buffer warnings
9b8a8c4e [ox/std] Enable unsafe buffer warnings
e44fa288 [cityhash] Add pragmas to ignore unsafe buffer warnings
e13c6e81 [ox/std] Remove raw char* CharBufferWriter constructor
cb55b31a [ox/std] Cleanup
ab3f9e16 [ox/std] Make Span access check message consistent with other messages
8f25ef96 [ox/std] Make CharBufferWriter constructor take a Span
e13eebaf [ox/std] Cleanup an unsafe buffer
114f5c66 [ox/std] Add overflow checking to SpanIterator
df44fe23 [keel] Cleanup
72f4db3d [nostalgia/core/studio] Fix paste command to never paste beyond target dimensions
8a9ff971 [nostalgia/core] Fix resizeSubsheet to work for both growing and shrinking
5a8da59d [keel] Fix readAsset to actually return asset
afa3a13d [keel] Cleanup
6522cf8a [keel] Add ensureValid call to readAsset
f772e48b [ox] Add Vector/Array/Span overflow checking
13bfe881 [nostalgia/core] Fix resizeSubsheet array overflow
50254754 Merge commit '9e11019b87ba27d1dac9e097dc212a126e404218'
bfe890ae [ox] Fix typo in docs
ab5bc1ad [ox/std] Remove oxRequireT and oxRequireMT
abf7548a [nostalgia/core] Add missing include
e2682b5e [studio/modlib] Add missing include
792ad414 [nostalgia] Remove .vs dir

git-subtree-dir: deps/nostalgia
git-subtree-split: 161640fa11986677dc2e1da6ffd4575e38ab31ad
This commit is contained in:
Gary Talent 2024-12-04 19:55:17 -06:00
parent 9e11019b87
commit 4ccdfc3a6e
101 changed files with 842 additions and 731 deletions

View File

@ -1,44 +0,0 @@
{
"version": "0.2.1",
"defaults": {},
"configurations": [
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "nostalgia.exe (Install)",
"name": "nostalgia.exe (Install)",
"args": [
"${projectDir}/sample_project"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "nostalgia.exe",
"name": "nostalgia.exe",
"args": [
"${projectDir}/sample_project"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "nostalgia-studio.exe (Install)",
"name": "nostalgia-studio.exe (Install)",
"args": [
"-profile",
"${projectDir}/src/nostalgia/studio/nostalgia-studio-dev.json"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "nostalgia-studio.exe",
"name": "nostalgia-studio.exe",
"args": [
"-profile",
"${projectDir}/src/nostalgia/studio/nostalgia-studio-dev.json"
]
}
]
}

View File

@ -104,6 +104,11 @@ using size_t = decltype(alignof(int));
#endif
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
#endif
namespace cityhash::detail {
template<typename T>
@ -671,4 +676,8 @@ constexpr uint128 CityHash128(const char *s, size_t len) noexcept {
}
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#endif // CITY_HASH_H_

10
deps/ox/ox-docs.md vendored
View File

@ -176,14 +176,10 @@ ox::Result<int> f2() noexcept {
```
```oxRequire``` is not quite as versatile, but it should still cleanup a lot of otherwise less ideal code.
```oxRequire``` also has variants for throwing the error and for making to value non-const:
```oxRequire``` by default creates a const, but there is also an ```oxRequireM``` (oxRequire Mutable)
variant for creating a non-const value.
* ```oxRequireM``` - oxRequire Mutable
* ```oxRequireT``` - oxRequire Throw
* ```oxRequireMT``` - oxRequire Mutable Throw
The throw variants of ```oxRequire``` are generally legacy code.
```ox::Result::unwrapThrow``` is generally preferred now.
### Logging and Output
@ -207,7 +203,7 @@ never be checked in.
```oxError``` always prints.
It includes file and line, and is prefixed with a red "ERROR:".
It should generally be used conservatively.
It shuld be used only when there is an error that is not technically fatal, but
It should be used only when there is an error that is not technically fatal, but
the user almost certainly wants to know about it.
```oxTrace``` and ```oxTracef```:

View File

@ -1,4 +1,9 @@
cmake_minimum_required(VERSION 3.10)
if(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang")
# enable warnings
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wunsafe-buffer-usage")
endif()
add_library(
OxClArgs

View File

@ -11,16 +11,18 @@
namespace ox {
ClArgs::ClArgs(int argc, const char **args) noexcept {
for (auto i = 0u; i < static_cast<unsigned>(argc); ++i) {
auto arg = String(args[i]);
ClArgs::ClArgs(int argc, const char **args) noexcept: ClArgs({args, static_cast<size_t>(argc)}) {}
ClArgs::ClArgs(ox::SpanView<const char*> args) noexcept {
for (auto i = 0u; i < args.size(); ++i) {
auto arg = StringView(args[i]);
if (arg[0] == '-') {
while (arg[0] == '-' && arg.len()) {
arg = arg.substr(1);
arg = substr(arg, 1);
}
m_bools[arg] = true;
// parse additional arguments
if (i < static_cast<unsigned>(argc) && args[i + 1]) {
if (i < args.size() && args[i + 1]) {
auto val = String(args[i + 1]);
if (val.len() && val[i] != '-') {
if (val == "false") {

View File

@ -9,6 +9,7 @@
#pragma once
#include <ox/std/hashmap.hpp>
#include <ox/std/span.hpp>
#include <ox/std/string.hpp>
namespace ox {
@ -22,6 +23,8 @@ class ClArgs {
public:
ClArgs(int argc, const char **args) noexcept;
ClArgs(ox::SpanView<const char*> args) noexcept;
[[nodiscard]]
bool getBool(ox::StringViewCR arg, bool defaultValue) const noexcept;

View File

@ -1,3 +1,7 @@
if(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang")
# enable warnings
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wunsafe-buffer-usage")
endif()
add_library(
OxFS

View File

@ -10,6 +10,8 @@
#include <ox/fs/ptrarith/nodebuffer.hpp>
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox {
using InodeId_t = uint64_t;
@ -771,3 +773,5 @@ using FileStore16 = FileStoreTemplate<uint16_t>;
using FileStore32 = FileStoreTemplate<uint32_t>;
}
OX_CLANG_NOWARN_END

View File

@ -15,6 +15,8 @@
#include "types.hpp"
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox {
template<typename InodeId_t>
@ -333,3 +335,5 @@ using Directory16 = Directory<FileStore16, uint16_t>;
using Directory32 = Directory<FileStore32, uint32_t>;
}
OX_CLANG_NOWARN_END

View File

@ -32,7 +32,9 @@ FileAddress::FileAddress(ox::StringViewCR path) noexcept {
auto pathSize = path.bytes();
m_data.path = new char[pathSize + 1];
memcpy(m_data.path, path.data(), pathSize);
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
m_data.path[pathSize] = 0;
OX_CLANG_NOWARN_END
m_type = FileAddressType::Path;
}

View File

@ -13,6 +13,8 @@
#include <ox/model/typenamecatcher.hpp>
#include <ox/model/types.hpp>
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox {
enum class FileAddressType: int8_t {
@ -180,3 +182,5 @@ constexpr Error model(T *h, CommonPtrWith<FileAddress> auto *fa) noexcept {
}
}
OX_CLANG_NOWARN_END

View File

@ -11,6 +11,8 @@
#include <ox/std/trace.hpp>
#include "pathiterator.hpp"
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox {
PathIterator::PathIterator(const char *path, std::size_t maxSize, std::size_t iterator) {
@ -30,7 +32,7 @@ PathIterator::PathIterator(StringViewCR path): PathIterator(path.data(), path.by
*/
Error PathIterator::dirPath(char *out, std::size_t outSize) {
const auto idx = ox::lastIndexOf(m_path, '/', m_maxSize);
const auto size = static_cast<std::size_t>(idx + 1);
const auto size = static_cast<std::size_t>(idx) + 1;
if (idx >= 0 && size < outSize) {
ox::memcpy(out, m_path, size);
out[size] = 0;
@ -183,3 +185,5 @@ const char *PathIterator::fullPath() const {
}
}
OX_CLANG_NOWARN_END

View File

@ -13,6 +13,8 @@
#include "ptr.hpp"
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox::ptrarith {
template<typename size_t, typename Item>
@ -449,3 +451,5 @@ struct OX_PACKED Item {
};
}
OX_CLANG_NOWARN_END

View File

@ -10,6 +10,8 @@
#include <ox/std/std.hpp>
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox::ptrarith {
template<typename T, typename size_t, size_t minOffset = 1>
@ -256,3 +258,5 @@ constexpr Result<Ptr<T, size_t, minOffset>> Ptr<T, size_t, minOffset>::validate(
}
}
OX_CLANG_NOWARN_END

View File

@ -226,13 +226,14 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
},
};
int main(int argc, const char **args) {
int main(int argc, const char **argv) {
if (argc < 2) {
oxError("Must specify test to run");
return -1;
}
auto const args = ox::Span{argv, static_cast<size_t>(argc)};
ox::StringView const testName = args[1];
ox::StringView const testArg = args[2] ? args[2] : nullptr;
ox::StringView const testArg = argc >= 3 ? args[2] : nullptr;
auto const func = tests.find(testName);
if (func != tests.end()) {
oxAssert(func->second(testArg), "Test returned Error");

View File

@ -39,25 +39,25 @@ static ox::Result<ox::UniquePtr<ox::FileSystem>> loadFs(const char *path) noexce
return {ox::make_unique<ox::FileSystem32>(buff.data, buff.size)};
}
static ox::Error runLs(ox::FileSystem *fs, int argc, const char **argv) noexcept {
if (argc < 2) {
static ox::Error runLs(ox::FileSystem *fs, ox::Span<const char*> args) noexcept {
if (args.size() < 2) {
oxErr("Must provide a directory to ls\n");
return OxError(1);
}
oxRequire(files, fs->ls(argv[1]));
oxRequire(files, fs->ls(args[1]));
for (const auto &file : files) {
oxOutf("{}\n", file);
}
return OxError(0);
}
static ox::Error runRead(ox::FileSystem *fs, int argc, const char **argv) noexcept {
if (argc < 2) {
static ox::Error runRead(ox::FileSystem *fs, ox::Span<const char*> args) noexcept {
if (args.size() < 2) {
oxErr("Must provide a path to a file to read\n");
return OxError(1);
}
oxRequire(buff, fs->read(ox::StringView(argv[1])));
fwrite(buff.data(), sizeof(decltype(buff)::value_type), buff.size(), stdout);
oxRequire(buff, fs->read(ox::StringView(args[1])));
std::ignore = fwrite(buff.data(), sizeof(decltype(buff)::value_type), buff.size(), stdout);
return OxError(0);
}
@ -66,13 +66,14 @@ static ox::Error run(int argc, const char **argv) noexcept {
oxErr("OxFS file and subcommand arguments are required\n");
return OxError(1);
}
const auto fsPath = argv[1];
ox::String subCmd(argv[2]);
auto const args = ox::Span{argv, static_cast<size_t>(argc)};
auto const fsPath = args[1];
ox::String subCmd(args[2]);
oxRequire(fs, loadFs(fsPath));
if (subCmd == "ls") {
return runLs(fs.get(), argc - 2, argv + 2);
return runLs(fs.get(), args + 2);
} else if (subCmd == "read") {
return runRead(fs.get(), argc - 2, argv + 2);
return runRead(fs.get(), args + 2);
}
return OxError(1);
}

View File

@ -45,6 +45,7 @@ class CirculerBuffer {
if (sz > avail()) {
return OxError(1, "Insufficient space in buffer");
}
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
// write seg 1
const auto seg1Sz = ox::min(sz, m_buff.size() - m_writePt);
ox::listcpy(&m_buff[m_writePt], &buff[0], seg1Sz);
@ -56,6 +57,7 @@ class CirculerBuffer {
ox::listcpy(&m_buff[0], &buff[seg1Sz], seg2Sz);
oxAssert(m_buff[0] == buff[seg1Sz], "break");
}
OX_ALLOW_UNSAFE_BUFFERS_END
return {};
}
@ -90,7 +92,9 @@ class CirculerBuffer {
m_readPt -= m_buff.size();
// read seg 2
const auto seg2Sz = bytesRead - seg1Sz;
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
ox::listcpy(&out[seg1Sz], &m_buff[0], seg2Sz);
OX_ALLOW_UNSAFE_BUFFERS_END
}
return bytesRead;
}

View File

@ -9,8 +9,8 @@
#ifdef OX_USE_STDLIB
#include <cstdio>
#include <sys/types.h>
#ifndef _WIN32
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
@ -25,15 +25,22 @@
#include "logconn.hpp"
#include <ox/std/bit.hpp>
namespace ox {
#ifdef _WIN32
using Socket = SOCKET;
using LenType = int;
#else
using Socket = int;
using LenType = size_t;
#endif
using namespace trace;
void closeSock(auto s) noexcept {
static void closeSock(auto s) noexcept {
#ifdef _WIN32
closesocket(s);
closesocket(static_cast<Socket>(s));
#else
close(s);
#endif
@ -56,8 +63,8 @@ ox::Error LoggerConn::initConn(ox::StringViewCR appName) noexcept {
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
addr.sin_port = htons(5590);
m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
oxReturnError(OxError(static_cast<ox::ErrorCode>(connect(m_socket, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)))));
m_socket = static_cast<int>(socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
oxReturnError(OxError(static_cast<ox::ErrorCode>(connect(static_cast<Socket>(m_socket), reinterpret_cast<sockaddr*>(&addr), sizeof(addr)))));
return sendInit({.appName = ox::BasicString<128>(appName)});
}
@ -65,9 +72,9 @@ ox::Error LoggerConn::send(const char *buff, std::size_t len) const noexcept {
std::size_t totalSent = 0;
while (totalSent < len) {
//std::fprintf(stdout, "Sending %lu/%lu bytes on socket %d\n", len, totalSent, m_socket);
const auto sent = ::send(m_socket, buff, len, 0);
const auto sent = ::send(static_cast<Socket>(m_socket), buff, static_cast<LenType>(len), 0);
if (sent < 0) {
std::fprintf(stderr, "Could not send msg\n");
std::ignore = std::fprintf(stderr, "Could not send msg\n");
return OxError(1, "Could not send msg");
}
totalSent += static_cast<std::size_t>(sent);
@ -90,13 +97,14 @@ void LoggerConn::msgSend() noexcept {
if (!m_running) {
break;
}
std::lock_guard buffLk(m_buffMut);
std::lock_guard const buffLk(m_buffMut);
while (true) {
ox::Array<char, ox::units::KB> tmp;
Array<char, units::KB> tmp;
const auto read = m_buff.read(tmp.data(), tmp.size());
if (!read) {
break;
}
oxAssert(read <= tmp.size(), "logger trying to read too much data");
//std::printf("LoggerConn: sending %lu bytes\n", read);
std::ignore = send(tmp.data(), read);
}

View File

@ -57,7 +57,7 @@ static_assert(highestBit(uint64_t(1) << 31) == 31);
static_assert(highestBit(uint64_t(1) << 63) == 63);
struct McInt {
uint8_t data[9] = {};
ox::Array<uint8_t, 9> data{};
// length of integer in bytes
std::size_t length = 0;
};
@ -104,7 +104,7 @@ constexpr McInt encodeInteger(I pInput) noexcept {
auto intermediate =
static_cast<uint64_t>(leVal.raw() | (negBit << (valBits - 1))) << bytes |
static_cast<uint64_t>(bytesIndicator);
ox::memcpy(out.data, &intermediate, sizeof(intermediate));
ox::memcpy(&out.data[0], &intermediate, sizeof(intermediate));
}
out.length = bytes;
}
@ -160,7 +160,7 @@ constexpr Result<I> decodeInteger(Reader_c auto&rdr, std::size_t *bytesRead) noe
ox::Array<uint32_t, 2> d = {};
//d[0] = decoded & 0xffff'ffff;
//d[1] = decoded >> 32;
ox::memcpy(d.data(), &decoded, sizeof(decoded));
ox::memcpy(&d[0], &decoded, sizeof(decoded));
auto bit = negBit;
for (; bit < ox::min<std::size_t>(Bits<I>, 32); ++bit) {
d[0] |= 1 << bit;
@ -175,7 +175,7 @@ constexpr Result<I> decodeInteger(Reader_c auto&rdr, std::size_t *bytesRead) noe
d[0] = d[1];
d[1] = d0Tmp;
}
ox::memcpy(&out, d.data(), sizeof(out));
ox::memcpy(&out, &d[0], sizeof(out));
return out;
}
}
@ -185,7 +185,7 @@ constexpr Result<I> decodeInteger(Reader_c auto&rdr, std::size_t *bytesRead) noe
template<typename I>
Result<I> decodeInteger(McInt m) noexcept {
std::size_t bytesRead{};
BufferReader br({reinterpret_cast<const char*>(m.data), 9});
BufferReader br({reinterpret_cast<const char*>(m.data.data()), 9});
return decodeInteger<I>(br, &bytesRead);
}

View File

@ -147,11 +147,13 @@ constexpr FieldBitmap::FieldBitmap(uint8_t *map, std::size_t maxLen) noexcept:
constexpr Error FieldBitmap::set(std::size_t i, bool on) noexcept {
if (i / 8 < m_mapLen) {
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
if (on) {
m_map[i / 8] |= 1 << (i % 8);
} else {
m_map[i / 8] &= ~static_cast<uint8_t>(1 << (i % 8));
}
OX_ALLOW_UNSAFE_BUFFERS_END
return {};
} else {
return OxError(McPresenceMapOverflow);

View File

@ -214,7 +214,9 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, auto *v
auto &handler = *reader.interface();
oxReturnError(handler.setTypeInfo("List", 0, {}, static_cast<std::size_t>(len)));
for (std::size_t i = 0; i < len; ++i) {
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
oxReturnError(handler.field({}, &val[i]));
OX_ALLOW_UNSAFE_BUFFERS_END
}
} else {
oxTracef("ox.mc.read.field(T)", "{}, length: {}", name, valLen);
@ -380,9 +382,9 @@ constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char
// re-allocate in case too small
safeDelete(*val);
*val = new char[size + 1];
auto data = *val;
auto data = ox::Span{*val, size + 1};
// read the string
oxReturnError(m_reader.read(data, size));
oxReturnError(m_reader.read(data.data(), size));
data[size] = 0;
}
++m_field;
@ -402,9 +404,9 @@ constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char
*val = new char[size + 1];
buffLen = size + 1;
}
auto data = *val;
auto data = ox::Span{*val, size + 1};
// read the string
oxReturnError(m_reader.read(data, size));
oxReturnError(m_reader.read(data.data(), size));
data[size] = 0;
} else {
auto data = *val;

View File

@ -117,7 +117,7 @@ class MetalClawWriter {
bool fieldSet = false;
if (val && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
auto mi = mc::encodeInteger(val);
oxReturnError(m_writer.write(reinterpret_cast<const char*>(mi.data), mi.length));
oxReturnError(m_writer.write(reinterpret_cast<const char*>(mi.data.data()), mi.length));
fieldSet = true;
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
@ -194,7 +194,7 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, const BasicString<Sm
if (val->len() && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
// write the length
const auto strLen = mc::encodeInteger(val->len());
oxReturnError(m_writer.write(reinterpret_cast<const char*>(strLen.data), strLen.length));
oxReturnError(m_writer.write(reinterpret_cast<const char*>(strLen.data.data()), strLen.length));
// write the string
oxReturnError(m_writer.write(val->c_str(), static_cast<std::size_t>(val->len())));
fieldSet = true;
@ -217,7 +217,7 @@ constexpr Error MetalClawWriter<Writer>::fieldCString(const char*, const char *c
const auto strLen = *val ? ox::strlen(*val) : 0;
// write the length
const auto strLenBuff = mc::encodeInteger(strLen);
oxReturnError(m_writer.write(reinterpret_cast<const char*>(strLenBuff.data), strLenBuff.length));
oxReturnError(m_writer.write(reinterpret_cast<const char*>(strLenBuff.data.data()), strLenBuff.length));
// write the string
oxReturnError(m_writer.write(*val, static_cast<std::size_t>(strLen)));
fieldSet = true;
@ -243,7 +243,7 @@ constexpr Error MetalClawWriter<Writer>::fieldCString(const char*, const char *v
if (strLen && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
// write the length
const auto strLenBuff = mc::encodeInteger(strLen);
oxReturnError(m_writer.write(reinterpret_cast<const char*>(strLenBuff.data), strLenBuff.length));
oxReturnError(m_writer.write(reinterpret_cast<const char*>(strLenBuff.data.data()), strLenBuff.length));
// write the string
oxReturnError(m_writer.write(val, static_cast<std::size_t>(strLen)));
fieldSet = true;
@ -298,14 +298,16 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, const T *val, std::s
if (len && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
// write the length
const auto arrLen = mc::encodeInteger(len);
oxReturnError(m_writer.write(reinterpret_cast<const char*>(arrLen.data), arrLen.length));
oxReturnError(m_writer.write(reinterpret_cast<const char*>(arrLen.data.data()), arrLen.length));
auto const writeIdx = m_writer.tellp();
MetalClawWriter<Writer> writer(m_writer);
ModelHandlerInterface handler{&writer};
oxReturnError(handler.template setTypeInfo<T>("List", 0, {}, static_cast<std::size_t>(len)));
// write the array
for (std::size_t i = 0; i < len; ++i) {
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
oxReturnError(handler.field("", &val[i]));
OX_ALLOW_UNSAFE_BUFFERS_END
}
oxReturnError(writer.finalize());
fieldSet = writeIdx != m_writer.tellp();
@ -324,7 +326,7 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, const HashMap<String
if (len && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
// write the length
const auto arrLen = mc::encodeInteger(len);
oxReturnError(m_writer.write(reinterpret_cast<const char*>(arrLen.data), arrLen.length));
oxReturnError(m_writer.write(reinterpret_cast<const char*>(arrLen.data.data()), arrLen.length));
// write map
MetalClawWriter<Writer> writer(m_writer);
ModelHandlerInterface handler{&writer};
@ -395,7 +397,7 @@ Result<Buffer> writeMC(auto const&val, std::size_t buffReserveSz = 2 * units::KB
}
Error writeMC(char *buff, std::size_t buffLen, auto const&val, std::size_t *sizeOut = nullptr) noexcept {
CharBuffWriter bw(buff, buffLen);
CharBuffWriter bw{{buff, buffLen}};
oxReturnError(writeMC(bw, val));
if (sizeOut) {
*sizeOut = bw.tellp();

View File

@ -90,7 +90,7 @@ constexpr Error model(T *io, CommonPtrWith<Subscript> auto *type) noexcept {
}
oxReturnError(io->field("length", &type->length));
oxReturnError(io->field("smallSzLen", &type->smallSzLen));
return OxError(0);
return {};
}
using SubscriptStack = Vector<Subscript, 3>;
@ -119,6 +119,7 @@ struct DescriptorField {
subscriptLevels(pSubscriptLevels),
subscriptStack(std::move(pSubscriptType)),
typeId(std::move(pTypeId)) {
oxAssert(subscriptLevels <= static_cast<int>(subscriptStack.size()), "Subscript level mismatch");
}
constexpr DescriptorField(const DescriptorField &other) noexcept:
@ -202,7 +203,7 @@ constexpr Error model(T *io, CommonPtrWith<DescriptorType> auto *type) noexcept
oxReturnError(io->field("fieldList", &type->fieldList));
oxReturnError(io->field("length", &type->length));
oxReturnError(io->field("preloadable", &type->preloadable));
return OxError(0);
return {};
}
template<typename T>
@ -215,7 +216,7 @@ constexpr Error model(T *io, CommonPtrWith<DescriptorField> auto *field) noexcep
// defaultValue is unused now, but leave placeholder for backwards compatibility
int defaultValue = 0;
oxReturnError(io->field("defaultValue", &defaultValue));
return OxError(0);
return {};
}
template<typename ReaderBase>

View File

@ -97,8 +97,14 @@ class TypeDescWriter {
std::size_t fields = ModelFieldCount_v<T>) noexcept;
template<typename T>
constexpr Error field(StringViewCR name, const T *val, std::size_t valLen,
const SubscriptStack &subscriptStack = {}) noexcept;
constexpr Error field(
StringViewCR name,
T const*val,
std::size_t valLen,
SubscriptStack const&subscriptStack) noexcept;
template<typename T>
constexpr Error field(StringViewCR name, T const*val, std::size_t valLen) noexcept;
template<typename T, bool force>
constexpr Error field(StringViewCR name, UnionView<T, force> val) noexcept;
@ -193,7 +199,7 @@ constexpr ox::Error TypeDescWriter::setTypeInfo(
// array handler
template<typename T>
constexpr Error TypeDescWriter::field(StringViewCR name, const T*, std::size_t, const SubscriptStack &subscriptStack) noexcept {
constexpr Error TypeDescWriter::field(StringViewCR name, T const*, std::size_t, SubscriptStack const&subscriptStack) noexcept {
if (m_type) {
constexpr typename remove_pointer<T>::type *p = nullptr;
const auto t = type(p);
@ -204,6 +210,21 @@ constexpr Error TypeDescWriter::field(StringViewCR name, const T*, std::size_t,
return OxError(1);
}
// array handler
template<typename T>
constexpr Error TypeDescWriter::field(StringViewCR name, T const*, std::size_t) noexcept {
if (m_type) {
constexpr typename remove_pointer<T>::type *p = nullptr;
const auto t = type(p);
oxAssert(t != nullptr, "field(const char *name, T *val, std::size_t): Type not found or generated");
auto const lvls = detail::indirectionLevels_v<T> + 1;
SubscriptStack subscriptStack{lvls};
m_type->fieldList.emplace_back(t, String(name), lvls, subscriptStack, buildTypeId(*t));
return OxError(0);
}
return OxError(1);
}
template<typename T, bool force>
constexpr Error TypeDescWriter::field(StringViewCR name, UnionView<T, force> val) noexcept {
if (m_type) {

View File

@ -188,8 +188,8 @@ class ModelValue {
constexpr Error setType(
DescriptorType const*type,
int subscriptLevels = 0,
SubscriptStack const& = {}) noexcept;
SubscriptStack const& = {},
int subscriptLevels = 0) noexcept;
template<typename T>
constexpr Error setType() noexcept;
@ -242,7 +242,7 @@ class ModelValueArray {
m_vec.resize(sz);
if (sz > oldSz) {
for (auto i = oldSz; i < sz; ++i) {
oxReturnError(m_vec[i].setType(m_type, m_typeSubscriptLevels));
oxReturnError(m_vec[i].setType(m_type, m_subscriptStack, m_typeSubscriptLevels));
}
}
return {};
@ -276,8 +276,9 @@ class ModelValueArray {
constexpr Error setType(
DescriptorType const*type,
int subscriptLevels,
SubscriptStack subscriptStack) noexcept {
SubscriptStack subscriptStack,
int subscriptLevels) noexcept {
oxAssert(subscriptLevels <= static_cast<int>(subscriptStack.size()), "subscript level mismatch");
m_type = type;
m_typeSubscriptLevels = subscriptLevels;
m_subscriptStack = std::move(subscriptStack);
@ -400,7 +401,7 @@ class ModelValueVector {
m_vec.resize(sz);
if (sz > oldSz) {
for (auto i = oldSz; i < sz; ++i) {
oxReturnError(m_vec[i].setType(m_type, m_typeSubscriptLevels, m_subscriptStack));
oxReturnError(m_vec[i].setType(m_type, m_subscriptStack, m_typeSubscriptLevels));
}
}
return {};
@ -418,8 +419,9 @@ class ModelValueVector {
constexpr Error setType(
DescriptorType const*type,
int subscriptLevels,
SubscriptStack subscriptStack) noexcept {
SubscriptStack subscriptStack,
int subscriptLevels) noexcept {
oxAssert(subscriptLevels <= static_cast<int>(subscriptStack.size()), "subscript level mismatch");
m_type = type;
m_typeSubscriptLevels = subscriptLevels;
m_subscriptStack = std::move(subscriptStack);
@ -674,11 +676,11 @@ class ModelObject {
for (const auto &f : type->fieldList) {
auto field = make_unique<Field>();
field->name = f.fieldName;
oxReturnError(field->value.setType(f.type, f.subscriptLevels, f.subscriptStack));
oxReturnError(field->value.setType(f.type, f.subscriptStack, f.subscriptLevels));
m_fields[field->name] = &field->value;
m_fieldsOrder.emplace_back(std::move(field));
}
return OxError(0);
return {};
}
};
@ -797,12 +799,12 @@ class ModelUnion {
auto field = make_unique<Field>();
field->name = f.fieldName;
field->idx = i;
oxReturnError(field->value.setType(f.type, f.subscriptLevels));
oxReturnError(field->value.setType(f.type, SubscriptStack{static_cast<size_t>(f.subscriptLevels)}, f.subscriptLevels));
m_fields[field->name] = field.get();
m_fieldsOrder.emplace_back(std::move(field));
++i;
}
return OxError(0);
return {};
}
[[nodiscard]]
@ -1076,20 +1078,21 @@ constexpr ModelValue::Type ModelValue::type() const noexcept {
constexpr Error ModelValue::setType(
const DescriptorType *type,
int subscriptLevels,
SubscriptStack const&subscriptStack) noexcept {
SubscriptStack const&subscriptStack,
int subscriptLevels) noexcept {
freeResources();
oxAssert(subscriptLevels <= static_cast<int>(subscriptStack.size()), "subscript level mismatch");
if (subscriptLevels) {
auto const&subscript = subscriptStack[subscriptStack.size() - static_cast<size_t>(subscriptLevels)];
if (subscript.subscriptType == Subscript::SubscriptType::InlineArray) {
m_type = Type::InlineArray;
m_data.array = new ModelValueArray;
oxReturnError(m_data.array->setType(type, subscriptLevels - 1, subscriptStack));
oxReturnError(m_data.array->setType(type, subscriptStack, subscriptLevels - 1));
oxReturnError(m_data.array->setSize(static_cast<size_t>(subscript.length)));
} else {
m_type = Type::Vector;
m_data.vec = new ModelValueVector;
oxReturnError(m_data.vec->setType(type, subscriptLevels - 1, subscriptStack));
oxReturnError(m_data.vec->setType(type, subscriptStack, subscriptLevels - 1));
}
return {};
} else if (type->typeName == types::Bool) {

View File

@ -244,7 +244,9 @@ Error OrganicClawReader::field(const char *key, T *val, std::size_t valLen) noex
OrganicClawReader r(srcVal);
ModelHandlerInterface handler{&r};
for (decltype(srcSize) i = 0; i < srcSize; ++i) {
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
oxReturnError(handler.field("", &val[i]));
OX_ALLOW_UNSAFE_BUFFERS_END
}
return OxError(0);
}
@ -272,7 +274,9 @@ Error readOC(BufferView buff, auto &val) noexcept {
Json::Value doc;
Json::CharReaderBuilder parserBuilder;
auto parser = UniquePtr<Json::CharReader>(parserBuilder.newCharReader());
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
if (!parser->parse(buff.data(), buff.data() + buff.size(), &doc, nullptr)) {
OX_ALLOW_UNSAFE_BUFFERS_END
return OxError(1, "Could not parse JSON");
}
OrganicClawReader reader(buff.data(), buff.size());

View File

@ -200,7 +200,9 @@ Error OrganicClawWriter::field(const char *key, const T *val, std::size_t len) n
OrganicClawWriter w((Json::Value(Json::arrayValue)));
ModelHandlerInterface<OrganicClawWriter, OpType::Write> handler{&w};
for (std::size_t i = 0; i < len; ++i) {
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
oxReturnError(handler.field({}, &val[i]));
OX_ALLOW_UNSAFE_BUFFERS_END
}
value(key) = w.m_json;
}

View File

@ -1,3 +1,9 @@
if(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang")
# enable warnings
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wunsafe-buffer-usage")
endif()
if(OX_USE_STDLIB AND OX_ENABLE_TRACEHOOK)
add_library(
OxTraceHook SHARED

View File

@ -8,6 +8,10 @@
#pragma once
#include "def.hpp"
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox {
template<typename It, typename T>
@ -41,3 +45,5 @@ constexpr OutIt copy_n(It in, Size cnt, OutIt out) {
}
}
OX_CLANG_NOWARN_END

View File

@ -9,6 +9,7 @@
#pragma once
#include "bit.hpp"
#include "def.hpp"
#include "error.hpp"
#include "initializerlist.hpp"
#include "iterator.hpp"
@ -17,6 +18,8 @@
#include "types.hpp"
#include "utility.hpp"
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox {
template<typename T, std::size_t ArraySize>
@ -35,6 +38,10 @@ class Array {
public:
constexpr Array() noexcept = default;
template<typename ...Args>
constexpr Array(Args ...list) noexcept: m_items{std::move(list)...} {
}
constexpr Array(std::initializer_list<T> list) noexcept;
constexpr Array(const Array &other);
@ -174,11 +181,13 @@ constexpr Array<T, ArraySize> &Array<T, ArraySize>::operator=(Array &&other) noe
template<typename T, std::size_t ArraySize>
constexpr T &Array<T, ArraySize>::operator[](std::size_t i) noexcept {
ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Array access overflow");
return m_items[i];
}
template<typename T, std::size_t ArraySize>
constexpr const T &Array<T, ArraySize>::operator[](std::size_t i) const noexcept {
ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Array access overflow");
return m_items[i];
}
@ -198,3 +207,5 @@ constexpr bool Array<T, ArraySize>::contains(const T &v) const {
}
}
OX_CLANG_NOWARN_END

View File

@ -6,6 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "fmt.hpp"
#include "stacktrace.hpp"
#include "trace.hpp"
@ -13,7 +14,7 @@
namespace ox {
void panic(const char *file, int line, const char *panicMsg, const Error &err) noexcept {
void panic(StringViewCR file, int line, StringViewCR 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);
@ -31,4 +32,40 @@ void panic(const char *file, int line, const char *panicMsg, const Error &err) n
#endif
}
void panic(const char *file, int line, const char *panicMsg, const Error &err) noexcept {
panic(StringView{file}, line, StringView{panicMsg}, err);
}
void assertFailFuncRuntime(StringViewCR file, int line, StringViewCR assertTxt, StringViewCR msg) noexcept {
#ifdef OX_USE_STDLIB
auto output = sfmt("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, msg);
output += genStackTrace(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
}
void assertFailFuncRuntime(StringViewCR file, int line, [[maybe_unused]] const Error &err, StringViewCR, StringViewCR assertMsg) noexcept {
#if defined(OX_USE_STDLIB)
auto msg = sfmt("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, assertMsg);
if (err.msg) {
msg += sfmt("\tError Message:\t{}\n", err.msg);
}
msg += sfmt("\tError Code:\t{}\n", static_cast<ErrorCode>(err));
if (err.file != nullptr) {
msg += sfmt("\tError Location:\t{}:{}\n", err.file, err.line);
}
msg += genStackTrace(2);
oxErr(msg);
oxTracef("assert", "Failed assert: {} [{}:{}]", assertMsg, file, line);
std::abort();
#else
constexprPanic(file, line, assertMsg);
#endif
}
}

View File

@ -32,19 +32,13 @@ constexpr void constexprPanic(StringViewCR file, int line, StringViewCR panicMsg
}
}
void assertFailFuncRuntime(StringViewCR file, int line, StringViewCR assertTxt, StringViewCR msg) noexcept;
void assertFailFuncRuntime(StringViewCR file, int line, const Error &err, StringViewCR, StringViewCR assertMsg) noexcept;
constexpr void assertFunc(StringViewCR file, int line, bool pass, [[maybe_unused]]StringViewCR assertTxt, [[maybe_unused]]StringViewCR msg) noexcept {
if (!pass) {
if (!std::is_constant_evaluated()) {
#ifdef OX_USE_STDLIB
auto output = sfmt("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, msg);
output += genStackTrace(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
assertFailFuncRuntime(file, line, assertTxt, msg);
} else {
while (true);
}
@ -54,22 +48,7 @@ constexpr void assertFunc(StringViewCR file, int line, bool pass, [[maybe_unused
constexpr void assertFunc(StringViewCR file, int line, const Error &err, StringViewCR, StringViewCR assertMsg) noexcept {
if (err) {
if (!std::is_constant_evaluated()) {
#if defined(OX_USE_STDLIB)
auto msg = sfmt("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, assertMsg);
if (err.msg) {
msg += sfmt("\tError Message:\t{}\n", err.msg);
}
msg += sfmt("\tError Code:\t{}\n", static_cast<ErrorCode>(err));
if (err.file != nullptr) {
msg += sfmt("\tError Location:\t{}:{}\n", err.file, err.line);
}
msg += genStackTrace(2);
oxErr(msg);
oxTracef("assert", "Failed assert: {} [{}:{}]", assertMsg, file, line);
std::abort();
#else
constexprPanic(file, line, assertMsg);
#endif
assertFailFuncRuntime(file, line, err, {}, assertMsg);
} else {
while (true);
}

View File

@ -9,9 +9,12 @@
#pragma once
#include "bit.hpp"
#include "def.hpp"
#include "cstrops.hpp"
#include "iterator.hpp"
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox::detail {
class BaseStringView {
@ -202,7 +205,7 @@ class BaseStringView {
}
[[nodiscard]]
constexpr auto operator[](std::size_t i) const noexcept {
constexpr auto &operator[](std::size_t i) const noexcept {
return m_str[i];
}
@ -215,3 +218,5 @@ class BaseStringView {
};
}
OX_CLANG_NOWARN_END

View File

@ -14,12 +14,14 @@
#include "vector.hpp"
#include "writer.hpp"
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox {
extern template class Vector<char>;
using Buffer = Vector<char>;
using BufferView = SpanView<char>;
using BufferView = Span<const char>;
class BufferWriter {
private:
@ -100,15 +102,11 @@ class CharBuffWriter {
char *m_buff = nullptr;
public:
template<std::size_t sz>
explicit constexpr CharBuffWriter(ox::Array<char, sz> &buff) noexcept:
explicit constexpr CharBuffWriter(ox::Span<char> 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 {};
@ -237,3 +235,5 @@ extern template class WriterT<BufferWriter>;
extern template class WriterT<CharBuffWriter>;
}
OX_CLANG_NOWARN_END

View File

@ -8,9 +8,12 @@
#pragma once
#include "def.hpp"
#include "types.hpp"
#include "typetraits.hpp"
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox {
template<typename T1, typename T2>
@ -113,3 +116,5 @@ constexpr int lastIndexOf(const auto &str, int character, std::size_t maxLen = 0
}
}
OX_CLANG_NOWARN_END

View File

@ -44,10 +44,6 @@
// 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
@ -75,6 +71,21 @@ constexpr void oxAssert(const ox::Error&, const char*) noexcept {}
#define ox_alloca(size) __builtin_alloca(size)
#endif
#define OX_PRAGMA(x) _Pragma(#x)
#ifdef __clang__
#define OX_CLANG_NOWARN_BEGIN(warnoption) \
OX_PRAGMA(clang diagnostic push) \
OX_PRAGMA(clang diagnostic ignored #warnoption)
#define OX_CLANG_NOWARN_END OX_PRAGMA(clang diagnostic pop)
#define OX_ALLOW_UNSAFE_BUFFERS_BEGIN OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
#define OX_ALLOW_UNSAFE_BUFFERS_END OX_CLANG_NOWARN_END
#else
#define OX_CLANG_NOWARN_BEGIN(warnoption)
#define OX_CLANG_NOWARN_END
#define OX_ALLOW_UNSAFE_BUFFERS_BEGIN
#define OX_ALLOW_UNSAFE_BUFFERS_END
#endif
/**
* @return an ox::MallocaPtr of the given type pointing to the requested size memory allocation
*/

View File

@ -24,6 +24,7 @@ class exception {
}
#endif
#include "defines.hpp"
#include "def.hpp"
#include "typetraits.hpp"
#include "utility.hpp"
@ -332,4 +333,12 @@ constexpr Error toError(const Result<T> &r) noexcept {
}
constexpr void primitiveAssert(const char *file, int line, bool pass, const char *msg) noexcept {
if constexpr(ox::defines::Debug) {
if (!pass) [[unlikely]] {
panic(file, line, msg, OxError(1));
}
}
}
}

View File

@ -25,6 +25,8 @@
#include "types.hpp"
#include "typetraits.hpp"
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox {
namespace detail {
@ -81,16 +83,16 @@ class FmtArg {
private:
static constexpr auto DataSz = 23;
char dataStr[DataSz] = {};
ox::Array<char, DataSz> dataStr{};
template<typename T>
constexpr StringView sv(const T &v, char *dataStr) noexcept {
constexpr StringView sv(const T &v, ox::Span<char> dataStr) noexcept {
if constexpr(is_bool_v<T>) {
return v ? "true" : "false";
} else if constexpr(is_integer_v<T>) {
ox::CharBuffWriter w(dataStr, DataSz);
ox::CharBuffWriter w{dataStr};
std::ignore = ox::writeItoa(v, w);
return dataStr;
return dataStr.data();
} else {
return toStringView(v);
}
@ -225,3 +227,5 @@ constexpr Result<T> join(auto const&d, auto const&list) {
}
}
OX_CLANG_NOWARN_END

View File

@ -8,8 +8,11 @@
#include "assert.hpp"
#include "bit.hpp"
#include "def.hpp"
#include "heapmgr.hpp"
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox::heapmgr {
static struct HeapSegment *volatile g_heapBegin = nullptr;
@ -142,3 +145,5 @@ void operator delete[](void *ptr, unsigned long int) noexcept {
}
#endif
OX_CLANG_NOWARN_END

View File

@ -10,6 +10,7 @@
#include "array.hpp"
#include "concepts.hpp"
#include "def.hpp"
#include "cstrops.hpp"
#include "memops.hpp"
#include "error.hpp"
@ -175,7 +176,9 @@ constexpr Error IString<StrCap>::append(const char *str, std::size_t strLen) noe
strLen = cap() - currentLen;
err = OxError(1, "Insufficient space for full string");
}
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
ox::strncpy(m_buff.data() + currentLen, str, strLen);
OX_CLANG_NOWARN_END
// make sure last element is a null terminator
m_buff[currentLen + strLen] = 0;
m_size += strLen;
@ -263,7 +266,7 @@ constexpr auto itoa(Integer v) noexcept {
}();
ox::IString<Cap> out;
std::ignore = out.resize(out.cap());
ox::CharBuffWriter w(out.data(), out.cap());
ox::CharBuffWriter w{{out.data(), out.cap()}};
std::ignore = writeItoa(v, w);
std::ignore = out.resize(w.tellp());
return out;

View File

@ -8,6 +8,8 @@
#pragma once
#include "def.hpp"
#include "error.hpp"
#include "math.hpp"
#if !__has_include(<iterator>)
@ -38,6 +40,8 @@ struct contiguous_iterator_tag: public random_access_iterator_tag {
#include <iterator>
#endif
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox {
template<typename Category, typename T, typename DiffType = std::ptrdiff_t,
@ -129,14 +133,17 @@ struct SpanIterator {
}
constexpr PtrType operator->() const noexcept {
ox::primitiveAssert(__FILE__, __LINE__, m_offset < m_max, "SpanIterator access overflow");
return &m_t[m_offset];
}
constexpr RefType operator*() const noexcept {
ox::primitiveAssert(__FILE__, __LINE__, m_offset < m_max, "SpanIterator access overflow");
return m_t[m_offset];
}
constexpr RefType operator[](std::size_t s) const noexcept {
ox::primitiveAssert(__FILE__, __LINE__, s < m_max, "SpanIterator access overflow");
return m_t[s];
}
@ -167,3 +174,5 @@ struct SpanIterator {
};
}
OX_CLANG_NOWARN_END

View File

@ -10,6 +10,8 @@
#include "types.hpp"
#include "memops.hpp"
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
#ifndef OX_USE_STDLIB
#define ox_inhibit_loop_to_libcall __attribute__((__optimize__("-fno-tree-loop-distribute-patterns")))
@ -96,3 +98,5 @@ int memcmp(const void *ptr1, const void *ptr2, std::size_t size) noexcept {
}
}
OX_CLANG_NOWARN_END

View File

@ -8,6 +8,7 @@
#pragma once
#include "def.hpp"
#include "types.hpp"
#include "typetraits.hpp"
@ -27,6 +28,8 @@ int memcmp(const void *ptr1, const void *ptr2, std::size_t size) noexcept;
}
#endif
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox {
template<typename T1, typename T2>
@ -56,3 +59,5 @@ void *memsetElements(T *ptr, T val, std::size_t elements) noexcept {
}
}
OX_CLANG_NOWARN_END

View File

@ -8,11 +8,7 @@
#pragma once
#include "bit.hpp"
#include "initializerlist.hpp"
#include "iterator.hpp"
#include "memory.hpp"
#include "new.hpp"
#include "types.hpp"
#include "utility.hpp"

View File

@ -9,9 +9,12 @@
#pragma once
#include "bit.hpp"
#include "def.hpp"
#include "stddef.hpp"
#include "types.hpp"
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox {
using RandomSeed = uint64_t[2];
@ -51,3 +54,5 @@ constexpr uint64_t Random::gen() noexcept {
}
}
OX_CLANG_NOWARN_END

View File

@ -10,135 +10,21 @@
#include "array.hpp"
#include "bit.hpp"
#include "def.hpp"
#include "iterator.hpp"
#include "vector.hpp"
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox {
template<typename T>
class SpanView {
private:
T const*m_items{};
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];
}
constexpr SpanView operator+(size_t i) const noexcept {
return {m_items + i, m_size - i};
}
constexpr SpanView operator+=(size_t i) noexcept {
m_items += i;
m_size -= i;
return *this;
}
[[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{};
std::size_t m_size{};
public:
using value_type = T;
@ -147,20 +33,34 @@ class Span {
template<typename RefType = T&, typename PtrType = T*, bool reverse = false>
using iterator = SpanIterator<T, RefType, PtrType, reverse>;
constexpr Span() noexcept = default;
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>
constexpr Span(ox::Array<ox::remove_const_t<T>, sz> const&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, typename Allocator>
constexpr Span(ox::Vector<ox::remove_const_t<T>, sz, Allocator> const&v) noexcept:
m_items(v.data()),
m_size(v.size()) {
}
template<std::size_t sz>
constexpr Span(T a[sz]) noexcept:
constexpr Span(T (&a)[sz]) noexcept:
m_items(a),
m_size(sz) {
}
@ -229,13 +129,27 @@ class Span {
}
constexpr T &operator[](std::size_t i) noexcept {
ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Span access overflow");
return m_items[i];
}
constexpr const T &operator[](std::size_t i) const noexcept {
ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Span access overflow");
return m_items[i];
}
constexpr Span operator+(size_t i) const noexcept {
ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Span access overflow");
return {m_items + i, m_size - i};
}
constexpr Span operator+=(size_t i) noexcept {
ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Span access overflow");
m_items += i;
m_size -= i;
return *this;
}
[[nodiscard]]
constexpr auto data() const noexcept {
return m_items;
@ -253,4 +167,9 @@ class Span {
};
template<typename T>
using SpanView = Span<const T>;
}
OX_CLANG_NOWARN_END

View File

@ -18,11 +18,14 @@
#endif
#endif
#include "def.hpp"
#include "defines.hpp"
#include "string.hpp"
#include "trace.hpp"
#include "vector.hpp"
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox {
#if defined(OX_USE_STDLIB) && __has_include(<unistd.h>)
@ -100,3 +103,5 @@ void printStackTrace([[maybe_unused]]unsigned shave) noexcept {
}
}
OX_CLANG_NOWARN_END

View File

@ -13,6 +13,7 @@
#endif
#include "algorithm.hpp"
#include "def.hpp"
#include "ignore.hpp"
#include "memops.hpp"
#include "serialize.hpp"
@ -22,6 +23,8 @@
#include "strops.hpp"
#include "vector.hpp"
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox {
template<typename Integer>
@ -496,12 +499,12 @@ constexpr char &BasicString<SmallStringSize_v>::operator[](std::size_t i) noexce
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 - 1);
return BasicString(&m_buff[pos], m_buff.size() - pos - 1);
}
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 src = &m_buff[begin];
const auto size = end - begin;
BasicString<SmallStringSize_v> out(size);
const auto buff = out.data();
@ -568,3 +571,5 @@ struct MaybeView<ox::BasicString<sz>> {
};
}
OX_CLANG_NOWARN_END

View File

@ -17,6 +17,8 @@
#include "maybeview.hpp"
#include "writer.hpp"
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox {
template<std::size_t buffLen>
@ -116,3 +118,4 @@ constexpr ox::Result<int> atoi(ox::StringViewCR str) noexcept {
}
OX_CLANG_NOWARN_END

View File

@ -6,6 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "def.hpp"
#include "strops.hpp"
static_assert(ox::strcmp("asdf", "hijk") < 0, "asdf < hijk");
@ -17,7 +18,9 @@ static_assert(ox::strcmp("", "") == 0, "\"\" == \"\"");
static_assert([] {
auto testStr = "asdf";
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
return ox::strchr(testStr, 0, 4) == &testStr[4];
OX_CLANG_NOWARN_END
}(), "ox::strchr 0");
static_assert([] {

View File

@ -9,18 +9,21 @@
#pragma once
#include "cstrops.hpp"
#include "def.hpp"
#include "error.hpp"
#include "math.hpp"
#include "stringview.hpp"
#include "types.hpp"
#include "vector.hpp"
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox {
[[nodiscard]]
constexpr ox::StringView substr(ox::StringView const&str, std::size_t pos) noexcept {
if (str.len() >= pos) {
return {str.data() + pos, str.len() - pos};
return {&str[pos], str.len() - pos};
}
return {};
}
@ -28,7 +31,7 @@ constexpr ox::StringView substr(ox::StringView const&str, std::size_t pos) noexc
[[nodiscard]]
constexpr ox::StringView substr(ox::StringView const&str, std::size_t start, std::size_t end) noexcept {
if (str.len() >= start && end >= start) {
return {str.data() + start, end - start};
return {&str[start], end - start};
}
return {};
}
@ -113,3 +116,5 @@ constexpr ox::Result<std::size_t> lastIndexOf(ox::StringViewCR str, int characte
}
}
OX_CLANG_NOWARN_END

View File

@ -121,7 +121,9 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
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");
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
oxAssert(a2 >= buff.front().unwrap() && a2 < buff.back().unwrap() && a2 > a1 + 5, "malloc is broken");
OX_CLANG_NOWARN_END
ox::heapmgr::free(a1);
ox::heapmgr::free(a2);
return OxError(0);
@ -470,10 +472,12 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
},
};
int main(int argc, const char **args) {
int main(int argc, const char **argv) {
if (argc < 2) {
oxError("Must specify test to run");
return -1;
}
auto const args = ox::Span{argv, static_cast<size_t>(argc)};
auto const testName = args[1];
auto const func = tests.find(testName);
if (func != tests.end()) {

View File

@ -10,6 +10,17 @@
namespace ox::trace {
static class: public Logger {
public:
ox::Error send(const TraceMsg&) noexcept final {
return {};
}
ox::Error sendInit(const InitTraceMsg&) noexcept final {
return {};
}
} defaultLogger;
static Logger *logger = &defaultLogger;
void init() {
oxTraceInitHook();
}
@ -19,19 +30,6 @@ void init(Logger *logger) {
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;
}

View File

@ -173,7 +173,7 @@ class OutStream {
return *this;
}
constexpr OutStream &operator<<(const char *v) noexcept {
constexpr OutStream &operator<<(StringViewCR v) noexcept {
if (m_msg.msg.len()) {
m_msg.msg += m_delimiter;
}
@ -181,6 +181,10 @@ class OutStream {
return *this;
}
constexpr OutStream &operator<<(const char *v) noexcept {
return operator<<(StringView{v});
}
template<std::size_t sz>
constexpr OutStream &operator<<(const IString<sz> &v) noexcept {
return operator<<(v.c_str());

View File

@ -269,6 +269,41 @@ template<class T>
constexpr bool is_move_constructible_v = detail::is_move_constructible<T>(0);
template<typename T>
struct remove_cv {
using type = T;
};
template<typename T>
struct remove_cv<const T> {
using type = T;
};
template<typename T>
struct remove_cv<volatile T> {
using type = T;
};
template<typename T>
struct remove_cv<const volatile T> {
using type = T;
};
template<typename T>
struct remove_const {
using type = T;
};
template<typename T>
struct remove_const<const T> {
using type = T;
};
template<typename T>
using remove_const_t = typename remove_const<T>::type;
// is String?
template<std::size_t SmallStringSize>

View File

@ -9,6 +9,7 @@
#pragma once
#include "bit.hpp"
#include "def.hpp"
#include "ignore.hpp"
#include "istring.hpp"
#include "buffer.hpp"
@ -18,6 +19,8 @@
#include "stringview.hpp"
#include "strops.hpp"
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox {
using UUIDStr = ox::IString<36>;
@ -107,12 +110,12 @@ class UUID {
static ox::Result<UUID> generate() noexcept;
[[nodiscard]]
constexpr auto const&value() const noexcept {
constexpr ox::Array<uint8_t, 16> const&value() const noexcept {
return m_value;
}
[[nodiscard]]
constexpr auto isNull() const noexcept {
constexpr bool 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;
@ -187,7 +190,7 @@ class UUID {
constexpr UUIDStr toString() const noexcept {
UUIDStr out;
std::ignore = out.resize(UUIDStr::cap());
ox::CharBuffWriter bw(out.data(), UUIDStr::cap());
ox::CharBuffWriter bw{{out.data(), UUIDStr::cap()}};
std::ignore = toString(bw);
out[UUIDStr::cap()] = 0;
return out;
@ -220,3 +223,5 @@ constexpr Error model(T *io, ox::CommonPtrWith<UUID> auto *obj) noexcept {
}
}
OX_CLANG_NOWARN_END

View File

@ -14,7 +14,7 @@ namespace ox {
static_assert([] {
Vec2 v(1, 2);
return v.x == 1 && v.y == 2 && v[0] == 1 && v[1] == 2 && v.size() == 2;
return v.x == 1 && v.y == 2 && v.size() == 2;
}());
}

View File

@ -34,112 +34,6 @@ class Vec2 {
float x = 0;
float 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 Vec2() noexcept = default;
explicit constexpr Vec2(class Point const&pt) noexcept;
@ -159,85 +53,8 @@ class Vec2 {
}
#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 Vec2 &v) const noexcept {
for (auto i = 0u; i < v.size(); ++i) {
if ((*this)[i] != v[i]) {
return false;
}
}
return true;
return x == v.x && y == v.y;
}
constexpr auto operator!=(const Vec2 &v) const noexcept {
@ -292,17 +109,6 @@ class Vec2 {
y /= i;
return *this;
}
protected:
[[nodiscard]]
constexpr float *start() noexcept {
return&x;
}
[[nodiscard]]
constexpr const float *start() const noexcept {
return &x;
}
};
template<typename T>

View File

@ -20,6 +20,8 @@
#include "types.hpp"
#include "utility.hpp"
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
namespace ox {
namespace detail {
@ -422,11 +424,13 @@ constexpr Vector<T, SmallVectorSize, Allocator> &Vector<T, SmallVectorSize, Allo
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr T &Vector<T, SmallVectorSize, Allocator>::operator[](std::size_t i) noexcept {
ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Vector access overflow");
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 {
ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Vector access overflow");
return m_items[i];
}
@ -707,3 +711,5 @@ constexpr auto alignOf(const Vector<T>&) noexcept {
}
}
OX_ALLOW_UNSAFE_BUFFERS_END

View File

@ -6,6 +6,8 @@
#include "addresses.hpp"
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
namespace teagba {
inline auto bgSetSbb(volatile BgCtl &bgCtl, unsigned sbb) noexcept {
@ -53,3 +55,5 @@ constexpr void iterateBgCtl(auto cb) noexcept {
}
}
OX_ALLOW_UNSAFE_BUFFERS_END

View File

@ -1,4 +1,9 @@
if(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang")
# enable warnings
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wunsafe-buffer-usage")
endif()
project(nostalgia CXX)
#project packages

View File

@ -121,11 +121,20 @@ ox::Error loadSpritePalette(
CompactPalette const&palette,
size_t page = 0) noexcept;
ox::Error loadBgPalette(
Context &ctx,
size_t palBank,
ox::StringViewCR palettePath) noexcept;
ox::Error loadBgPalette(
Context &ctx,
size_t palBank,
ox::FileAddress const&paletteAddr) noexcept;
ox::Error loadSpritePalette(
Context &ctx,
ox::StringViewCR palettePath) noexcept;
ox::Error loadSpritePalette(
Context &ctx,
ox::FileAddress const&paletteAddr) noexcept;
@ -143,6 +152,14 @@ ox::Error loadBgTileSheet(
size_t srcTileIdx,
size_t tileCnt) noexcept;
ox::Error loadBgTileSheet(
Context &ctx,
unsigned cbb,
ox::StringViewCR tsPath,
size_t dstTileIdx,
size_t srcTileIdx,
size_t tileCnt) noexcept;
ox::Error loadBgTileSheet(
Context &ctx,
unsigned cbb,
@ -157,6 +174,12 @@ ox::Error loadBgTileSheet(
CompactTileSheet const&ts,
ox::Optional<unsigned> const&paletteBank = {}) noexcept;
ox::Error loadBgTileSheet(
Context &ctx,
unsigned cbb,
ox::StringViewCR tilesheetPath,
ox::Optional<unsigned> const&paletteBank) noexcept;
ox::Error loadBgTileSheet(
Context &ctx,
unsigned cbb,
@ -168,6 +191,11 @@ ox::Error loadSpriteTileSheet(
CompactTileSheet const&ts,
bool loadDefaultPalette) noexcept;
ox::Error loadSpriteTileSheet(
Context &ctx,
ox::StringViewCR tilesheetPath,
bool loadDefaultPalette = false) noexcept;
ox::Error loadSpriteTileSheet(
Context &ctx,
ox::FileAddress const&tilesheetAddr,

View File

@ -4,6 +4,8 @@
#pragma once
#include <ox/std/types.hpp>
namespace nostalgia::core {
struct InitParams {

View File

@ -33,7 +33,14 @@ struct TileSheetV1 {
[[nodiscard]]
constexpr bool valid(TileSheetV1 const&ts) noexcept {
return ts.bpp == 4 || ts.bpp == 8;
auto const bytes = static_cast<size_t>(ts.columns * ts.rows * PixelsPerTile) / (ts.bpp == 4 ? 2 : 1);
return (ts.bpp == 4 || ts.bpp == 8) && ts.pixels.size() == bytes;
}
constexpr ox::Error repair(TileSheetV1 &ts, int bpp) noexcept {
auto const bytes = static_cast<size_t>(ts.columns * ts.rows * PixelsPerTile) / (bpp == 4 ? 2 : 1);
ts.pixels.resize(bytes);
return {};
}
@ -65,9 +72,34 @@ struct TileSheetV2 {
};
[[nodiscard]]
constexpr bool valid(TileSheetV2::SubSheet const&ss, int bpp) noexcept {
auto const bytes = static_cast<size_t>(ss.columns * ss.rows * PixelsPerTile) / (bpp == 4 ? 2 : 1);
return ox::all_of(ss.subsheets.begin(), ss.subsheets.end(),
[bpp, bytes](TileSheetV2::SubSheet const&s) {
return bytes == s.pixels.size() && valid(s, bpp);
});
}
[[nodiscard]]
constexpr bool valid(TileSheetV2 const&ts) noexcept {
return ts.bpp == 4 || ts.bpp == 8;
return (ts.bpp == 4 || ts.bpp == 8) && valid(ts.subsheet, ts.bpp);
}
constexpr void repair(TileSheetV2::SubSheet &ss, int bpp) noexcept {
auto const bytes = static_cast<size_t>(ss.columns * ss.rows * PixelsPerTile) / (bpp == 4 ? 2 : 1);
ss.pixels.resize(bytes);
for (auto &s : ss.subsheets) {
repair(s, bpp);
}
}
constexpr ox::Error repair(TileSheetV2 &ts) noexcept {
if (ts.bpp != 4 && ts.bpp != 8) {
return OxError(1, "Unable to repair TileSheet");
}
repair(ts.subsheet, ts.bpp);
return {};
}
@ -110,9 +142,34 @@ struct TileSheetV3 {
};
[[nodiscard]]
constexpr bool valid(TileSheetV3::SubSheet const&ss, int bpp) noexcept {
auto const bytes = static_cast<size_t>(ss.columns * ss.rows * PixelsPerTile) / (bpp == 4 ? 2 : 1);
return ox::all_of(ss.subsheets.begin(), ss.subsheets.end(),
[bpp, bytes](TileSheetV3::SubSheet const&s) {
return bytes == s.pixels.size() && valid(s, bpp);
});
}
[[nodiscard]]
constexpr bool valid(TileSheetV3 const&ts) noexcept {
return ts.bpp == 4 || ts.bpp == 8;
return (ts.bpp == 4 || ts.bpp == 8) && valid(ts.subsheet, ts.bpp);
}
constexpr void repair(TileSheetV3::SubSheet &ss, int bpp) noexcept {
auto const bytes = static_cast<size_t>(ss.columns * ss.rows * PixelsPerTile) / (bpp == 4 ? 2 : 1);
ss.pixels.resize(bytes);
for (auto &s : ss.subsheets) {
repair(s, bpp);
}
}
constexpr ox::Error repair(TileSheetV3 &ts) noexcept {
if (ts.bpp != 4 && ts.bpp != 8) {
return OxError(1, "Unable to repair TileSheet");
}
repair(ts.subsheet, ts.bpp);
return {};
}
@ -173,9 +230,34 @@ struct TileSheetV4 {
};
[[nodiscard]]
constexpr bool valid(TileSheetV4::SubSheet const&ss, int bpp) noexcept {
auto const bytes = static_cast<size_t>(ss.columns * ss.rows * PixelsPerTile) / (bpp == 4 ? 2 : 1);
return ox::all_of(ss.subsheets.begin(), ss.subsheets.end(),
[bpp, bytes](TileSheetV4::SubSheet const&s) {
return bytes == s.pixels.size() && valid(s, bpp);
});
}
[[nodiscard]]
constexpr bool valid(TileSheetV4 const&ts) noexcept {
return ts.bpp == 4 || ts.bpp == 8;
return (ts.bpp == 4 || ts.bpp == 8) && valid(ts.subsheet, ts.bpp);
}
constexpr void repair(TileSheetV4::SubSheet &ss, int bpp) noexcept {
auto const bytes = static_cast<size_t>(ss.columns * ss.rows * PixelsPerTile) / (bpp == 4 ? 2 : 1);
ss.pixels.resize(bytes);
for (auto &s : ss.subsheets) {
repair(s, bpp);
}
}
constexpr ox::Error repair(TileSheetV4 &ts) noexcept {
if (ts.bpp != 4 && ts.bpp != 8) {
return OxError(1, "Unable to repair TileSheet");
}
repair(ts.subsheet, ts.bpp);
return {};
}

View File

@ -17,6 +17,8 @@
#include "context.hpp"
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
namespace nostalgia::core {
static constexpr auto SpriteCount = 128;
@ -283,3 +285,5 @@ uint_t spriteCount(Context&) noexcept {
}
}
OX_ALLOW_UNSAFE_BUFFERS_END

View File

@ -25,7 +25,9 @@ using namespace nostalgia::core;
void panic(const char *file, int line, const char *panicMsg, ox::Error const&err) noexcept {
// reset heap to make sure we have enough memory to allocate context data
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
ox::heapmgr::initHeap(HEAP_BEGIN, HEAP_END);
OX_ALLOW_UNSAFE_BUFFERS_END
auto tctx = turbine::init(keel::loadRomFs("").unwrap(), "Nostalgia").unwrap();
auto ctx = init(*tctx).unwrap();
std::ignore = initGfx(*ctx, {});

View File

@ -18,6 +18,14 @@ int tileRows(Context&) noexcept {
return GbaTileRows;
}
ox::Error loadBgPalette(
Context &ctx,
size_t palBank,
ox::StringViewCR palettePath) noexcept {
oxRequire(pal, keel::readObj<CompactPalette>(keelCtx(ctx), palettePath));
return loadBgPalette(ctx, palBank, *pal, 0);
}
ox::Error loadBgPalette(
Context &ctx,
size_t palBank,
@ -26,6 +34,13 @@ ox::Error loadBgPalette(
return loadBgPalette(ctx, palBank, *pal, 0);
}
ox::Error loadSpritePalette(
Context &ctx,
ox::StringViewCR palettePath) noexcept {
oxRequire(pal, keel::readObj<CompactPalette>(keelCtx(ctx), palettePath));
return loadSpritePalette(ctx, *pal, 0);
}
ox::Error loadSpritePalette(
Context &ctx,
ox::FileAddress const&paletteAddr) noexcept {
@ -44,6 +59,26 @@ ox::Error loadBgTileSheet(
return loadBgTileSheet(ctx, cbb, *ts, dstTileIdx, srcTileIdx, tileCnt);
}
ox::Error loadBgTileSheet(
Context &ctx,
unsigned cbb,
ox::StringViewCR tsPath,
size_t dstTileIdx,
size_t srcTileIdx,
size_t tileCnt) noexcept {
oxRequire(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), tsPath));
return loadBgTileSheet(ctx, cbb, *ts, dstTileIdx, srcTileIdx, tileCnt);
}
ox::Error loadBgTileSheet(
Context &ctx,
unsigned cbb,
ox::StringViewCR tilesheetPath,
ox::Optional<unsigned> const&paletteBank) noexcept {
oxRequire(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), tilesheetPath));
return loadBgTileSheet(ctx, cbb, *ts, paletteBank);
}
ox::Error loadBgTileSheet(
Context &ctx,
unsigned cbb,
@ -53,6 +88,14 @@ ox::Error loadBgTileSheet(
return loadBgTileSheet(ctx, cbb, *ts, paletteBank);
}
ox::Error loadSpriteTileSheet(
Context &ctx,
ox::StringViewCR tilesheetPath,
bool loadDefaultPalette) noexcept {
oxRequire(ts, readObj<CompactTileSheet>(keelCtx(ctx), tilesheetPath));
return loadSpriteTileSheet(ctx, *ts, loadDefaultPalette);
}
ox::Error loadSpriteTileSheet(
Context &ctx,
ox::FileAddress const&tilesheetAddr,
@ -213,12 +256,11 @@ void puts(
int const column,
int const row,
ox::StringViewCR str) noexcept {
auto const col = static_cast<uint_t>(column);
for (auto i = 0u; i < str.bytes(); ++i) {
setBgTile(
ctx,
0,
static_cast<int>(col + i),
column + static_cast<int>(i),
row,
static_cast<uint8_t>(charMap[static_cast<uint8_t>(str[i])]));
}

View File

@ -554,20 +554,21 @@ static ox::Result<TileSheetData> buildSetTsd(
static void copyPixels(
CompactTileSheet const&ts,
uint32_t *dst,
ox::Span<uint32_t> dst,
size_t const srcPxIdx,
size_t pxlCnt) noexcept {
size_t idx{};
if (ts.bpp == 4) {
for (size_t i = 0; i < pxlCnt; i += 2) {
auto const [a, b] = get2Pixels4Bpp(ts, i + srcPxIdx);
*(dst++) = a;
*(dst++) = b;
dst[idx++] = a;
dst[idx++] = b;
}
} else if (ts.bpp == 8) {
for (size_t i = 0; i < pxlCnt; i += 2) {
auto const [a, b] = get2Pixels8Bpp(ts, i + srcPxIdx);
*(dst++) = a;
*(dst++) = b;
dst[idx++] = a;
dst[idx++] = b;
}
}
}
@ -587,7 +588,7 @@ ox::Error loadBgTileSheet(
if (dstPxIdx + pxlCnt >= cbbPxls.size()) {
return OxError(1, "video mem dst overflow");
}
auto const dst = &cbbPxls[dstPxIdx];
auto const dst = ox::Span{cbbPxls} + dstPxIdx;
copyPixels(ts, dst, srcPxIdx, pxlCnt);
auto const cbbTiles = cbbPxls.size() / bytesPerTile;
int constexpr cbbWidth = 8;

View File

@ -12,7 +12,7 @@ TileSheetClipboard::Pixel::Pixel(uint16_t pColorIdx, ox::Point pPt) noexcept {
}
void TileSheetClipboard::addPixel(const ox::Point &pt, uint16_t colorIdx) noexcept {
void TileSheetClipboard::addPixel(ox::Point const&pt, uint16_t colorIdx) noexcept {
m_pixels.emplace_back(colorIdx, pt);
}
@ -25,18 +25,20 @@ CutPasteCommand::CutPasteCommand(
CommandId commandId,
TileSheet &img,
TileSheet::SubSheetIdx subSheetIdx,
const ox::Point &dstStart,
const ox::Point &dstEnd,
const TileSheetClipboard &cb) noexcept:
ox::Point const&dstStart,
ox::Point dstEnd,
TileSheetClipboard const&cb) noexcept:
m_commandId(commandId),
m_img(img),
m_subSheetIdx(std::move(subSheetIdx)) {
const auto &subsheet = getSubSheet(m_img, m_subSheetIdx);
for (const auto &p : cb.pixels()) {
const auto dstPt = p.pt + dstStart;
auto const&ss = getSubSheet(m_img, m_subSheetIdx);
dstEnd.x = std::min(ss.columns * TileWidth - 1, dstEnd.x);
dstEnd.y = std::min(ss.rows * TileHeight - 1, dstEnd.y);
for (auto const&p : cb.pixels()) {
auto const dstPt = p.pt + dstStart;
if (dstPt.x <= dstEnd.x && dstPt.y <= dstEnd.y) {
const auto idx = core::idx(subsheet, dstPt);
m_changes.emplace_back(static_cast<uint32_t>(idx), p.colorIdx, getPixel(subsheet, m_img.bpp, idx));
auto const idx = core::idx(ss, dstPt);
m_changes.emplace_back(static_cast<uint32_t>(idx), p.colorIdx, getPixel(ss, m_img.bpp, idx));
}
}
}

View File

@ -68,7 +68,7 @@ class CutPasteCommand: public TileSheetCommand {
TileSheet &img,
TileSheet::SubSheetIdx subSheetIdx,
ox::Point const&dstStart,
ox::Point const&dstEnd,
ox::Point dstEnd,
TileSheetClipboard const&cb) noexcept;
ox::Error redo() noexcept final;

View File

@ -2,6 +2,8 @@
* Copyright 2016 - 2024 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include <ox/std/algorithm.hpp>
#include "deletetilescommand.hpp"
namespace nostalgia::core {
@ -20,11 +22,9 @@ core::DeleteTilesCommand::DeleteTilesCommand(
// copy pixels to be erased
{
auto &s = getSubSheet(m_img, m_idx);
auto &p = s.pixels;
auto dst = m_deletedPixels.data();
auto src = p.data() + m_deletePos;
const auto sz = m_deleteSz * sizeof(decltype(p[0]));
ox::memcpy(dst, src, sz);
auto dst = m_deletedPixels.begin();
auto src = s.pixels.begin() + m_deletePos;
ox::copy_n(src, m_deleteSz, dst);
}
}
@ -32,9 +32,9 @@ ox::Error core::DeleteTilesCommand::redo() noexcept {
auto &s = getSubSheet(m_img, m_idx);
auto &p = s.pixels;
auto srcPos = m_deletePos + m_deleteSz;
const auto src = p.data() + srcPos;
const auto dst1 = p.data() + m_deletePos;
const auto dst2 = p.data() + (p.size() - m_deleteSz);
auto const src = &p[srcPos];
auto const dst1 = &p[m_deletePos];
auto const dst2 = &p[(p.size() - m_deleteSz)];
ox::memmove(dst1, src, p.size() - srcPos);
ox::memset(dst2, 0, m_deleteSz * sizeof(decltype(p[0])));
return {};
@ -43,10 +43,10 @@ ox::Error core::DeleteTilesCommand::redo() noexcept {
ox::Error DeleteTilesCommand::undo() noexcept {
auto &s = getSubSheet(m_img, m_idx);
auto &p = s.pixels;
const auto src = p.data() + m_deletePos;
const auto dst1 = p.data() + m_deletePos + m_deleteSz;
const auto dst2 = src;
const auto sz = p.size() - m_deletePos - m_deleteSz;
auto const src = &p[m_deletePos];
auto const dst1 = &p[m_deletePos + m_deleteSz];
auto const dst2 = src;
auto const sz = p.size() - m_deletePos - m_deleteSz;
ox::memmove(dst1, src, sz);
ox::memcpy(dst2, m_deletedPixels.data(), m_deletedPixels.size());
return {};

View File

@ -21,10 +21,9 @@ core::InsertTilesCommand::InsertTilesCommand(
{
auto &s = getSubSheet(m_img, m_idx);
auto &p = s.pixels;
auto dst = m_deletedPixels.data();
auto src = p.data() + p.size() - m_insertCnt;
const auto sz = m_insertCnt * sizeof(decltype(p[0]));
ox::memcpy(dst, src, sz);
auto dst = m_deletedPixels.begin();
auto src = p.begin() + p.size() - m_insertCnt;
ox::copy_n(src, m_insertCnt, dst);
}
}
@ -32,8 +31,8 @@ ox::Error InsertTilesCommand::redo() noexcept {
auto &s = getSubSheet(m_img, m_idx);
auto &p = s.pixels;
auto dstPos = m_insertPos + m_insertCnt;
const auto dst = p.data() + dstPos;
const auto src = p.data() + m_insertPos;
auto const dst = &p[dstPos];
auto const src = &p[m_insertPos];
ox::memmove(dst, src, p.size() - dstPos);
ox::memset(src, 0, m_insertCnt * sizeof(decltype(p[0])));
return {};
@ -42,11 +41,11 @@ ox::Error InsertTilesCommand::redo() noexcept {
ox::Error InsertTilesCommand::undo() noexcept {
auto &s = getSubSheet(m_img, m_idx);
auto &p = s.pixels;
const auto srcIdx = m_insertPos + m_insertCnt;
const auto src = p.data() + srcIdx;
const auto dst1 = p.data() + m_insertPos;
const auto dst2 = p.data() + p.size() - m_insertCnt;
const auto sz = p.size() - srcIdx;
auto const srcIdx = m_insertPos + m_insertCnt;
auto const src = &p[srcIdx];
auto const dst1 = &p[m_insertPos];
auto const dst2 = &p[p.size() - m_insertCnt];
auto const sz = p.size() - srcIdx;
ox::memmove(dst1, src, sz);
ox::memcpy(dst2, m_deletedPixels.data(), m_deletedPixels.size());
return {};

View File

@ -120,7 +120,7 @@ ox::StringView TileSheetEditorModel::palPath() const noexcept {
}
constexpr ox::StringView uuidPrefix = "uuid://";
if (ox::beginsWith(path, uuidPrefix)) {
auto uuid = ox::StringView(path.data() + uuidPrefix.bytes(), path.bytes() - uuidPrefix.bytes());
auto uuid = ox::StringView(&path[uuidPrefix.bytes()], path.bytes() - uuidPrefix.bytes());
auto out = keelCtx(m_tctx).uuidToPath.at(uuid);
if (out.error) {
return {};
@ -197,7 +197,7 @@ void TileSheetEditorModel::fill(ox::Point const&pt, int palIdx) noexcept {
if (pt.x >= s.columns * TileWidth || pt.y >= s.rows * TileHeight) {
return;
}
getFillPixels(updateMap.data(), pt, oldColor);
getFillPixels(updateMap, pt, oldColor);
ox::Vector<std::size_t> idxList;
auto i = core::idx(s, pt) / PixelsPerTile * PixelsPerTile;
for (auto u : updateMap) {
@ -281,7 +281,7 @@ bool TileSheetEditorModel::pixelSelected(std::size_t idx) const noexcept {
return m_selection && m_selection->contains(pt);
}
void TileSheetEditorModel::getFillPixels(bool *pixels, ox::Point const&pt, int oldColor) const noexcept {
void TileSheetEditorModel::getFillPixels(ox::Span<bool> pixels, ox::Point const&pt, int oldColor) const noexcept {
const auto &activeSubSheet = this->activeSubSheet();
const auto tileIdx = [activeSubSheet](const ox::Point &pt) noexcept {
return ptToIdx(pt, activeSubSheet.columns) / PixelsPerTile;

View File

@ -128,7 +128,7 @@ class TileSheetEditorModel: public ox::SignalHandler {
bool pixelSelected(std::size_t idx) const noexcept;
private:
void getFillPixels(bool *pixels, ox::Point const&pt, int oldColor) const noexcept;
void getFillPixels(ox::Span<bool> pixels, ox::Point const&pt, int oldColor) const noexcept;
void pushCommand(studio::UndoCommand *cmd) noexcept;

View File

@ -163,8 +163,8 @@ unsigned pixelCnt(TileSheet::SubSheet const&ss, int8_t pBpp) noexcept {
ox::Error resizeSubsheet(TileSheet::SubSheet &ss, int8_t pBpp, ox::Size const&sz) noexcept {
ox::Vector<uint8_t> out;
oxReturnError(setPixelCount(out, pBpp, static_cast<size_t>(sz.width * sz.height) * PixelsPerTile));
auto const w = ss.columns * TileWidth;
auto const h = ss.rows * TileHeight;
auto const w = ox::min<int32_t>(ss.columns, sz.width) * TileWidth;
auto const h = ox::min<int32_t>(ss.rows, sz.height) * TileHeight;
for (auto x = 0; x < w; ++x) {
for (auto y = 0; y < h; ++y) {
auto const palIdx = getPixel(ss, pBpp, {x, y});

View File

@ -24,9 +24,10 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
},
};
int main(int argc, const char **args) {
int main(int argc, const char **argv) {
int retval = -1;
if (argc > 0) {
auto const args = ox::Span{argv, static_cast<size_t>(argc)};
auto const testName = ox::StringView(args[1]);
if (tests.find(testName) != tests.end()) {
retval = static_cast<int>(tests[testName]());

View File

@ -1,7 +1,6 @@
add_executable(
nostalgia WIN32
app.cpp
main.cpp
)
# enable LTO
@ -23,6 +22,8 @@ endif()
target_link_libraries(
nostalgia
NostalgiaKeelModules
NostalgiaProfile
OlympicApplib
OxLogConn
)

View File

@ -65,8 +65,8 @@ static void testKeyEventHandler(turbine::Context &tctx, turbine::Key key, bool d
[[maybe_unused]]
static ox::Error runTest(turbine::Context &tctx) {
constexpr ox::FileAddress TileSheetAddr = ox::StringLiteral("/TileSheets/Charset.ng");
constexpr ox::FileAddress PaletteAddr = ox::StringLiteral("/Palettes/Chester.npal");
constexpr ox::StringView TileSheetAddr{"/TileSheets/Charset.ng"};
constexpr ox::StringView PaletteAddr{"/Palettes/Chester.npal"};
oxRequireM(cctx, core::init(tctx));
turbine::setApplicationData(tctx, cctx.get());
oxRequire(tsStat, turbine::rom(tctx)->stat(PaletteAddr));
@ -84,24 +84,24 @@ static ox::Error runTest(turbine::Context &tctx) {
static ox::Error runTileSheetSetTest(turbine::Context &tctx) {
// this should make the screen display 'ABCDB', with the A being upside down
// and the first B being backwards
constexpr ox::FileAddress PaletteAddr = ox::StringLiteral("/Palettes/Charset.npal");
constexpr ox::StringView PaletteAddr{"/Palettes/Charset.npal"};
oxRequireM(cctx, core::init(tctx));
turbine::setApplicationData(tctx, cctx.get());
oxRequire(tsStat, turbine::rom(tctx)->stat(PaletteAddr));
core::TileSheetSet const set{
.bpp = 4,
.entries = {
{ .tilesheet = ox::StringLiteral("/TileSheets/Chester.ng"), .sections{{.begin = 0, .tiles = 1}} },
{ .tilesheet = ox::StringLiteral("/TileSheets/AB.ng"), .sections{{.begin = 0, .tiles = 2}} },
{ .tilesheet = ox::StringLiteral("/TileSheets/CD.ng"), .sections{{.begin = 0, .tiles = 2}} },
{ .tilesheet = ox::StringLiteral("/TileSheets/AB.ng"), .sections{{.begin = 1, .tiles = 1}} },
{ .tilesheet = ox::StringLiteral{"/TileSheets/Chester.ng"}, .sections{{.begin = 0, .tiles = 1}} },
{ .tilesheet = ox::StringLiteral{"/TileSheets/AB.ng"}, .sections{{.begin = 0, .tiles = 2}} },
{ .tilesheet = ox::StringLiteral{"/TileSheets/CD.ng"}, .sections{{.begin = 0, .tiles = 2}} },
{ .tilesheet = ox::StringLiteral{"/TileSheets/AB.ng"}, .sections{{.begin = 1, .tiles = 1}} },
},
};
constexpr auto bgPalBank = 1;
oxReturnError(core::loadBgTileSheet(*cctx, 0, set));
oxReturnError(core::loadSpriteTileSheet(*cctx, set));
oxReturnError(core::loadBgPalette(*cctx, bgPalBank, PaletteAddr));
oxReturnError(core::loadBgPalette(*cctx, 0, ox::StringLiteral("/Palettes/Chester.npal")));
oxReturnError(core::loadBgPalette(*cctx, 0, PaletteAddr));
oxReturnError(core::loadSpritePalette(*cctx, PaletteAddr));
core::setBgStatus(*cctx, 0, true);
core::setBgTile(*cctx, 0, 10, 9, { .tileIdx = 1, .palBank = bgPalBank, .flipX = 0, .flipY = 1 });
@ -147,7 +147,7 @@ static void sceneKeyEventHandler(turbine::Context &tctx, turbine::Key key, bool
[[maybe_unused]]
static ox::Error runScene(turbine::Context &tctx) {
constexpr ox::FileAddress SceneAddr = ox::StringLiteral("/Scenes/Chester.nscn");
constexpr ox::StringView SceneAddr{"/Scenes/Chester.nscn"};
oxRequireM(cctx, core::init(tctx));
oxRequire(scn, keel::readObj<scene::SceneStatic>(keelCtx(tctx), SceneAddr));
turbine::setUpdateHandler(tctx, sceneUpdateHandler);
@ -157,7 +157,20 @@ static ox::Error runScene(turbine::Context &tctx) {
return turbine::run(tctx);
}
ox::Error run(ox::UniquePtr<ox::FileSystem> &&fs) noexcept {
oxRequireM(tctx, turbine::init(std::move(fs), "Nostalgia"));
namespace olympic {
ox::Error run(
[[maybe_unused]] ox::StringView project,
[[maybe_unused]] ox::StringView appName,
[[maybe_unused]] ox::StringView projectDataDir,
ox::SpanView<char const*> args) noexcept {
if (args.size() < 2) {
return OxError(1, "Please provide path to project directory or OxFS file.");
}
auto const path = args[1];
oxRequireM(fs, keel::loadRomFs(path));
oxRequireM(tctx, turbine::init(std::move(fs), project));
return runTileSheetSetTest(*tctx);
}
}

View File

@ -1,43 +0,0 @@
/*
* Copyright 2016 - 2024 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include <ox/logconn/def.hpp>
#include <ox/logconn/logconn.hpp>
#include <keel/media.hpp>
#include "../modules/keelmodules.hpp"
#include "app.hpp"
static ox::Error run(int argc, const char **argv) noexcept {
#ifndef OX_BARE_METAL
// GBA doesn't need the modules and calling this doubles the size of the
// binary.
nostalgia::registerKeelModules();
#endif
if (argc < 2) {
return OxError(1, "Please provide path to project directory or OxFS file.");
}
const auto path = argv[1];
oxRequireM(fs, keel::loadRomFs(path));
return run(std::move(fs));
}
#ifdef _WIN32
int WinMain() {
auto const argc = __argc;
auto const argv = const_cast<const char**>(__argv);
#else
int main(int argc, const char **argv) {
#endif
OX_INIT_DEBUG_LOGGER(loggerConn, "Nostalgia Player")
ox::Error err;
err = run(argc, argv);
oxAssert(err, "Something went wrong...");
if (err) {
oxErrf("Failure: {}\n", toStr(err));
}
return static_cast<int>(err);
}

View File

@ -1,3 +1,8 @@
if(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang")
# enable warnings
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wunsafe-buffer-usage")
endif()
if(BUILDCORE_TARGET STREQUAL "gba")
project(Olympic ASM CXX)
else()

View File

@ -41,8 +41,7 @@ ox::Error run(
ox::StringView project,
ox::StringView appName,
ox::StringView projectDataDir,
int argc,
char const**argv) noexcept;
ox::SpanView<char const*> argv) noexcept;
}
@ -65,7 +64,11 @@ int main(int argc, char const**argv) {
#if OLYMPIC_LOAD_STUDIO_MODULES
OLYMPIC_PROJECT_NAMESPACE::registerStudioModules();
#endif
auto const err = olympic::run(OLYMPIC_PROJECT_NAME, OLYMPIC_APP_NAME, OLYMPIC_PROJECT_DATADIR, argc, argv);
auto const err = olympic::run(
OLYMPIC_PROJECT_NAME,
OLYMPIC_APP_NAME,
OLYMPIC_PROJECT_DATADIR,
{argv, static_cast<size_t>(argc)});
oxAssert(err, "Something went wrong...");
if (err) {
oxErrf("Failure: {}\n", toStr(err));

View File

@ -7,6 +7,8 @@
#include <ox/claw/claw.hpp>
#include <ox/fs/fs.hpp>
#include "validation.hpp"
namespace keel {
constexpr auto K1HdrSz = 40;
@ -26,7 +28,10 @@ ox::Result<T> readAsset(ox::BufferView buff) noexcept {
if (!err) {
offset = K1HdrSz; // the size of K1 headers
}
return ox::readClaw<T>(buff + offset);
auto out = ox::readClaw<T>(buff + offset);
oxReturnError(out);
oxReturnError(ensureValid(out.value));
return out;
}
ox::Result<ox::ModelObject> readAsset(ox::TypeStore &ts, ox::BufferView buff) noexcept;

View File

@ -14,8 +14,6 @@
#include <ox/std/hashmap.hpp>
#include <ox/std/utility.hpp>
#include "validation.hpp"
namespace keel {
class AssetManager;
@ -190,7 +188,7 @@ class AssetManager {
private:
class AssetTypeManagerBase: public ox::SignalHandler {
public:
virtual ~AssetTypeManagerBase() = default;
~AssetTypeManagerBase() override = default;
virtual void gc() noexcept = 0;
};
@ -217,7 +215,6 @@ class AssetManager {
ox::Result<AssetRef<T>> loadAsset(ox::StringView const assetId) noexcept {
auto &p = m_cache[assetId];
oxRequireM(obj, m_loader(assetId));
oxReturnError(ensureValid(obj));
if (!p) {
p = ox::make_unique<AssetContainer<T>>(std::move(obj));
} else {

View File

@ -63,10 +63,8 @@ namespace detail {
template<typename T>
constexpr auto makeLoader(Context &ctx) {
return [&ctx](ox::StringView assetId) -> ox::Result<T> {
ox::StringView path;
oxRequire(p, ctx.uuidToPath.at(assetId));
path = *p;
oxRequire(buff, ctx.rom->read(path));
oxRequire(buff, ctx.rom->read(*p));
auto [obj, err] = readAsset<T>(buff);
if (err) {
if (err != ox::Error_ClawTypeVersionMismatch && err != ox::Error_ClawTypeMismatch) {
@ -84,21 +82,17 @@ ox::Result<keel::AssetRef<T>> readObjFile(
keel::Context &ctx,
ox::StringView assetId,
bool forceLoad) noexcept {
ox::UUIDStr uuidStr;
if (beginsWith(assetId, "uuid://")) {
assetId = substr(assetId, 7);
oxRequire(p, keel::uuidToPath(ctx, assetId));
} else {
auto const [uuid, uuidErr] = getUuid(ctx, assetId);
if (!uuidErr) {
uuidStr = uuid.toString();
assetId = uuidStr;
assetId = uuid.toString();
}
}
if (forceLoad) {
ctx.assetManager.initTypeManager<T>(detail::makeLoader<T>, ctx);
oxRequire(cached, ctx.assetManager.loadAsset<T>(assetId));
return cached;
return ctx.assetManager.loadAsset<T>(assetId);
} else {
auto [cached, err] = ctx.assetManager.getAsset<T>(assetId);
if (err) {

View File

@ -7,8 +7,6 @@
#include <ox/std/def.hpp>
#include <ox/std/error.hpp>
#include <ox/std/string.hpp>
#include <ox/claw/read.hpp>
#include <ox/claw/write.hpp>
#include "asset.hpp"
#include "context.hpp"
@ -119,7 +117,6 @@ class Converter: public BaseConverter {
ox::Result<ox::UPtr<Wrap>> convertBuffToPtr(
keel::Context &ctx, ox::BufferView const&srcBuff) const noexcept final {
oxRequireM(src, readAsset<SrcType>(srcBuff));
oxReturnError(ensureValid(src));
auto dst = makeWrap<DstType>();
oxReturnError(convert(ctx, src, wrapCast<DstType>(*dst)));
return {std::move(dst)};

View File

@ -14,7 +14,7 @@ ox::Result<ox::UUID> readUuidHeader(ox::BufferView buff) noexcept {
if (k1Hdr != ox::StringView(buff.data(), k1Hdr.bytes())) [[unlikely]] {
return OxError(2, "No Keel asset header data");
}
return ox::UUID::fromString(ox::StringView(buff.data() + k1Hdr.bytes(), 36));
return ox::UUID::fromString(ox::StringView(&buff[k1Hdr.bytes()], 36));
}
ox::Result<ox::ModelObject> readAsset(ox::TypeStore &ts, ox::BufferView buff) noexcept {

View File

@ -9,7 +9,9 @@ namespace keel {
static ox::Vector<Module const*> mods;
void registerModule(Module const*mod) noexcept {
mods.emplace_back(mod);
if (mod) {
mods.emplace_back(mod);
}
}
[[nodiscard]]

View File

@ -81,8 +81,8 @@ static ox::Error pack(
return {};
}
static ox::Error run(int argc, char const**argv, ox::StringView projectDataDir) noexcept {
ox::ClArgs const args(argc, argv);
static ox::Error run(ox::SpanView<char const*> argv, ox::StringView projectDataDir) noexcept {
ox::ClArgs const args(argv);
auto const argSrc = args.getString("src", "");
auto const argRomBin = args.getString("rom-bin", "");
auto const argManifest = args.getString("manifest", "");
@ -103,9 +103,8 @@ ox::Error run(
[[maybe_unused]] ox::StringView project,
[[maybe_unused]] ox::StringView appName,
ox::StringView projectDataDir,
int argc,
char const**argv) noexcept {
return ::run(argc, argv, projectDataDir);
ox::SpanView<char const*> argv) noexcept {
return ::run(argv, projectDataDir);
}
}

View File

@ -15,16 +15,22 @@ static ox::Error pathToInode(
ox::FileSystem &dest,
ox::ModelObject &obj) noexcept {
auto &o = obj;
auto type = static_cast<ox::FileAddressType>(o.at("type").unwrap()->get<int8_t>());
auto &data = o.at("data").unwrap()->get<ox::ModelUnion>();
oxRequire(typeVal, o.at("type"));
auto const type = static_cast<ox::FileAddressType>(typeVal->get<int8_t>());
oxRequire(dataVal, o.at("data"));
auto &data = dataVal->get<ox::ModelUnion>();
ox::String path;
switch (type) {
case ox::FileAddressType::Path:
path = data.at("path").unwrap()->get<ox::String>();
case ox::FileAddressType::Path: {
oxRequire(pathVal, data.at("path"));
path = pathVal->get<ox::String>();
break;
case ox::FileAddressType::ConstPath:
path = data.at("constPath").unwrap()->get<ox::String>();
}
case ox::FileAddressType::ConstPath: {
oxRequire(pathVal, data.at("constPath"));
path = pathVal->get<ox::String>();
break;
}
case ox::FileAddressType::Inode:
case ox::FileAddressType::None:
return {};
@ -34,7 +40,7 @@ static ox::Error pathToInode(
oxReturnError(keel::uuidToPath(ctx, uuid).to<ox::String>().moveTo(path));
}
oxRequire(s, dest.stat(path));
oxReturnError(o.at("type").unwrap()->set(static_cast<int8_t>(ox::FileAddressType::Inode)));
oxReturnError(typeVal->set(static_cast<int8_t>(ox::FileAddressType::Inode)));
oxOutf("\tpath to inode: {} => {}\n", path, s.inode);
return data.set(2, s.inode);
}
@ -162,12 +168,12 @@ static ox::Error copy(
// copy
oxRequire(fileList, src.ls(path));
for (auto const&name : fileList) {
auto currentFile = ox::sfmt("{}{}", path, name);
auto const currentFile = ox::sfmt("{}{}", path, name);
if (beginsWith(name, ".")) {
continue;
}
oxRequire(stat, src.stat(currentFile));
if (stat.fileType == ox::FileType::Directory) {
oxRequire(srcStat, src.stat(currentFile));
if (srcStat.fileType == ox::FileType::Directory) {
oxReturnError(dest.mkdir(currentFile, true));
oxReturnError(copy(manifest, src, dest, currentFile + '/', childLogPrefix));
} else {
@ -181,9 +187,9 @@ static ox::Error copy(
// write file to dest
oxReturnError(dest.write(currentFile, buff));
status = "OK";
oxRequire(stat, dest.stat(currentFile));
oxRequire(dstStat, dest.stat(currentFile));
manifest.files[currentFile] = {
.inode = stat.inode,
.inode = dstStat.inode,
.type = ox::String{keel::readAssetTypeId(buff).or_value({})},
};
}

View File

@ -2,8 +2,6 @@
* Copyright 2016 - 2024 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include <ox/claw/read.hpp>
#include <keel/media.hpp>
#include <keel/typeconv.hpp>

View File

@ -25,9 +25,10 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
},
};
int main(int argc, const char **args) {
int main(int argc, const char **argv) {
int retval = -1;
if (argc > 0) {
auto const args = ox::Span{argv, static_cast<size_t>(argc)};
auto testName = args[1];
if (tests.find(testName) != tests.end()) {
retval = static_cast<int>(tests[testName]());

View File

@ -52,8 +52,7 @@ static ox::Error runApp(
static ox::Error run(
ox::StringViewCR appName,
ox::StringViewCR projectDataDir,
int,
char const**) {
ox::SpanView<const char*>) {
// seed UUID generator
auto const time = std::time(nullptr);
ox::UUID::seedGenerator({
@ -74,9 +73,8 @@ ox::Error run(
ox::StringView project,
ox::StringView appName,
ox::StringView projectDataDir,
int argc,
char const**argv) noexcept {
return studio::run(ox::sfmt("{} {}", project, appName), projectDataDir, argc, argv);
ox::SpanView<char const*> args) noexcept {
return studio::run(ox::sfmt("{} {}", project, appName), projectDataDir, args);
}
}

View File

@ -63,12 +63,14 @@ void NewMenu::addItemMaker(ox::UniquePtr<studio::ItemMaker> &&im) noexcept {
void NewMenu::drawNewItemType(studio::StudioContext &sctx) noexcept {
drawWindow(sctx.tctx, &m_open, [this] {
auto items = ox_malloca(m_types.size() * sizeof(char const*), char const*, nullptr);
auto const allocSz = m_types.size() * sizeof(char const*);
auto mem = ox_malloca(allocSz, char const*, nullptr);
auto items = ox::Span{mem.get(), allocSz};
for (auto i = 0u; auto const&im : m_types) {
items.get()[i] = im->typeName.c_str();
items[i] = im->typeName.c_str();
++i;
}
ImGui::ListBox("Item Type", &m_selectedType, items.get(), static_cast<int>(m_types.size()));
ImGui::ListBox("Item Type", &m_selectedType, items.data(), static_cast<int>(m_types.size()));
drawFirstPageButtons();
});
}
@ -116,11 +118,12 @@ void NewMenu::drawLastPageButtons(studio::StudioContext &sctx) noexcept {
void NewMenu::finish(studio::StudioContext &sctx) noexcept {
if (m_itemName.len() == 0) {
oxLogError(OxError(1, "New file error: no file name"));
return;
}
auto const&typeMaker = *m_types[static_cast<std::size_t>(m_selectedType)];
if (sctx.project->exists(typeMaker.itemPath(m_itemName))) {
oxLogError(OxError(1, "New file error: File already exists"));
oxLogError(OxError(1, "New file error: file already exists"));
return;
}
auto const [path, err] = typeMaker.write(sctx, m_itemName);

View File

@ -21,7 +21,9 @@ namespace studio {
static ox::Vector<studio::Module const*> modules;
void registerModule(studio::Module const*mod) noexcept {
modules.emplace_back(mod);
if (mod) {
modules.emplace_back(mod);
}
}
@ -238,18 +240,18 @@ void StudioUI::loadEditorMaker(studio::EditorMaker const&editorMaker) noexcept {
}
}
void StudioUI::loadModule(studio::Module const*mod) noexcept {
for (auto const&editorMaker : mod->editors(m_sctx)) {
void StudioUI::loadModule(studio::Module const&mod) noexcept {
for (auto const&editorMaker : mod.editors(m_sctx)) {
loadEditorMaker(editorMaker);
}
for (auto &im : mod->itemMakers(m_sctx)) {
for (auto &im : mod.itemMakers(m_sctx)) {
m_newMenu.addItemMaker(std::move(im));
}
}
void StudioUI::loadModules() noexcept {
for (auto const mod : modules) {
loadModule(mod);
loadModule(*mod);
}
}

View File

@ -69,7 +69,7 @@ class StudioUI: public ox::SignalHandler {
void loadEditorMaker(studio::EditorMaker const&editorMaker) noexcept;
void loadModule(studio::Module const*mod) noexcept;
void loadModule(studio::Module const&mod) noexcept;
void loadModules() noexcept;

View File

@ -5,6 +5,7 @@
#pragma once
#include <ox/std/defines.hpp>
#include <ox/std/string.hpp>
namespace studio {

View File

@ -189,7 +189,7 @@ bool BeginPopup(turbine::Context &ctx, ox::CStringView popupName, bool &show, Im
* @param selectedIdx
* @return true if new value selected, false otherwise
*/
bool ComboBox(ox::CStringView lbl, ox::SpanView<ox::String> list, size_t &selectedIdx) noexcept;
bool ComboBox(ox::CStringView lbl, ox::Span<const ox::String> list, size_t &selectedIdx) noexcept;
/**
*
@ -223,7 +223,7 @@ bool ListBox(
* @param selIdx
* @return true if new value selected, false otherwise
*/
bool ListBox(ox::CStringView name, ox::SpanView<ox::String> const&list, size_t &selIdx) noexcept;
bool ListBox(ox::CStringView name, ox::Span<const ox::String> const&list, size_t &selIdx) noexcept;
class FilePicker {
private:

View File

@ -22,10 +22,12 @@ static ox::Result<ox::String> toResult(nfdresult_t r, NFD::UniquePathN const&pat
switch (r) {
case NFD_OKAY: {
ox::String out;
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
for (auto i = 0u; path.get()[i]; ++i) {
auto const c = static_cast<char>(path.get()[i]);
std::ignore = out.append(&c, 1);
}
OX_ALLOW_UNSAFE_BUFFERS_END
return out;
}
case NFD_CANCEL:
@ -35,11 +37,11 @@ static ox::Result<ox::String> toResult(nfdresult_t r, NFD::UniquePathN const&pat
}
}
ox::Result<ox::String> saveFile(ox::Vector<FDFilterItem> const&filters) noexcept {
ox::Result<ox::String> saveFile(ox::Vector<FDFilterItem> const&exts) noexcept {
NFD::Guard const guard;
NFD::UniquePathN path;
ox::Vector<nfdnfilteritem_t, 5> filterItems(filters.size());
for (auto i = 0u; auto const&f : filters) {
ox::Vector<nfdnfilteritem_t, 5> filterItems(exts.size());
for (auto i = 0u; auto const&f : exts) {
filterItems[i].name = f.name.data();
filterItems[i].spec = f.spec.data();
++i;

View File

@ -87,7 +87,7 @@ bool BeginPopup(turbine::Context &ctx, ox::CStringView popupName, bool &show, Im
bool ComboBox(
ox::CStringView lbl,
ox::SpanView<ox::String> list,
ox::Span<const ox::String> list,
size_t &selectedIdx) noexcept {
bool out{};
auto const first = selectedIdx < list.size() ? list[selectedIdx].c_str() : "";
@ -155,7 +155,7 @@ bool ListBox(
return out;
}
bool ListBox(ox::CStringView name, ox::SpanView<ox::String> const&list, size_t &selIdx) noexcept {
bool ListBox(ox::CStringView name, ox::Span<const ox::String> const&list, size_t &selIdx) noexcept {
return ListBox(name, [list](size_t i) -> ox::CStringView {
return list[i];
}, list.size(), selIdx);

View File

@ -47,12 +47,14 @@ static ox::Result<std::size_t> findPreloadSection() noexcept {
constexpr auto headerP1Len = ox::strlen(headerP2);
constexpr auto headerP2Len = ox::strlen(headerP1);
constexpr auto headerLen = headerP1Len + headerP2Len;
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
for (auto current = MEM_ROM; current < reinterpret_cast<char*>(0x0a000000); current += headerLen) {
if (memcmp(current, headerP1, headerP1Len) == 0 &&
memcmp(current + headerP1Len, headerP2, headerP2Len) == 0) {
return reinterpret_cast<std::size_t>(current + headerLen);
}
}
OX_ALLOW_UNSAFE_BUFFERS_END
return OxError(1);
}

Some files were not shown because too many files have changed in this diff Show More