Compare commits

..

25 Commits

Author SHA1 Message Date
gary ef1c108b58 [ox/std] Address GCC finding a new way to be retarded
Build / build (push) Successful in 1m12s
2026-05-19 23:19:50 -05:00
gary 6a054cd970 [nostalgia] Enable Wayland support for GLFW
Build / build (push) Successful in 1m39s
2026-05-19 22:47:02 -05:00
gary 9070e6e109 [ox/std] Fix compiler warning
Build / build (push) Successful in 1m18s
2026-05-17 20:33:58 -05:00
gary 6cc6e9e7ed [studio] Rename caseInsensitiveEquals to caseInsensitiveStrCmp
Build / build (push) Successful in 1m9s
2026-05-17 15:56:14 -05:00
gary de859bef77 [ox/std] Rename caseInsensitiveEquals to caseInsensitiveStrCmp 2026-05-17 15:55:35 -05:00
gary d1a3538e9a [ox/oc] Fix writeOC Writer_c variant to add null terminator
Build / build (push) Successful in 1m10s
2026-05-17 15:49:00 -05:00
gary d10a71f06d [studio] Add missing include
Build / build (push) Failing after 1m6s
2026-05-17 15:36:57 -05:00
gary 9593e7eef9 [ox] Add writeOC Writer_c variant 2026-05-17 15:31:56 -05:00
gary 2f9b9c0842 [studio] Fix change-format to only write data portion once
Build / build (push) Successful in 1m15s
2026-05-17 15:22:11 -05:00
gary dce09b564c [ox/std] Fix Result::originate to return value
Build / build (push) Successful in 1m12s
2026-05-17 15:19:13 -05:00
gary 9f485d9496 [studio] Cleanup
Build / build (push) Successful in 1m9s
2026-05-17 15:07:10 -05:00
gary 2c50ce48ed [ox/std] Add Result::reoriginate functions 2026-05-17 15:02:07 -05:00
gary 72e16cb285 [studio] Change output of Claw OC files to make them recognizable as test files 2026-05-17 14:53:42 -05:00
gary d1e410ac55 [ox/std] Add caseInsensitiveEquals 2026-05-17 14:30:43 -05:00
gary be32d575f5 [ox/claw] Add writeClaw Writer_c variant 2026-05-17 14:29:43 -05:00
gary f24929f421 [studio] Remove extra copyright header
Build / build (push) Successful in 1m16s
2026-05-16 16:44:13 -05:00
gary 2d426d2bb3 [studio] Fix change-format format reading
Build / build (push) Successful in 1m13s
2026-05-16 16:29:19 -05:00
gary f89af6fcb3 [studio] Fix change-format usage message
Build / build (push) Successful in 1m12s
2026-05-16 16:17:00 -05:00
gary 899eaa9dce [studio] Add change-format subcommand
Build / build (push) Successful in 1m13s
2026-05-16 16:12:29 -05:00
gary d32b1033c3 [nostalgia/gfx/studio] Cleanup 2026-05-16 14:11:20 -05:00
gary 1d2814bbd0 Merge commit '2e119b5683574d7243d30a9ba33c05b06bcdb8a4'
Build / build (push) Successful in 1m15s
2026-05-08 22:36:42 -05:00
gary 2e119b5683 Squashed 'deps/oxlib/' changes from 170d6e35a..a787fef61
a787fef61 Uncomment code that from Pico fix
298184d58 Fix build warning
51999199c [ox] Fix build problems on Raspberry Pi Pico
682fc5b85 Merge commit 'c286e3794d9d4cc571671548ad765ce370bcfcb4'
94209fd74 [ox/std] Make is_integral use raw types

git-subtree-dir: deps/oxlib
git-subtree-split: a787fef6147dcd11519c24f992289349f0ec355d
2026-05-08 22:36:42 -05:00
gary 46c6ba2e17 Merge commit 'c286e3794d9d4cc571671548ad765ce370bcfcb4' 2026-05-07 01:18:59 -05:00
gary c286e3794d Squashed 'deps/oxlib/' changes from 85f17c418..170d6e35a
170d6e35a [ox] Add dist to gitignore
83fd814d6 [ox] Bump required CMake version

git-subtree-dir: deps/oxlib
git-subtree-split: 170d6e35a67739b600aa95abfff7269972a45c00
2026-05-07 01:18:59 -05:00
gary 45cbede7e2 [ox/std] Make is_integral use raw types 2026-05-07 01:16:57 -05:00
26 changed files with 389 additions and 193 deletions
+2 -2
View File
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.19)
cmake_minimum_required(VERSION 3.25)
set(CMAKE_POLICY_DEFAULT_CMP0110 NEW) # requires CMake 3.19
if(BUILDCORE_TARGET STREQUAL "gba")
@@ -52,7 +52,7 @@ if(NOT BUILDCORE_TARGET STREQUAL "gba")
set(GLFW_BUILD_TESTS OFF)
set(GLFW_BUILD_DOCS OFF)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(GLFW_BUILD_WAYLAND OFF)
set(GLFW_BUILD_WAYLAND ON)
endif()
add_subdirectory(deps/glfw)
add_subdirectory(deps/glutils)
+1
View File
@@ -3,6 +3,7 @@ build/gba
build/*-asan
build/*-debug
build/*-release
dist
.current_build
tags
compile_commands.json
+1 -1
View File
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.19)
cmake_minimum_required(VERSION 3.25)
set(CMAKE_POLICY_DEFAULT_CMP0110 NEW) # requires CMake 3.19
project(Ox CXX)
+20
View File
@@ -120,4 +120,24 @@ Result<Buffer> writeClaw(
return out;
}
Error writeClaw(
auto const &obj,
Writer_c auto &writer,
ClawFormat const fmt = ClawFormat::Metal) noexcept {
OX_RETURN_ERROR(detail::writeClawHeader(writer, &obj, fmt));
#ifdef OX_USE_STDLIB
if (fmt == ClawFormat::Metal) {
OX_RETURN_ERROR(writeMC(writer, obj));
} else if (fmt == ClawFormat::Organic) {
OX_RETURN_ERROR(writeOC(writer, obj));
}
#else
if (fmt != ClawFormat::Metal) {
return ox::Error(1, "OC is not supported in this build");
}
OX_RETURN_ERROR(writeMC(writer, obj));
#endif
return {};
}
}
-11
View File
@@ -38,17 +38,6 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
auto a1 = buffer->malloc(sizeof(String)).value;
auto a2 = buffer->malloc(sizeof(String)).value;
oxAssert(a1.valid(), "Allocation 1 failed.");
oxAssert(a2.valid(), "Allocation 2 failed.");
auto s1Buff = buffer->dataOf<String>(a1);
auto s2Buff = buffer->dataOf<String>(a2);
oxAssert(s1Buff.valid(), "s1 allocation 1 failed.");
oxAssert(s2Buff.valid(), "s2 allocation 2 failed.");
auto &s1 = *new (s1Buff) String("asdf");
auto &s2 = *new (s2Buff) String("aoeu");
oxTrace("test") << "s1: " << s1.c_str();
oxTrace("test") << "s2: " << s2.c_str();
oxAssert(s1 == "asdf", "Allocation 1 not as expected.");
oxAssert(s2 == "aoeu", "Allocation 2 not as expected.");
oxAssert(buffer->free(a1), "Free failed.");
oxAssert(buffer->free(a2), "Free failed.");
oxAssert(buffer->setSize(buffer->size() - buffer->available()), "Resize failed.");
+3 -1
View File
@@ -6,7 +6,9 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#ifdef OX_USE_STDLIB
#include <ox/std/defines.hpp>
#ifndef OX_OS_BareMetal
#include <cstdio>
#ifndef _WIN32
+2 -45
View File
@@ -44,15 +44,7 @@ class MetalClawWriter: public ModelHandlerBase<MetalClawWriter<Writer>, OpType::
constexpr ~MetalClawWriter() noexcept = default;
constexpr Error field(CString, int8_t const *val) noexcept;
constexpr Error field(CString, int16_t const *val) noexcept;
constexpr Error field(CString, int32_t const *val) noexcept;
constexpr Error field(CString, int64_t const *val) noexcept;
constexpr Error field(CString, uint8_t const *val) noexcept;
constexpr Error field(CString, uint16_t const *val) noexcept;
constexpr Error field(CString, uint32_t const *val) noexcept;
constexpr Error field(CString, uint64_t const *val) noexcept;
constexpr Error field(CString, Integer_c auto const *val) noexcept;
constexpr Error field(CString, bool const *val) noexcept;
@@ -133,42 +125,7 @@ constexpr MetalClawWriter<Writer>::MetalClawWriter(Writer &writer, Optional<int>
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, int8_t const *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, int16_t const *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, int32_t const *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, int64_t const *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, uint8_t const *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, uint16_t const *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, uint32_t const *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, uint64_t const *val) noexcept {
constexpr Error MetalClawWriter<Writer>::field(CString, Integer_c auto const *val) noexcept {
return appendInteger(*val);
}
+6 -6
View File
@@ -43,14 +43,14 @@ struct TestStruct {
int32_t Int6 = 0;
int32_t Int7 = 0;
int32_t Int8 = 0;
int unionIdx = 1;
int32_t unionIdx = 1;
TestUnion Union;
ox::String String;
ox::IString<32> IString = "";
uint32_t List[4] = {0, 0, 0, 0};
ox::Vector<uint32_t> Vector = {1, 2, 3, 4, 5};
ox::Vector<uint32_t> Vector2 = {1, 2, 3, 4, 5};
ox::HashMap<ox::String, int> Map;
ox::HashMap<ox::String, int32_t> Map;
TestStructNest EmptyStruct;
TestStructNest Struct;
constexpr ~TestStruct() noexcept {
@@ -204,7 +204,8 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
std::cout << "val.length: " << val.length << '\n';
return ox::Error(1);
}
ox::LittleEndian<decltype(expected)> decoded = *reinterpret_cast<decltype(expected)*>(&val.data[1]);
ox::LittleEndian<decltype(expected)> decoded;
ox::memcpy(&decoded, &val.data[1], sizeof(decoded));
if (expected != decoded) {
std::cout << "decoded: " << decoded << ", expected: " << expected << '\n';
return ox::Error(1);
@@ -370,7 +371,7 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
const auto [type, typeErr] = ox::buildTypeDef(typeStore, testIn);
oxAssert(typeErr, "Descriptor write failed");
ox::BufferReader br({dataBuff, dataBuffLen});
OX_RETURN_ERROR(ox::walkModel<ox::MetalClawReader>(type, br,
return ox::walkModel<ox::MetalClawReader>(type, br,
[](const ox::Vector<ox::FieldName>&, const ox::Vector<ox::String>&, const ox::DescriptorField &f, ox::MetalClawReader *rdr) -> ox::Error {
//std::cout << f.fieldName.c_str() << '\n';
auto fieldName = f.fieldName.c_str();
@@ -455,8 +456,7 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
}
return ox::Error(0);
}
));
return ox::Error(0);
);
}
},
}
+21 -62
View File
@@ -126,22 +126,7 @@ class TypeDescWriter {
private:
[[nodiscard]]
constexpr const DescriptorType *type(const int8_t *val) const noexcept;
[[nodiscard]]
constexpr const DescriptorType *type(const int16_t *val) const noexcept;
[[nodiscard]]
constexpr const DescriptorType *type(const int32_t *val) const noexcept;
[[nodiscard]]
constexpr const DescriptorType *type(const int64_t *val) const noexcept;
[[nodiscard]]
constexpr const DescriptorType *type(const uint8_t *val) const noexcept;
[[nodiscard]]
constexpr const DescriptorType *type(const uint16_t *val) const noexcept;
[[nodiscard]]
constexpr const DescriptorType *type(const uint32_t *val) const noexcept;
[[nodiscard]]
constexpr const DescriptorType *type(const uint64_t *val) const noexcept;
constexpr const DescriptorType *type(const Integer_c auto *val) const noexcept;
[[nodiscard]]
constexpr const DescriptorType *type(const bool *val) const noexcept;
@@ -295,52 +280,26 @@ constexpr const DescriptorType *TypeDescWriter::type(UnionView<U> val) const noe
return t;
}
constexpr const DescriptorType *TypeDescWriter::type(const int8_t*) const noexcept {
constexpr auto PT = PrimitiveType::SignedInteger;
constexpr auto Bytes = 1;
return getType(types::Int8, 0, PT, Bytes);
}
constexpr const DescriptorType *TypeDescWriter::type(const int16_t*) const noexcept {
constexpr auto PT = PrimitiveType::SignedInteger;
constexpr auto Bytes = 2;
return getType(types::Int16, 0, PT, Bytes);
}
constexpr const DescriptorType *TypeDescWriter::type(const int32_t*) const noexcept {
constexpr auto PT = PrimitiveType::SignedInteger;
constexpr auto Bytes = 4;
return getType(types::Int32, 0, PT, Bytes);
}
constexpr const DescriptorType *TypeDescWriter::type(const int64_t*) const noexcept {
constexpr auto PT = PrimitiveType::SignedInteger;
constexpr auto Bytes = 8;
return getType(types::Int64, 0, PT, Bytes);
}
constexpr const DescriptorType *TypeDescWriter::type(const uint8_t*) const noexcept {
constexpr auto PT = PrimitiveType::UnsignedInteger;
constexpr auto Bytes = 1;
return getType(types::Uint8, 0, PT, Bytes);
}
constexpr const DescriptorType *TypeDescWriter::type(const uint16_t*) const noexcept {
constexpr auto PT = PrimitiveType::UnsignedInteger;
constexpr auto Bytes = 2;
return getType(types::Uint16, 0, PT, Bytes);
}
constexpr const DescriptorType *TypeDescWriter::type(const uint32_t*) const noexcept {
constexpr auto PT = PrimitiveType::UnsignedInteger;
constexpr auto Bytes = 4;
return getType(types::Uint32, 0, PT, Bytes);
}
constexpr const DescriptorType *TypeDescWriter::type(const uint64_t*) const noexcept {
constexpr auto PT = PrimitiveType::UnsignedInteger;
constexpr auto Bytes = 8;
return getType(types::Uint64, 0, PT, Bytes);
constexpr const DescriptorType *TypeDescWriter::type(Integer_c auto const *val) const noexcept {
constexpr auto isSigned = ox::is_signed_v<decltype(*val)>;
constexpr auto PT = isSigned ?
PrimitiveType::SignedInteger :
PrimitiveType::UnsignedInteger;
constexpr auto sz = sizeof(*val);
constexpr auto bytes = sizeof(*val);
return getType([] {
switch (sz) {
case 1:
return isSigned ? types::Int8 : types::Uint8;
case 2:
return isSigned ? types::Int16 : types::Uint16;
case 4:
return isSigned ? types::Int32 : types::Uint32;
case 8:
return isSigned ? types::Int64 : types::Uint64;
}
return types::Int32;
}(), 0, PT, bytes);
}
constexpr const DescriptorType *TypeDescWriter::type(const bool*) const noexcept {
+17 -6
View File
@@ -28,6 +28,7 @@ namespace ox {
class OrganicClawWriter {
friend Error writeOC(Writer_c auto &writer, auto const &val) noexcept;
friend Result<Buffer> writeOC(const auto &val) noexcept;
friend Result<String> writeOCString(const auto &val) noexcept;
@@ -59,7 +60,7 @@ class OrganicClawWriter {
Error field(CString const key, int32_t const *val) noexcept {
if (targetValid() && (*val || m_json.isArray())) {
value(key) = *val;
value(key) = static_cast<Json::Int>(*val);
}
++m_fieldIt;
return {};
@@ -92,7 +93,7 @@ class OrganicClawWriter {
Error field(CString const key, uint32_t const *val) noexcept {
if (targetValid() && (*val || m_json.isArray())) {
value(key) = *val;
value(key) = static_cast<Json::UInt>(*val);
}
++m_fieldIt;
return {};
@@ -221,9 +222,9 @@ Error OrganicClawWriter::field(CString key, T const *val) noexcept {
// the int type needs to be normalized because jsoncpp doesn't
// factor in every permutation unsigned long, etc.
if constexpr(is_signed_v<T>) {
value(key) = static_cast<Int<8 * sizeof(*val)>>(*val);
value(key) = static_cast<Json::Int64>(*val);
} else {
value(key) = static_cast<Uint<8 * sizeof(*val)>>(*val);
value(key) = static_cast<Json::UInt64>(*val);
}
}
} else if constexpr(isVector_v<T> || isArray_v<T>) {
@@ -254,9 +255,19 @@ Error OrganicClawWriter::field(CString key, UnionView<U, force> val) noexcept {
return {};
}
Error writeOC(Writer_c auto &writer, auto const &val) noexcept {
OrganicClawWriter ocWriter;
ModelHandlerInterface handler(ocWriter);
OX_RETURN_ERROR(model(&handler, &val));
Json::StreamWriterBuilder const jsonBuilder;
auto const str = Json::writeString(jsonBuilder, ocWriter.m_json);
OX_RETURN_ERROR(writer.write(str.data(), str.size()));
return writer.put('\0');
}
Result<Buffer> writeOC(auto const &val) noexcept {
OrganicClawWriter writer;
ModelHandlerInterface<OrganicClawWriter, OpType::Write> handler(writer);
ModelHandlerInterface handler(writer);
OX_RETURN_ERROR(model(&handler, &val));
Json::StreamWriterBuilder const jsonBuilder;
auto const str = Json::writeString(jsonBuilder, writer.m_json);
@@ -270,7 +281,7 @@ Result<Buffer> writeOC(auto const &val) noexcept {
Result<String> writeOCString(auto const &val) noexcept {
OrganicClawWriter writer;
ModelHandlerInterface<OrganicClawWriter, OpType::Write> handler(writer);
ModelHandlerInterface handler(writer);
OX_RETURN_ERROR(model(&handler, &val));
Json::StreamWriterBuilder const jsonBuilder;
auto const str = Json::writeString(jsonBuilder, writer.m_json);
+2 -2
View File
@@ -78,10 +78,10 @@ target_compile_definitions(
$<$<BOOL:${OX_NODEBUG}>:OX_NODEBUG>
)
if(NOT WIN32)
if(NOT WIN32 AND NOT OX_BARE_METAL)
target_link_libraries(
OxStd PUBLIC
$<$<CXX_COMPILER_ID:GNU>:$<$<BOOL:${OX_USE_STDLIB}>:dl>>
dl
)
endif()
target_link_libraries(
+1
View File
@@ -63,6 +63,7 @@ constexpr void oxAssert(const ox::Error&, const char*) noexcept {}
#if defined(_MSC_VER)
#define ox_alloca(size) _alloca(size)
#elif OX_USE_STDLIB
#include <alloca.h>
#define ox_alloca(size) alloca(size)
#else
#define ox_alloca(size) __builtin_alloca(size)
+15
View File
@@ -345,6 +345,21 @@ struct [[nodiscard]] Result {
return *this;
}
constexpr Result reoriginate(
ErrorCode const pErrCode,
CString const pMsg = nullptr,
std::source_location const &pSrc = std::source_location::current()) const && noexcept {
if (error) {
return {std::move(value), Error{pErrCode, pMsg, pSrc}};
}
return {std::move(value)};
}
constexpr Result reoriginate(
std::source_location const &pSrc = std::source_location::current()) const && noexcept {
return {std::move(value), Error{error.errCode, error.msg, pSrc}};
}
};
namespace detail {
+21
View File
@@ -36,6 +36,27 @@ constexpr StringView substr(StringViewCR str, std::size_t const start, std::size
return {};
}
[[nodiscard]]
constexpr char toUpper(char const c) noexcept {
return c & static_cast<char>(0b1101'1111);
}
[[nodiscard]]
constexpr int caseInsensitiveStrCmp(StringViewCR a, StringViewCR b) noexcept {
auto const sz = ox::min(a.size(), b.size());
for (size_t i{}; i < sz; ++i) {
auto const ac = toUpper(a[i]);
auto const bc = toUpper(b[i]);
if (ac < bc) {
return -1;
}
if (ac > bc) {
return 1;
}
}
return 0;
}
[[nodiscard]]
constexpr bool beginsWith(StringViewCR base, char const beginning) noexcept {
return base.size() && base[0] == beginning;
+44 -46
View File
@@ -103,32 +103,33 @@ constexpr bool is_const_v<const T> = true;
// is_integral /////////////////////////////////////////////////////////////////
template<typename T> struct is_integral: false_type {};
template<> struct is_integral<bool> : true_type {};
template<> struct is_integral<wchar_t> : true_type {};
template<> struct is_integral<int8_t> : true_type {};
template<> struct is_integral<uint8_t> : true_type {};
template<> struct is_integral<int16_t> : true_type {};
template<> struct is_integral<uint16_t>: true_type {};
template<> struct is_integral<int32_t> : true_type {};
template<> struct is_integral<uint32_t>: true_type {};
template<> struct is_integral<const bool> : true_type {};
template<> struct is_integral<const wchar_t> : true_type {};
template<> struct is_integral<const int8_t> : true_type {};
template<> struct is_integral<const uint8_t> : true_type {};
template<> struct is_integral<const int16_t> : true_type {};
template<> struct is_integral<const uint16_t>: true_type {};
template<> struct is_integral<const int32_t> : true_type {};
template<> struct is_integral<const uint32_t>: true_type {};
// some of these need to be done with the actual language syntax because no one
// can agree on what an (u)int64_t is...
template<> struct is_integral<long>: true_type {};
template<> struct is_integral<long long>: true_type {};
template<> struct is_integral<unsigned long>: true_type {};
template<> struct is_integral<unsigned long long>: true_type {};
template<> struct is_integral<const long>: true_type {};
template<> struct is_integral<const long long>: true_type {};
template<> struct is_integral<const unsigned long>: true_type {};
template<> struct is_integral<bool> : true_type {};
template<> struct is_integral<wchar_t> : true_type {};
template<> struct is_integral<signed char> : true_type {};
template<> struct is_integral<unsigned char> : true_type {};
template<> struct is_integral<short> : true_type {};
template<> struct is_integral<unsigned short> : true_type {};
template<> struct is_integral<int> : true_type {};
template<> struct is_integral<unsigned int> : true_type {};
template<> struct is_integral<long> : true_type {};
template<> struct is_integral<long long> : true_type {};
template<> struct is_integral<unsigned long> : true_type {};
template<> struct is_integral<unsigned long long> : true_type {};
template<> struct is_integral<const bool> : true_type {};
template<> struct is_integral<const wchar_t> : true_type {};
template<> struct is_integral<const signed char> : true_type {};
template<> struct is_integral<const unsigned char> : true_type {};
template<> struct is_integral<const short> : true_type {};
template<> struct is_integral<const unsigned short> : true_type {};
template<> struct is_integral<const int> : true_type {};
template<> struct is_integral<const unsigned int> : true_type {};
template<> struct is_integral<const long> : true_type {};
template<> struct is_integral<const long long> : true_type {};
template<> struct is_integral<const unsigned long> : true_type {};
template<> struct is_integral<const unsigned long long>: true_type {};
template<typename T>
@@ -138,29 +139,26 @@ constexpr bool is_integral_v = is_integral<T>::value;
// is_integer /////////////////////////////////////////////////////////////////
template<typename T> struct is_integer: false_type {};
template<> struct is_integer<int8_t> : true_type {};
template<> struct is_integer<uint8_t> : true_type {};
template<> struct is_integer<int16_t> : true_type {};
template<> struct is_integer<uint16_t>: true_type {};
template<> struct is_integer<int32_t> : true_type {};
template<> struct is_integer<uint32_t>: true_type {};
template<> struct is_integer<int8_t const> : true_type {};
template<> struct is_integer<uint8_t const> : true_type {};
template<> struct is_integer<int16_t const> : true_type {};
template<> struct is_integer<uint16_t const>: true_type {};
template<> struct is_integer<int32_t const> : true_type {};
template<> struct is_integer<uint32_t const>: true_type {};
// some of these need to be done with the actual language syntax because no one
// can agree on what an (u)int64_t is...
template<> struct is_integer<long>: true_type {};
template<> struct is_integer<long long>: true_type {};
template<> struct is_integer<unsigned long>: true_type {};
template<> struct is_integer<unsigned long long>: true_type {};
template<> struct is_integer<long const>: true_type {};
template<> struct is_integer<long long const>: true_type {};
template<> struct is_integer<unsigned long const>: true_type {};
template<> struct is_integer<unsigned long long const>: true_type {};
template<> struct is_integer<signed char> : true_type {};
template<> struct is_integer<unsigned char> : true_type {};
template<> struct is_integer<short> : true_type {};
template<> struct is_integer<unsigned short> : true_type {};
template<> struct is_integer<int> : true_type {};
template<> struct is_integer<unsigned int> : true_type {};
template<> struct is_integer<long> : true_type {};
template<> struct is_integer<long long> : true_type {};
template<> struct is_integer<unsigned long> : true_type {};
template<> struct is_integer<unsigned long long> : true_type {};
template<> struct is_integer<const signed char> : true_type {};
template<> struct is_integer<const unsigned char> : true_type {};
template<> struct is_integer<const short> : true_type {};
template<> struct is_integer<const unsigned short> : true_type {};
template<> struct is_integer<const int> : true_type {};
template<> struct is_integer<const unsigned int> : true_type {};
template<> struct is_integer<const long> : true_type {};
template<> struct is_integer<const long long> : true_type {};
template<> struct is_integer<const unsigned long> : true_type {};
template<> struct is_integer<const unsigned long long> : true_type {};
template<typename T>
constexpr bool is_integer_v = is_integer<T>::value;
+7
View File
@@ -54,6 +54,10 @@ struct VectorAllocator {
// this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM,
// try removing it later
if (!std::is_constant_evaluated()) {
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overflow="
#endif
if (cap <= m_data.size() && count <= m_data.size()) {
for (auto i = 0u; i < count; ++i) {
auto const srcItem = std::launder(reinterpret_cast<T*>(&src->m_data[i]));
@@ -65,6 +69,9 @@ struct VectorAllocator {
*items = reinterpret_cast<T*>(m_data.data());
}
}
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
}
}
+2 -2
View File
@@ -43,7 +43,7 @@ uint64_t timeMapStrToUuid(int const elemCnt, int const lookups, uint64_t seed =
// start
auto const startTime = steadyNowMs();
for (int i = 0; i < lookups; ++i) {
auto const &k = keys[rand.gen() % keys.size()];
auto const &k = keys[static_cast<size_t>(rand.gen() % keys.size())];
map[k];
ox::expect(map[k], ox::UUID::fromString(k).unwrap());
}
@@ -65,7 +65,7 @@ uint64_t timeMapUuidToStr(int const elemCnt, int const lookups, uint64_t seed =
// start
auto const startTime = steadyNowMs();
for (int i = 0; i < lookups; ++i) {
auto const &k = keys[rand.gen() % keys.size()];
auto const &k = keys[static_cast<size_t>(rand.gen() % keys.size())];
ox::expect(map[k], k.toString());
}
return steadyNowMs() - startTime;
@@ -7,6 +7,7 @@
#include <ox/clargs/clargs.hpp>
#include <ox/std/trace.hpp>
#include <studio/context.hpp>
#include <studio/project.hpp>
#include <nostalgia/gfx/palette.hpp>
@@ -14,10 +15,6 @@
#include "export-tilesheet.hpp"
#include "nostalgia/gfx/tilesheet.hpp"
#include "studio/context.hpp"
namespace nostalgia::gfx {
static ox::Vector<uint32_t> normalizePixelSizes(
@@ -47,3 +47,5 @@ install(
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
add_subdirectory(subcommands)
+49 -3
View File
@@ -14,24 +14,68 @@
#include <studio/context.hpp>
#include <studioapp/studioapp.hpp>
#include "subcommands/change-format/change-format.hpp"
#include "configfile.hpp"
#include "studioui.hpp"
namespace studio {
static ox::Error convertStudioConfigV1ToStudioConfigV2(
keel::Context&,
StudioConfigV1 &src,
StudioConfigV2 &dst) noexcept {
dst.projects.emplace_back(StudioConfigV2::ProjectConfig{
.projectPath = std::move(src.projectPath),
.activeTabItemName = std::move(src.activeTabItemName),
.openFiles = std::move(src.openFiles),
});
dst.showProjectExplorer = src.showProjectExplorer;
return {};
}
static struct: Module {
ox::String id() const noexcept final {
return ox::String{"net.drinkingtea.studio"};
}
ox::Vector<Command> commands() const final {
return {
{
"change-format",
cmdChangeFormat,
}
};
}
} constexpr mod;
static struct: keel::Module {
ox::String id() const noexcept override {
return ox::String{"net.drinkingtea.studio"};
}
ox::Vector<keel::Converter> converters() const noexcept override {
return {
keel::Converter::make<convertStudioConfigV1ToStudioConfigV2>(),
};
}
} constexpr kmod;
class StudioUIDrawer: public turbine::gl::Drawer {
private:
StudioUI &m_ui;
public:
explicit StudioUIDrawer(StudioUI &ui) noexcept: m_ui(ui) {
}
protected:
void draw(turbine::Context&) noexcept final {
m_ui.draw();
}
};
static void keyEventHandler(turbine::Context &ctx, turbine::Key key, bool down) noexcept {
auto const sctx = turbine::applicationData<studio::Context>(ctx);
static void keyEventHandler(turbine::Context &ctx, turbine::Key const key, bool const down) noexcept {
auto const sctx = turbine::applicationData<Context>(ctx);
sctx->ui.handleKeyEvent(key, down);
}
@@ -65,6 +109,8 @@ static ox::Error run(
ox::StringViewCR appName,
ox::StringViewCR projectDataDir,
ox::SpanView<ox::CString> const &args) {
keel::registerModule(kmod);
registerModule(&mod);
// seed UUID generator
auto const time = std::time(nullptr);
ox::UUID::seedGenerator({
@@ -0,0 +1,68 @@
/*
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/std/string.hpp>
#include <ox/std/vector.hpp>
#include <ox/model/def.hpp>
namespace studio {
struct StudioConfigV1 {
static constexpr auto TypeName = "net.drinkingtea.studio.StudioConfig";
static constexpr auto TypeVersion = 1;
ox::String projectPath;
ox::String activeTabItemName;
ox::Vector<ox::String> openFiles;
bool showProjectExplorer = true;
};
OX_MODEL_BEGIN(StudioConfigV1)
OX_MODEL_FIELD_RENAME(activeTabItemName, active_tab_item_name)
OX_MODEL_FIELD_RENAME(projectPath, project_path)
OX_MODEL_FIELD_RENAME(openFiles, open_files)
OX_MODEL_FIELD_RENAME(showProjectExplorer, show_project_explorer)
OX_MODEL_END()
struct StudioConfigV2 {
static constexpr auto TypeName = "net.drinkingtea.studio.StudioConfig";
static constexpr auto TypeVersion = 2;
struct ProjectConfig {
static constexpr auto TypeName = "net.drinkingtea.studio.ProjectConfig";
static constexpr auto TypeVersion = 2;
ox::String projectPath;
ox::String activeTabItemName;
ox::Vector<ox::String> openFiles;
};
ox::Vector<ProjectConfig> projects;
bool showProjectExplorer = true;
[[nodiscard]]
constexpr ProjectConfig const *project() const {
return projects.empty() ? nullptr : &projects[0];
}
[[nodiscard]]
constexpr ProjectConfig *project() {
return projects.empty() ? nullptr : &projects[0];
}
};
OX_MODEL_BEGIN(StudioConfigV2::ProjectConfig)
OX_MODEL_FIELD_RENAME(activeTabItemName, active_tab_item_name)
OX_MODEL_FIELD_RENAME(projectPath, project_path)
OX_MODEL_FIELD_RENAME(openFiles, open_files)
OX_MODEL_END()
OX_MODEL_BEGIN(StudioConfigV2)
OX_MODEL_FIELD(projects)
OX_MODEL_FIELD_RENAME(showProjectExplorer, show_project_explorer)
OX_MODEL_END()
using StudioConfig = StudioConfigV2;
}
@@ -0,0 +1,10 @@
target_sources(
StudioAppLib PRIVATE
change-format/change-format.cpp
)
target_link_libraries(
StudioAppLib PUBLIC
OxClArgs
)
@@ -0,0 +1,67 @@
/*
* Copyright 2016 - 2026 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include <ox/clargs/clargs.hpp>
#include <ox/std/trace.hpp>
#include <studio/project.hpp>
#include "change-format.hpp"
namespace studio {
static ox::Error convertFile(
ox::FileSystem &fs,
ox::TypeStore &ts,
ox::StringViewCR path,
ox::ClawFormat const fmt) noexcept {
OX_REQUIRE_M(buff, fs.read(path).reoriginate(1, "unable to read file"));
OX_REQUIRE(uuid, keel::readUuidHeader(buff));
OX_REQUIRE(obj, keel::readAsset(ts, buff).reoriginate(1, "unable to parse file"));
buff.clear();
ox::BufferWriter writer{&buff};
OX_RETURN_ERROR(keel::writeUuidHeader(writer, uuid));
OX_RETURN_ERROR(ox::writeClaw(obj, writer, fmt));
if (fmt == ox::ClawFormat::Organic) {
*buff.back().value = '\n';
}
OX_RETURN_ERROR(fs.write(path, buff).reoriginate(1, "unable to write file"));
return {};
}
static void printUsage() noexcept {
oxErr("usage: change-format {mc,oc} [files...]\n");
}
[[nodiscard]]
static constexpr ox::Result<ox::ClawFormat> getFmt(ox::StringViewCR fmtStr) noexcept {
if (caseInsensitiveStrCmp(fmtStr, "mc") == 0) {
return ox::ClawFormat::Metal;
} else if (caseInsensitiveStrCmp(fmtStr, "oc") == 0) {
return ox::ClawFormat::Organic;
}
return ox::Error{1, "invalid format"};
}
ox::Error cmdChangeFormat(Project &project, ox::SpanView<ox::CString> const args) noexcept {
if (args.size() < 2) {
printUsage();
return ox::Error{1, "invalid input"};
}
auto const [fmt, fmtErr] = getFmt(args[0]);
if (fmtErr) {
printUsage();
}
auto &fs = project.romFs();
auto &ts = project.typeStore();
for (auto const &file : args + 1) {
auto const err = convertFile(fs, ts, file, fmt);
if (err) {
oxErrf("Failed to convert {}: {}\n", file, err.msg);
}
}
return {};
}
}
@@ -0,0 +1,13 @@
/*
* Copyright 2016 - 2026 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <studio/project.hpp>
namespace studio {
ox::Error cmdChangeFormat(Project &project, ox::SpanView<ox::CString> args) noexcept;
}
@@ -122,6 +122,16 @@ class Project: public ox::SignalHandler {
ox::Error writeTypeStore() noexcept;
[[nodiscard]]
constexpr ox::TypeStore &typeStore() noexcept {
return m_typeStore;
}
[[nodiscard]]
constexpr ox::TypeStore const &typeStore() const noexcept {
return m_typeStore;
}
private:
void buildFileIndex() noexcept;
@@ -155,7 +165,7 @@ template<typename T>
ox::Error Project::writeObj(ox::StringViewCR path, T const &obj, ox::ClawFormat fmt) noexcept {
OX_REQUIRE_M(buff, ox::writeClaw(obj, fmt));
if (fmt == ox::ClawFormat::Organic) {
buff.pop_back();
*buff.back().value = '\n';
}
// write to FS
OX_RETURN_ERROR(mkdir(parentDir(path)));
+3 -1
View File
@@ -14,13 +14,15 @@
namespace studio {
static_assert(fileExt("main.c").value == "c");
static_assert(fileExt("main.cc").value == "cc");
static_assert(fileExt("main.cpp").value == "cpp");
static_assert(fileExt("a.b.c").value == "c");
static_assert(parentDir("/a/b/c") == "/a/b");
static_assert(parentDir("/a/b/c/") == "/a/b");
static void generateTypes(ox::TypeStore &ts) noexcept {
for (auto const mod : keel::modules()) {
for (auto gen : mod->types()) {
for (auto const gen : mod->types()) {
oxLogError(gen(ts));
}
}