From a09a4c1518cbec8e0c987b76c5a77938c31b973b Mon Sep 17 00:00:00 2001 From: Narr the Reg <5944268+german77@users.noreply.github.com> Date: Thu, 21 May 2026 00:18:34 -0600 Subject: [PATCH 1/2] all: Enforce weak / global functions --- include/devenv/seadFontMgr.h | 2 +- include/gfx/seadFrameBuffer.h | 2 +- include/gfx/seadProjection.h | 4 +- include/resource/seadResource.h | 1 + modules/src/devenv/seadFontMgr.cpp | 1 - modules/src/gfx/seadFrameBuffer.cpp | 2 - modules/src/gfx/seadProjection.cpp | 2 + modules/src/math/seadMathCalcCommon.cpp | 91 ++- modules/src/prim/seadStringBuilder.cpp | 823 +++++++++++++++++++----- modules/src/resource/seadResource.cpp | 1 + 10 files changed, 735 insertions(+), 194 deletions(-) diff --git a/include/devenv/seadFontMgr.h b/include/devenv/seadFontMgr.h index 217546d6..ad502ff1 100644 --- a/include/devenv/seadFontMgr.h +++ b/include/devenv/seadFontMgr.h @@ -34,7 +34,7 @@ class UniformBlockBuffer class FontBase { public: - virtual ~FontBase(); + virtual ~FontBase() = default; virtual float getHeight() const = 0; virtual float getWidth() const = 0; diff --git a/include/gfx/seadFrameBuffer.h b/include/gfx/seadFrameBuffer.h index a4337630..728db6b5 100644 --- a/include/gfx/seadFrameBuffer.h +++ b/include/gfx/seadFrameBuffer.h @@ -31,7 +31,7 @@ class LogicalFrameBuffer mPhysicalArea(physical_x, physical_y, physical_x + physical_w, physical_y + physical_h) { } - virtual ~LogicalFrameBuffer(); + virtual ~LogicalFrameBuffer() = default; const Vector2f& getVirtualSize() const { return mVirtualSize; } const BoundBox2f& getPhysicalArea() const { return mPhysicalArea; } diff --git a/include/gfx/seadProjection.h b/include/gfx/seadProjection.h index f3d64fa7..addef964 100644 --- a/include/gfx/seadProjection.h +++ b/include/gfx/seadProjection.h @@ -21,7 +21,7 @@ class Projection public: Projection(); - virtual ~Projection() = default; + virtual ~Projection(); virtual f32 getNear() const = 0; virtual f32 getFar() const = 0; @@ -72,7 +72,7 @@ class PerspectiveProjection : public Projection public: PerspectiveProjection(); PerspectiveProjection(f32 near, f32 far, f32 fovy_rad, f32 aspect); - ~PerspectiveProjection() override; + ~PerspectiveProjection() override = default; f32 getNear() const override; f32 getFar() const override; diff --git a/include/resource/seadResource.h b/include/resource/seadResource.h index fc2e4e02..9267d6a0 100644 --- a/include/resource/seadResource.h +++ b/include/resource/seadResource.h @@ -58,6 +58,7 @@ class IndirectResource : public Resource public: IndirectResource(); + ~IndirectResource() override; void create(sead::ReadStream* stream, u32 size, sead::Heap* heap); diff --git a/modules/src/devenv/seadFontMgr.cpp b/modules/src/devenv/seadFontMgr.cpp index 4c64df75..1ab60c29 100644 --- a/modules/src/devenv/seadFontMgr.cpp +++ b/modules/src/devenv/seadFontMgr.cpp @@ -2,5 +2,4 @@ namespace sead { -FontBase::~FontBase() = default; } // namespace sead diff --git a/modules/src/gfx/seadFrameBuffer.cpp b/modules/src/gfx/seadFrameBuffer.cpp index de45507f..acf30486 100644 --- a/modules/src/gfx/seadFrameBuffer.cpp +++ b/modules/src/gfx/seadFrameBuffer.cpp @@ -2,8 +2,6 @@ namespace sead { -LogicalFrameBuffer::~LogicalFrameBuffer() = default; - FrameBuffer::~FrameBuffer() = default; void FrameBuffer::clearMRT(DrawContext*, u32, const Color4f&) const {} diff --git a/modules/src/gfx/seadProjection.cpp b/modules/src/gfx/seadProjection.cpp index 9cd07d2d..622b0425 100644 --- a/modules/src/gfx/seadProjection.cpp +++ b/modules/src/gfx/seadProjection.cpp @@ -12,6 +12,8 @@ Projection::Projection() mDeviceZOffset = Graphics::sDefaultDeviceZOffset; } +Projection::~Projection() = default; + void Projection::updateAttributesForDirectProjection() {} const Matrix44f& Projection::getProjectionMatrix() const diff --git a/modules/src/math/seadMathCalcCommon.cpp b/modules/src/math/seadMathCalcCommon.cpp index 557ffc59..d1afa91a 100644 --- a/modules/src/math/seadMathCalcCommon.cpp +++ b/modules/src/math/seadMathCalcCommon.cpp @@ -609,8 +609,8 @@ const MathCalcCommon::LogSample MathCalcCommon::cLogTbl[256 + 1]{ {0.6931471824645996, 0.0019512200960889459}, }; -template -T MathCalcCommon::gcd(T x, T y) +template <> +s32 MathCalcCommon::gcd(s32 x, s32 y) { if (x == 0 || y == 0) return 0; @@ -626,18 +626,88 @@ T MathCalcCommon::gcd(T x, T y) return x; } -template -T MathCalcCommon::lcm(T x, T y) +template <> +s32 MathCalcCommon::lcm(s32 x, s32 y) { if (x == 0 || y == 0) return 0; return x / gcd(x, y) * y; } -template s32 MathCalcCommon::gcd(s32 x, s32 y); -template s32 MathCalcCommon::lcm(s32 x, s32 y); -template u32 MathCalcCommon::gcd(u32 x, u32 y); -template u32 MathCalcCommon::lcm(u32 x, u32 y); +template <> +u32 MathCalcCommon::gcd(u32 x, u32 y) +{ + if (x == 0 || y == 0) + return 0; + + while (x != y) + { + if (x > y) + x -= y; + else + y -= x; + } + + return x; +} + +template <> +u32 MathCalcCommon::lcm(u32 x, u32 y) +{ + if (x == 0 || y == 0) + return 0; + return x / gcd(x, y) * y; +} + +template <> +s64 MathCalcCommon::gcd(s64 x, s64 y) +{ + if (x == 0 || y == 0) + return 0; + + while (x != y) + { + if (x > y) + x -= y; + else + y -= x; + } + + return x; +} + +template <> +s64 MathCalcCommon::lcm(s64 x, s64 y) +{ + if (x == 0 || y == 0) + return 0; + return x / gcd(x, y) * y; +} + +template <> +u64 MathCalcCommon::gcd(u64 x, u64 y) +{ + if (x == 0 || y == 0) + return 0; + + while (x != y) + { + if (x > y) + x -= y; + else + y -= x; + } + + return x; +} + +template <> +u64 MathCalcCommon::lcm(u64 x, u64 y) +{ + if (x == 0 || y == 0) + return 0; + return x / gcd(x, y) * y; +} template <> u32 MathCalcCommon::atanIdx_(f32 t) @@ -684,9 +754,4 @@ f32 MathCalcCommon::logTable(f32 x) return cLogTbl[index].log_val + (cLogTbl[index].log_delta * rest) + (more * ln2()); } -template s64 MathCalcCommon::gcd(s64 x, s64 y); -template s64 MathCalcCommon::lcm(s64 x, s64 y); -template u64 MathCalcCommon::gcd(u64 x, u64 y); -template u64 MathCalcCommon::lcm(u64 x, u64 y); - } // namespace sead diff --git a/modules/src/prim/seadStringBuilder.cpp b/modules/src/prim/seadStringBuilder.cpp index e02bb842..e7ac5b11 100644 --- a/modules/src/prim/seadStringBuilder.cpp +++ b/modules/src/prim/seadStringBuilder.cpp @@ -6,6 +6,74 @@ namespace sead { +template <> +s32 StringBuilder::copy(const char* src, s32 copy_length) +{ + char* dst = mBuffer; + const s32 buffer_size = mBufferSize; + SEAD_ASSERT_MSG(src, "str must not be null"); + if (dst == src) + return 0; + + if (copy_length == -1) + copy_length = calcStrLength_(src); + + if (copy_length >= buffer_size) + { + SEAD_ASSERT_MSG(false, "Buffer overflow. (Buffer Size: %d, Copy Size: %d)", buffer_size, + copy_length); + copy_length = buffer_size - 1; + } + + if (copy_length >= 1) + { + MemUtil::copy(dst, src, copy_length * sizeof(char)); + dst[copy_length] = SafeStringBase::cNullChar; + } + else + { + copy_length = 0; + *dst = SafeStringBase::cNullChar; + } + + mLength = copy_length; + return copy_length; +} + +template <> +s32 WStringBuilder::copy(const char16* src, s32 copy_length) +{ + char16* dst = mBuffer; + const s32 buffer_size = mBufferSize; + SEAD_ASSERT_MSG(src, "str must not be null"); + if (dst == src) + return 0; + + if (copy_length == -1) + copy_length = calcStrLength_(src); + + if (copy_length >= buffer_size) + { + SEAD_ASSERT_MSG(false, "Buffer overflow. (Buffer Size: %d, Copy Size: %d)", buffer_size, + copy_length); + copy_length = buffer_size - 1; + } + + if (copy_length >= 1) + { + MemUtil::copy(dst, src, copy_length * sizeof(char16)); + dst[copy_length] = SafeStringBase::cNullChar; + } + else + { + copy_length = 0; + *dst = SafeStringBase::cNullChar; + } + + mLength = copy_length; + return copy_length; +} + template <> StringBuilder* StringBuilder::create(s32 buffer_size, Heap* heap, s32 alignment) { @@ -18,8 +86,8 @@ WStringBuilder* WStringBuilder::create(s32 buffer_size, Heap* heap, s32 alignmen return createImpl_(buffer_size, heap, alignment); } -template -StringBuilderBase* StringBuilderBase::create(const T* str, Heap* heap, s32 alignment) +template <> +StringBuilder* StringBuilder::create(const char* str, Heap* heap, s32 alignment) { const s32 len = calcStrLength_(str); auto* builder = createImpl_(len + 1, heap, alignment); @@ -27,8 +95,14 @@ StringBuilderBase* StringBuilderBase::create(const T* str, Heap* heap, s32 return builder; } -template StringBuilder* StringBuilder::create(const char* str, Heap* heap, s32 alignment); -template WStringBuilder* WStringBuilder::create(const char16* str, Heap* heap, s32 alignment); +template <> +WStringBuilder* WStringBuilder::create(const char16* str, Heap* heap, s32 alignment) +{ + const s32 len = calcStrLength_(str); + auto* builder = createImpl_(len + 1, heap, alignment); + builder->copy(str, len); + return builder; +} template StringBuilderBase* StringBuilderBase::createImpl_(s32 buffer_size, Heap* heap, s32 alignment) @@ -58,14 +132,14 @@ StringBuilderBase* StringBuilderBase::createImpl_(s32 buffer_size, Heap* h } } -template -bool StringBuilderBase::endsWith(const T* suffix) const +template <> +bool StringBuilder::endsWith(const char* suffix) const { const s32 sub_str_len = calcStrLength_(suffix); if (sub_str_len == 0) return true; - const T* strc = mBuffer; + const char* strc = mBuffer; const s32 len = calcLength(); if (len < sub_str_len) @@ -79,50 +153,83 @@ bool StringBuilderBase::endsWith(const T* suffix) const return true; } -template bool StringBuilder::endsWith(const char* suffix) const; -template bool WStringBuilder::endsWith(const char16* suffix) const; +template <> +bool WStringBuilder::endsWith(const char16* suffix) const +{ + const s32 sub_str_len = calcStrLength_(suffix); + if (sub_str_len == 0) + return true; + + const char16* strc = mBuffer; -template -s32 StringBuilderBase::copy(const T* src, s32 copy_length) + const s32 len = calcLength(); + if (len < sub_str_len) + return false; + + for (s32 i = 0; i < sub_str_len; ++i) + { + if (strc[len - sub_str_len + i] != suffix[i]) + return false; + } + return true; +} + +template <> +s32 StringBuilder::copyAt(s32 at_, const char* src, s32 copy_length) { - T* dst = mBuffer; + char* dst = getMutableStringTop_(); const s32 buffer_size = mBufferSize; + SEAD_ASSERT_MSG(src, "str must not be null"); - if (dst == src) - return 0; if (copy_length == -1) copy_length = calcStrLength_(src); - if (copy_length >= buffer_size) + s32 len = this->calcLength(); + s32 at = at_; + if (at_ < 0) { - SEAD_ASSERT_MSG(false, "Buffer overflow. (Buffer Size: %d, Copy Size: %d)", buffer_size, - copy_length); - copy_length = buffer_size - 1; + const s32 at_new = len + at_ + 1; + if (at_new < 0) + { + SEAD_ASSERT_MSG(false, "at(%d) out of range[%d, %d]", at_, -len - 1, len); + at = 0; + goto check_buffer_overflow; + } + at = at_new; } - if (copy_length >= 1) + if (len < at) { - MemUtil::copy(dst, src, copy_length * sizeof(T)); - dst[copy_length] = SafeStringBase::cNullChar; + SEAD_ASSERT_MSG(false, "at(%d) out of range[%d, %d]", at_, -len - 1, len); + copy_length = 0; + return copy_length; } - else + +check_buffer_overflow: + if (at + copy_length >= buffer_size) { - copy_length = 0; - *dst = SafeStringBase::cNullChar; + SEAD_ASSERT_MSG(false, "Buffer overflow. (Buffer Size: %d, At: %d, Copy Length: %d)", + buffer_size, at, copy_length); + copy_length = buffer_size - at - 1; } - mLength = copy_length; + if (copy_length < 1) + return 0; + + MemUtil::copy(dst + at, src, copy_length * sizeof(char)); + if (mLength < at + copy_length) + dst[at + copy_length] = SafeStringBase::cNullChar; + + if (mLength < at + copy_length) + mLength = at + copy_length; return copy_length; } -template s32 StringBuilder::copy(const char* src, s32 copy_length); -template s32 WStringBuilder::copy(const char16* src, s32 copy_length); - -template -s32 StringBuilderBase::copyAt(s32 at_, const T* src, s32 copy_length) +template <> +s32 WStringBuilder::copyAt(s32 at_, const char16* src, s32 copy_length) { - T* dst = getMutableStringTop_(); + char16* dst = getMutableStringTop_(); const s32 buffer_size = mBufferSize; SEAD_ASSERT_MSG(src, "str must not be null"); @@ -162,22 +269,19 @@ s32 StringBuilderBase::copyAt(s32 at_, const T* src, s32 copy_length) if (copy_length < 1) return 0; - MemUtil::copy(dst + at, src, copy_length * sizeof(T)); + MemUtil::copy(dst + at, src, copy_length * sizeof(char16)); if (mLength < at + copy_length) - dst[at + copy_length] = SafeStringBase::cNullChar; + dst[at + copy_length] = SafeStringBase::cNullChar; if (mLength < at + copy_length) mLength = at + copy_length; return copy_length; } -template s32 StringBuilder::copyAt(s32 at, const char* src, s32 copy_length); -template s32 WStringBuilder::copyAt(s32 at, const char16* src, s32 copy_length); - -template -s32 StringBuilderBase::cutOffCopy(const T* src, s32 copy_length) +template <> +s32 StringBuilder::cutOffCopy(const char* src, s32 copy_length) { - T* dst = mBuffer; + char* dst = mBuffer; const s32 buffer_size = mBufferSize; SEAD_ASSERT_MSG(src, "str must not be null"); if (dst == src) @@ -191,26 +295,53 @@ s32 StringBuilderBase::cutOffCopy(const T* src, s32 copy_length) if (copy_length >= 1) { - MemUtil::copy(dst, src, copy_length * sizeof(T)); - dst[copy_length] = SafeStringBase::cNullChar; + MemUtil::copy(dst, src, copy_length * sizeof(char)); + dst[copy_length] = SafeStringBase::cNullChar; } else { copy_length = 0; - *dst = SafeStringBase::cNullChar; + *dst = SafeStringBase::cNullChar; } mLength = copy_length; return copy_length; } -template s32 StringBuilder::cutOffCopy(const char* src, s32 copy_length); -template s32 WStringBuilder::cutOffCopy(const char16* src, s32 copy_length); +template <> +s32 WStringBuilder::cutOffCopy(const char16* src, s32 copy_length) +{ + char16* dst = mBuffer; + const s32 buffer_size = mBufferSize; + SEAD_ASSERT_MSG(src, "str must not be null"); + if (dst == src) + return 0; + + if (copy_length == -1) + copy_length = calcStrLength_(src); -template -s32 StringBuilderBase::cutOffCopyAt(s32 at_, const T* src, s32 copy_length) + if (copy_length >= buffer_size) + copy_length = buffer_size - 1; + + if (copy_length >= 1) + { + MemUtil::copy(dst, src, copy_length * sizeof(char16)); + dst[copy_length] = SafeStringBase::cNullChar; + } + else + { + copy_length = 0; + *dst = SafeStringBase::cNullChar; + } + + mLength = copy_length; + return copy_length; +} + +template <> +s32 StringBuilder::cutOffCopyAt(s32 at_, const char* src, s32 copy_length) { - T* dst = getMutableStringTop_(); + char* dst = getMutableStringTop_(); const s32 buffer_size = mBufferSize; SEAD_ASSERT_MSG(src, "str must not be null"); @@ -246,22 +377,67 @@ s32 StringBuilderBase::cutOffCopyAt(s32 at_, const T* src, s32 copy_length) if (copy_length < 1) return 0; - MemUtil::copy(dst + at, src, copy_length * sizeof(T)); + MemUtil::copy(dst + at, src, copy_length * sizeof(char)); if (mLength < at + copy_length) - dst[at + copy_length] = SafeStringBase::cNullChar; + dst[at + copy_length] = SafeStringBase::cNullChar; if (mLength < at + copy_length) mLength = at + copy_length; return copy_length; } -template s32 StringBuilder::cutOffCopyAt(s32 at, const char* src, s32 copy_length); -template s32 WStringBuilder::cutOffCopyAt(s32 at, const char16* src, s32 copy_length); +template <> +s32 WStringBuilder::cutOffCopyAt(s32 at_, const char16* src, s32 copy_length) +{ + char16* dst = getMutableStringTop_(); + const s32 buffer_size = mBufferSize; -template -s32 StringBuilderBase::copyAtWithTerminate(s32 at_, const T* src, s32 copy_length) + SEAD_ASSERT_MSG(src, "str must not be null"); + + if (copy_length == -1) + copy_length = calcStrLength_(src); + + s32 len = this->calcLength(); + s32 at = at_; + if (at_ < 0) + { + const s32 at_new = len + at_ + 1; + if (at_new < 0) + { + SEAD_ASSERT_MSG(false, "at(%d) out of range[%d, %d]", at_, -len - 1, len); + at = 0; + goto check_buffer_overflow; + } + at = at_new; + } + + if (len < at) + { + SEAD_ASSERT_MSG(false, "at(%d) out of range[%d, %d]", at_, -len - 1, len); + copy_length = 0; + return copy_length; + } + +check_buffer_overflow: + if (at + copy_length >= buffer_size) + copy_length = buffer_size - at - 1; + + if (copy_length < 1) + return 0; + + MemUtil::copy(dst + at, src, copy_length * sizeof(char16)); + if (mLength < at + copy_length) + dst[at + copy_length] = SafeStringBase::cNullChar; + + if (mLength < at + copy_length) + mLength = at + copy_length; + return copy_length; +} + +template <> +s32 StringBuilder::copyAtWithTerminate(s32 at_, const char* src, s32 copy_length) { - T* dst = getMutableStringTop_(); + char* dst = getMutableStringTop_(); const s32 buffer_size = mBufferSize; SEAD_ASSERT_MSG(src, "str must not be null"); @@ -301,19 +477,67 @@ s32 StringBuilderBase::copyAtWithTerminate(s32 at_, const T* src, s32 copy_le if (copy_length < 1) return 0; - MemUtil::copy(dst + at, src, copy_length * sizeof(T)); - dst[at + copy_length] = SafeStringBase::cNullChar; + MemUtil::copy(dst + at, src, copy_length * sizeof(char)); + dst[at + copy_length] = SafeStringBase::cNullChar; if (at <= mLength) mLength = at + copy_length; return copy_length; } -template s32 StringBuilder::copyAtWithTerminate(s32 at, const char* src, s32 copy_length); -template s32 WStringBuilder::copyAtWithTerminate(s32 at, const char16* src, s32 copy_length); +template <> +s32 WStringBuilder::copyAtWithTerminate(s32 at_, const char16* src, s32 copy_length) +{ + char16* dst = getMutableStringTop_(); + const s32 buffer_size = mBufferSize; -template -s32 StringBuilderBase::format(const T* format, ...) + SEAD_ASSERT_MSG(src, "str must not be null"); + + if (copy_length == -1) + copy_length = calcStrLength_(src); + + s32 len = this->calcLength(); + s32 at = at_; + if (at_ < 0) + { + const s32 at_new = len + at_ + 1; + if (at_new < 0) + { + SEAD_ASSERT_MSG(false, "at(%d) out of range[%d, %d]", at_, -len - 1, len); + at = 0; + goto check_buffer_overflow; + } + at = at_new; + } + + if (len < at) + { + SEAD_ASSERT_MSG(false, "at(%d) out of range[%d, %d]", at_, -len - 1, len); + copy_length = 0; + return copy_length; + } + +check_buffer_overflow: + if (at + copy_length >= buffer_size) + { + SEAD_ASSERT_MSG(false, "Buffer overflow. (Buffer Size: %d, At: %d, Copy Length: %d)", + buffer_size, at, copy_length); + copy_length = buffer_size - at - 1; + } + + if (copy_length < 1) + return 0; + + MemUtil::copy(dst + at, src, copy_length * sizeof(char16)); + dst[at + copy_length] = SafeStringBase::cNullChar; + + if (at <= mLength) + mLength = at + copy_length; + return copy_length; +} + +template <> +s32 StringBuilder::format(const char* format, ...) { std::va_list args; va_start(args, format); @@ -322,8 +546,15 @@ s32 StringBuilderBase::format(const T* format, ...) return ret; } -template s32 StringBuilder::format(const char* format, ...); -template s32 WStringBuilder::format(const char16* format, ...); +template <> +s32 WStringBuilder::format(const char16* format, ...) +{ + std::va_list args; + va_start(args, format); + s32 ret = formatV(format, args); + va_end(args); + return ret; +} template <> s32 StringBuilder::formatImpl_(char* s, s32 n, const char* format, va_list args) @@ -342,8 +573,17 @@ s32 WStringBuilder::formatImpl_(char16* s, s32 n, const char16* format, va_list return n - 1; } -template -s32 StringBuilderBase::appendWithFormat(const T* format, ...) +template <> +s32 StringBuilder::appendWithFormat(const char* format, ...) +{ + std::va_list args; + va_start(args, format); + const s32 ret = appendWithFormatV(format, args); + va_end(args); + return ret; +} +template <> +s32 WStringBuilder::appendWithFormat(const char16* format, ...) { std::va_list args; va_start(args, format); @@ -352,13 +592,10 @@ s32 StringBuilderBase::appendWithFormat(const T* format, ...) return ret; } -template s32 StringBuilder::appendWithFormat(const char* format, ...); -template s32 WStringBuilder::appendWithFormat(const char16* format, ...); - -template -s32 StringBuilderBase::append(const T* str, s32 append_length) +template <> +s32 StringBuilder::append(const char* str, s32 append_length) { - T* dst = getMutableStringTop_(); + char* dst = getMutableStringTop_(); const s32 buffer_size = mBufferSize; SEAD_ASSERT_MSG(str, "str must not be null"); @@ -378,15 +615,42 @@ s32 StringBuilderBase::append(const T* str, s32 append_length) if (append_length < 1) return 0; - MemUtil::copy(dst + at, str, append_length * sizeof(T)); - dst[at + append_length] = SafeStringBase::cNullChar; + MemUtil::copy(dst + at, str, append_length * sizeof(char)); + dst[at + append_length] = SafeStringBase::cNullChar; mLength = at + append_length; return append_length; } -template s32 StringBuilder::append(const char* str, s32 append_length); -template s32 WStringBuilder::append(const char16* str, s32 append_length); +template <> +s32 WStringBuilder::append(const char16* str, s32 append_length) +{ + char16* dst = getMutableStringTop_(); + const s32 buffer_size = mBufferSize; + + SEAD_ASSERT_MSG(str, "str must not be null"); + + if (append_length == -1) + append_length = calcStrLength_(str); + + const s32 at = this->calcLength(); + + if (at + append_length >= buffer_size) + { + SEAD_ASSERT_MSG(false, "Buffer overflow. (Buffer Size: %d, At: %d, Str Length: %d)", + buffer_size, at, append_length); + append_length = buffer_size - at - 1; + } + + if (append_length < 1) + return 0; + + MemUtil::copy(dst + at, str, append_length * sizeof(char16)); + dst[at + append_length] = SafeStringBase::cNullChar; + + mLength = at + append_length; + return append_length; +} // NON_MATCHING: regalloc differences template @@ -401,16 +665,31 @@ s32 appendImpl_(T* buffer_, s32* length_, const s32 buffer_size_, T c, s32 num) num = buffer_size_ - length - 1; } - for (s32 i = 0; i < num; ++i) - buffer_[length + i] = c; + for (s32 i = 0; i < num; ++i) + buffer_[length + i] = c; + + buffer_[length + num] = SafeStringBase::cNullChar; + *length_ = length + num; + return num; +} + +template <> +s32 StringBuilder::append(char c, s32 num) +{ + if (num < 0) + { + SEAD_ASSERT_MSG(false, "append error. num < 0, num = %d", num); + return 0; + } + + if (num == 0) + return 0; - buffer_[length + num] = SafeStringBase::cNullChar; - *length_ = length + num; - return num; + return appendImpl_(mBuffer, &mLength, mBufferSize, c, num); } -template -s32 StringBuilderBase::append(T c, s32 num) +template <> +s32 WStringBuilder::append(char16 c, s32 num) { if (num < 0) { @@ -424,14 +703,39 @@ s32 StringBuilderBase::append(T c, s32 num) return appendImpl_(mBuffer, &mLength, mBufferSize, c, num); } -template s32 StringBuilder::append(char c, s32 n); -template s32 WStringBuilder::append(char16 c, s32 n); +template <> +s32 StringBuilder::chop(s32 chop_num) +{ + s32 length = this->calcLength(); + char* buffer = getMutableStringTop_(); + const auto fail = [=] { + SEAD_ASSERT_MSG(false, "chop_num(%d) out of range[0, %d]", chop_num, length); + }; + + if (chop_num < 0) + { + fail(); + return 0; + } -template -s32 StringBuilderBase::chop(s32 chop_num) + if (chop_num > length) + { + fail(); + length = mLength; + chop_num = mLength; + } + + const s32 new_length = length - chop_num; + buffer[new_length] = SafeStringBase::cNullChar; + mLength = new_length; + return chop_num; +} + +template <> +s32 WStringBuilder::chop(s32 chop_num) { s32 length = this->calcLength(); - T* buffer = getMutableStringTop_(); + char16* buffer = getMutableStringTop_(); const auto fail = [=] { SEAD_ASSERT_MSG(false, "chop_num(%d) out of range[0, %d]", chop_num, length); }; @@ -450,16 +754,31 @@ s32 StringBuilderBase::chop(s32 chop_num) } const s32 new_length = length - chop_num; - buffer[new_length] = SafeStringBase::cNullChar; + buffer[new_length] = SafeStringBase::cNullChar; mLength = new_length; return chop_num; } -template s32 StringBuilder::chop(s32 chop_num); -template s32 WStringBuilder::chop(s32 chop_num); +template <> +s32 StringBuilder::chopMatchedChar(char c) +{ + const s32 length = this->calcLength(); + if (length < 1) + return 0; -template -s32 StringBuilderBase::chopMatchedChar(T c) + const s32 new_length = length - 1; + if (mBuffer[new_length] == c) + { + mBuffer[new_length] = SafeStringBase::cNullChar; + mLength = new_length; + return 1; + } + + return 0; +} + +template <> +s32 WStringBuilder::chopMatchedChar(char16 c) { const s32 length = this->calcLength(); if (length < 1) @@ -468,7 +787,7 @@ s32 StringBuilderBase::chopMatchedChar(T c) const s32 new_length = length - 1; if (mBuffer[new_length] == c) { - mBuffer[new_length] = SafeStringBase::cNullChar; + mBuffer[new_length] = SafeStringBase::cNullChar; mLength = new_length; return 1; } @@ -476,22 +795,40 @@ s32 StringBuilderBase::chopMatchedChar(T c) return 0; } -template s32 StringBuilder::chopMatchedChar(char c); -template s32 WStringBuilder::chopMatchedChar(char16 c); +template <> +s32 StringBuilder::chopMatchedChar(const char* characters) +{ + const s32 length = this->calcLength(); + if (length < 1) + return 0; -template -s32 StringBuilderBase::chopMatchedChar(const T* characters) + char* buffer = getMutableStringTop_(); + for (const char* it = characters; *it; ++it) + { + if (buffer[length - 1] == *it) + { + buffer[length - 1] = SafeStringBase::cNullChar; + mLength = length - 1; + return 1; + } + } + + return 0; +} + +template <> +s32 WStringBuilder::chopMatchedChar(const char16* characters) { const s32 length = this->calcLength(); if (length < 1) return 0; - T* buffer = getMutableStringTop_(); - for (const T* it = characters; *it; ++it) + char16* buffer = getMutableStringTop_(); + for (const char16* it = characters; *it; ++it) { if (buffer[length - 1] == *it) { - buffer[length - 1] = SafeStringBase::cNullChar; + buffer[length - 1] = SafeStringBase::cNullChar; mLength = length - 1; return 1; } @@ -500,11 +837,26 @@ s32 StringBuilderBase::chopMatchedChar(const T* characters) return 0; } -template s32 StringBuilder::chopMatchedChar(const char* characters); -template s32 WStringBuilder::chopMatchedChar(const char16* characters); +template <> +s32 StringBuilder::chopUnprintableAsciiChar() +{ + const s32 length = this->calcLength(); + if (length < 1) + return 0; + + const s32 new_length = length - 1; + if (mBuffer[new_length] <= ' ' || mBuffer[new_length] == 0x7F) + { + mBuffer[new_length] = SafeStringBase::cNullChar; + mLength = new_length; + return 1; + } + + return 0; +} -template -s32 StringBuilderBase::chopUnprintableAsciiChar() +template <> +s32 WStringBuilder::chopUnprintableAsciiChar() { const s32 length = this->calcLength(); if (length < 1) @@ -513,7 +865,7 @@ s32 StringBuilderBase::chopUnprintableAsciiChar() const s32 new_length = length - 1; if (mBuffer[new_length] <= ' ' || mBuffer[new_length] == 0x7F) { - mBuffer[new_length] = SafeStringBase::cNullChar; + mBuffer[new_length] = SafeStringBase::cNullChar; mLength = new_length; return 1; } @@ -521,17 +873,42 @@ s32 StringBuilderBase::chopUnprintableAsciiChar() return 0; } -template s32 StringBuilder::chopUnprintableAsciiChar(); -template s32 WStringBuilder::chopUnprintableAsciiChar(); +template <> +s32 StringBuilder::rstrip(const char* characters) +{ + const s32 length = this->calcLength(); + if (length <= 0) + return 0; + + char* buffer = mBuffer; + s32 new_length = length; + const auto should_strip = [characters, buffer](s32 idx) { + for (auto it = characters; *it; ++it) + { + if (buffer[idx] == *it) + return true; + } + return false; + }; + while (new_length >= 1 && should_strip(new_length - 1)) + --new_length; -template -s32 StringBuilderBase::rstrip(const T* characters) + if (length <= new_length) + return 0; + + mBuffer[new_length] = SafeStringBase::cNullChar; + mLength = new_length; + return length - new_length; +} + +template <> +s32 WStringBuilder::rstrip(const char16* characters) { const s32 length = this->calcLength(); if (length <= 0) return 0; - T* buffer = mBuffer; + char16* buffer = mBuffer; s32 new_length = length; const auto should_strip = [characters, buffer](s32 idx) { for (auto it = characters; *it; ++it) @@ -547,23 +924,42 @@ s32 StringBuilderBase::rstrip(const T* characters) if (length <= new_length) return 0; - mBuffer[new_length] = SafeStringBase::cNullChar; + mBuffer[new_length] = SafeStringBase::cNullChar; mLength = new_length; return length - new_length; } -template s32 StringBuilder::rstrip(const char* characters); -template s32 WStringBuilder::rstrip(const char16* characters); +// NON_MATCHING: equivalent, two instruction reorders +template <> +s32 StringBuilder::rstripUnprintableAsciiChars() +{ + const s32 length = this->calcLength(); + if (length <= 0) + return 0; + + char* buffer = mBuffer; + s32 new_length = length; + while (new_length >= 1 && (buffer[new_length - 1] <= 0x20 || buffer[new_length - 1] == 0x7F)) + --new_length; + + if (length <= new_length) + return 0; + + const s32 ret = length - new_length; + mBuffer[new_length] = SafeStringBase::cNullChar; + mLength = new_length; + return ret; +} // NON_MATCHING: equivalent, two instruction reorders -template -s32 StringBuilderBase::rstripUnprintableAsciiChars() +template <> +s32 WStringBuilder::rstripUnprintableAsciiChars() { const s32 length = this->calcLength(); if (length <= 0) return 0; - T* buffer = mBuffer; + char16* buffer = mBuffer; s32 new_length = length; while (new_length >= 1 && (buffer[new_length - 1] <= 0x20 || buffer[new_length - 1] == 0x7F)) --new_length; @@ -572,18 +968,38 @@ s32 StringBuilderBase::rstripUnprintableAsciiChars() return 0; const s32 ret = length - new_length; - mBuffer[new_length] = SafeStringBase::cNullChar; + mBuffer[new_length] = SafeStringBase::cNullChar; mLength = new_length; return ret; } -template s32 StringBuilder::rstripUnprintableAsciiChars(); -template s32 WStringBuilder::rstripUnprintableAsciiChars(); +template <> +s32 StringBuilder::trim(s32 trim_length) +{ + char* mutableString = getMutableStringTop_(); + + if (trim_length >= mBufferSize) + { + SEAD_ASSERT_MSG(false, "trim_length(%d) out of bounds. [0, %d)", trim_length, mBufferSize); + return this->calcLength(); + } -template -s32 StringBuilderBase::trim(s32 trim_length) + if (trim_length < 0) + { + SEAD_ASSERT_MSG(false, "trim_length(%d) out of bounds. [0, %d)", trim_length, mBufferSize); + trim_length = 0; + } + + mutableString[trim_length] = SafeStringBase::cNullChar; + if (trim_length < mLength) + mLength = trim_length; + return trim_length; +} + +template <> +s32 WStringBuilder::trim(s32 trim_length) { - T* mutableString = getMutableStringTop_(); + char16* mutableString = getMutableStringTop_(); if (trim_length >= mBufferSize) { @@ -597,19 +1013,40 @@ s32 StringBuilderBase::trim(s32 trim_length) trim_length = 0; } - mutableString[trim_length] = SafeStringBase::cNullChar; + mutableString[trim_length] = SafeStringBase::cNullChar; if (trim_length < mLength) mLength = trim_length; return trim_length; } -template s32 StringBuilder::trim(s32 trim_length); -template s32 WStringBuilder::trim(s32 trim_length); +template <> +s32 StringBuilder::trimMatchedString(const char* str) +{ + char* buffer = getMutableStringTop_(); + const s32 length = this->calcLength(); -template -s32 StringBuilderBase::trimMatchedString(const T* str) + const s32 trim_str_length = calcStrLength_(str); + const s32 new_length = length - trim_str_length; + + if (length < trim_str_length) + return length; + + char* substring = &buffer[new_length]; + for (s32 i = 0; i < trim_str_length; ++i) + { + if (substring[i] != str[i]) + return length; + } + + buffer[new_length] = SafeStringBase::cNullChar; + mLength = new_length; + return new_length; +} + +template <> +s32 WStringBuilder::trimMatchedString(const char16* str) { - T* buffer = getMutableStringTop_(); + char16* buffer = getMutableStringTop_(); const s32 length = this->calcLength(); const s32 trim_str_length = calcStrLength_(str); @@ -618,26 +1055,41 @@ s32 StringBuilderBase::trimMatchedString(const T* str) if (length < trim_str_length) return length; - T* substring = &buffer[new_length]; + char16* substring = &buffer[new_length]; for (s32 i = 0; i < trim_str_length; ++i) { if (substring[i] != str[i]) return length; } - buffer[new_length] = SafeStringBase::cNullChar; + buffer[new_length] = SafeStringBase::cNullChar; mLength = new_length; return new_length; } -template s32 StringBuilder::trimMatchedString(const char* str); -template s32 WStringBuilder::trimMatchedString(const char16* str); +template <> +s32 StringBuilder::replaceChar(char old_char, char new_char) +{ + const s32 length = this->calcLength(); + char* buffer = getMutableStringTop_(); -template -s32 StringBuilderBase::replaceChar(T old_char, T new_char) + s32 replaced_count = 0; + for (s32 i = 0; i < length; ++i) + { + if (buffer[i] == old_char) + { + ++replaced_count; + buffer[i] = new_char; + } + } + return replaced_count; +} + +template <> +s32 WStringBuilder::replaceChar(char16 old_char, char16 new_char) { const s32 length = this->calcLength(); - T* buffer = getMutableStringTop_(); + char16* buffer = getMutableStringTop_(); s32 replaced_count = 0; for (s32 i = 0; i < length; ++i) @@ -651,14 +1103,49 @@ s32 StringBuilderBase::replaceChar(T old_char, T new_char) return replaced_count; } -template s32 StringBuilder::replaceChar(char old_char, char new_char); -template s32 WStringBuilder::replaceChar(char16 old_char, char16 new_char); +template <> +s32 StringBuilder::replaceCharList(const SafeString& old_chars, const SafeString& new_chars) +{ + char* buffer = getMutableStringTop_(); + const s32 length = this->calcLength(); -template -s32 StringBuilderBase::replaceCharList(const SafeStringBase& old_chars, - const SafeStringBase& new_chars) + s32 old_chars_len = old_chars.calcLength(); + const s32 new_chars_len = new_chars.calcLength(); + + if (old_chars_len != new_chars_len) + { + SEAD_ASSERT_MSG(false, "old_chars(%s).length is not equal to new_chars(%s).length.", + old_chars.cstr(), new_chars.cstr()); + if (old_chars_len > new_chars_len) + old_chars_len = new_chars_len; + } + + const char* old_chars_c = old_chars.cstr(); + const char* new_chars_c = new_chars.cstr(); + + if (length < 1) + return 0; + + s32 replaced_count = 0; + for (s32 i = 0; i < length; ++i) + { + for (s32 character_idx = 0; character_idx < old_chars_len; ++character_idx) + { + if (buffer[i] == old_chars_c[character_idx]) + { + ++replaced_count; + buffer[i] = new_chars_c[character_idx]; + break; + } + } + } + return replaced_count; +} + +template <> +s32 WStringBuilder::replaceCharList(const WSafeString& old_chars, const WSafeString& new_chars) { - T* buffer = getMutableStringTop_(); + char16* buffer = getMutableStringTop_(); const s32 length = this->calcLength(); s32 old_chars_len = old_chars.calcLength(); @@ -668,23 +1155,15 @@ s32 StringBuilderBase::replaceCharList(const SafeStringBase& old_chars, { // Nintendo's code just uses the same format string for both T = char and T = char16_t, // which is undefined behavior and produces annoying format warnings, so let's fix it... - if constexpr (std::is_same()) - { - SEAD_ASSERT_MSG(false, "old_chars(%s).length is not equal to new_chars(%s).length.", - old_chars.cstr(), new_chars.cstr()); - } - else if constexpr (std::is_same()) - { - // There is no standard format specifier for char16_t strings :/ - SEAD_ASSERT_MSG(false, "old_chars(%p).length is not equal to new_chars(%p).length.", - old_chars.cstr(), new_chars.cstr()); - } + // There is no standard format specifier for char16_t strings :/ + SEAD_ASSERT_MSG(false, "old_chars(%p).length is not equal to new_chars(%p).length.", + old_chars.cstr(), new_chars.cstr()); if (old_chars_len > new_chars_len) old_chars_len = new_chars_len; } - const T* old_chars_c = old_chars.cstr(); - const T* new_chars_c = new_chars.cstr(); + const char16* old_chars_c = old_chars.cstr(); + const char16* new_chars_c = new_chars.cstr(); if (length < 1) return 0; @@ -705,11 +1184,6 @@ s32 StringBuilderBase::replaceCharList(const SafeStringBase& old_chars, return replaced_count; } -template s32 StringBuilder::replaceCharList(const SafeString& old_chars, - const SafeString& new_chars); -template s32 WStringBuilder::replaceCharList(const WSafeString& old_chars, - const WSafeString& new_chars); - template template s32 StringBuilderBase::convertFromOtherType_(const OtherType* src, s32 src_size) @@ -744,28 +1218,29 @@ s32 StringBuilderBase::convertFromOtherType_(const OtherType* src, s32 src_si return copy_size; } -template -s32 StringBuilderBase::convertFromMultiByteString(const char* str, s32 str_length) +template <> +s32 StringBuilder::convertFromMultiByteString(const char* str, s32 str_length) { - if constexpr (std::is_same()) - return copy(str, str_length); - else - return convertFromOtherType_(str, str_length); + return copy(str, str_length); } -template -s32 StringBuilderBase::convertFromWideCharString(const char16* str, s32 str_length) +template <> +s32 StringBuilder::convertFromWideCharString(const char16* str, s32 str_length) { - if constexpr (std::is_same()) - return copy(str, str_length); - else - return convertFromOtherType_(str, str_length); + return convertFromOtherType_(str, str_length); +} + +template <> +s32 WStringBuilder::convertFromMultiByteString(const char* str, s32 str_length) +{ + return convertFromOtherType_(str, str_length); } -template s32 StringBuilder::convertFromMultiByteString(const char* str, s32 str_length); -template s32 StringBuilder::convertFromWideCharString(const char16* str, s32 str_length); -template s32 WStringBuilder::convertFromMultiByteString(const char* str, s32 str_length); -template s32 WStringBuilder::convertFromWideCharString(const char16* str, s32 str_length); +template <> +s32 WStringBuilder::convertFromWideCharString(const char16* str, s32 str_length) +{ + return copy(str, str_length); +} template s32 StringBuilderBase::cutOffAppend(const T* str, s32 append_length) diff --git a/modules/src/resource/seadResource.cpp b/modules/src/resource/seadResource.cpp index 29806131..b874fd80 100644 --- a/modules/src/resource/seadResource.cpp +++ b/modules/src/resource/seadResource.cpp @@ -38,6 +38,7 @@ void DirectResource::create(u8* buffer, u32 bufferSize, u32 allocSize, bool allo } IndirectResource::IndirectResource() = default; +IndirectResource::~IndirectResource() = default; void IndirectResource::create(sead::ReadStream* stream, u32 size, sead::Heap* heap) { From 2b535112288da40bda191c02a3d1b85e771d58f9 Mon Sep 17 00:00:00 2001 From: Narr the Reg <5944268+german77@users.noreply.github.com> Date: Fri, 29 May 2026 10:43:01 -0600 Subject: [PATCH 2/2] Use inline Impl to avoid code duplication --- CMakeLists.txt | 1 - include/prim/seadStringBuilder.h | 26 + modules/src/devenv/seadFontMgr.cpp | 5 - modules/src/math/seadMathCalcCommon.cpp | 102 +-- modules/src/prim/seadStringBuilder.cpp | 876 +++++++++--------------- 5 files changed, 374 insertions(+), 636 deletions(-) delete mode 100644 modules/src/devenv/seadFontMgr.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index edbe2783..bf8f0c6e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,7 +59,6 @@ add_library(sead OBJECT include/devenv/seadGameConfig.h include/devenv/seadStackTrace.h modules/src/devenv/seadAssertConfig.cpp - modules/src/devenv/seadFontMgr.cpp modules/src/devenv/seadGameConfig.cpp modules/src/devenv/seadStackTrace.cpp diff --git a/include/prim/seadStringBuilder.h b/include/prim/seadStringBuilder.h index 786c9ca8..9f3513f5 100644 --- a/include/prim/seadStringBuilder.h +++ b/include/prim/seadStringBuilder.h @@ -180,6 +180,32 @@ class StringBuilderBase template s32 convertFromOtherType_(const OtherType* src, s32 src_size); + s32 copyImpl_(const T* src, s32 copy_length); + bool endsWithImpl_(const T* suffix) const; + s32 copyAtImpl_(s32 at, const T* src, s32 copy_length); + s32 cutOffCopyImpl_(const T* src, s32 copy_length); + s32 cutOffCopyAtImpl_(s32 at, const T* src, s32 copy_length); + s32 copyAtWithTerminateImpl_(s32 at, const T* src, s32 copy_length); + s32 appendImpl_(const T* str, s32 append_length); + s32 appendImpl_(T* buffer, s32* length_, const s32 buffer_size, T c, s32 num); + s32 chopImpl_(s32 chop_num); + s32 chopMatchedCharImpl_(T c); + s32 chopMatchedCharImpl_(const T* characters); + s32 chopUnprintableAsciiCharImpl_(); + s32 rstripImpl_(const T* characters); + s32 rstripUnprintableAsciiCharsImpl_(); + s32 trimImpl_(s32 trim_length); + s32 trimMatchedStringImpl_(const T* str); + s32 replaceCharImpl_(T old_char, T new_char); + inline s32 replaceCharListImpl_(const SafeStringBase& old_chars, + const SafeStringBase& new_chars); + s32 convertFromMultiByteStringImpl_(const char* str, s32 str_length); + s32 convertFromWideCharStringImpl_(const char16* str, s32 str_length); + s32 cutOffAppendImpl_(const T* str, s32 append_length); + s32 cutOffAppendImpl_(T c, s32 num); + s32 prependImpl_(const T* str, s32 prepend_length); + s32 prependImpl_(T c, s32 num); + T* getMutableStringTop_() const { return mBuffer; } T* mBuffer; diff --git a/modules/src/devenv/seadFontMgr.cpp b/modules/src/devenv/seadFontMgr.cpp deleted file mode 100644 index 1ab60c29..00000000 --- a/modules/src/devenv/seadFontMgr.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "devenv/seadFontMgr.h" - -namespace sead -{ -} // namespace sead diff --git a/modules/src/math/seadMathCalcCommon.cpp b/modules/src/math/seadMathCalcCommon.cpp index d1afa91a..61690a75 100644 --- a/modules/src/math/seadMathCalcCommon.cpp +++ b/modules/src/math/seadMathCalcCommon.cpp @@ -608,9 +608,8 @@ const MathCalcCommon::LogSample MathCalcCommon::cLogTbl[256 + 1]{ {0.6911921501159668, 0.0019550349097698927}, {0.6931471824645996, 0.0019512200960889459}, }; - -template <> -s32 MathCalcCommon::gcd(s32 x, s32 y) +template +T gcdImpl_(T x, T y) { if (x == 0 || y == 0) return 0; @@ -626,87 +625,36 @@ s32 MathCalcCommon::gcd(s32 x, s32 y) return x; } -template <> -s32 MathCalcCommon::lcm(s32 x, s32 y) -{ - if (x == 0 || y == 0) - return 0; - return x / gcd(x, y) * y; -} - -template <> -u32 MathCalcCommon::gcd(u32 x, u32 y) +template +T lcmImpl_(T x, T y) { if (x == 0 || y == 0) return 0; - - while (x != y) - { - if (x > y) - x -= y; - else - y -= x; - } - - return x; + return x / gcdImpl_(x, y) * y; } template <> -u32 MathCalcCommon::lcm(u32 x, u32 y) -{ - if (x == 0 || y == 0) - return 0; - return x / gcd(x, y) * y; -} - -template <> -s64 MathCalcCommon::gcd(s64 x, s64 y) +s32 MathCalcCommon::gcd(s32 x, s32 y) { - if (x == 0 || y == 0) - return 0; - - while (x != y) - { - if (x > y) - x -= y; - else - y -= x; - } - - return x; + return gcdImpl_(x, y); } template <> -s64 MathCalcCommon::lcm(s64 x, s64 y) +s32 MathCalcCommon::lcm(s32 x, s32 y) { - if (x == 0 || y == 0) - return 0; - return x / gcd(x, y) * y; + return lcmImpl_(x, y); } template <> -u64 MathCalcCommon::gcd(u64 x, u64 y) +u32 MathCalcCommon::gcd(u32 x, u32 y) { - if (x == 0 || y == 0) - return 0; - - while (x != y) - { - if (x > y) - x -= y; - else - y -= x; - } - - return x; + return gcdImpl_(x, y); } template <> -u64 MathCalcCommon::lcm(u64 x, u64 y) +u32 MathCalcCommon::lcm(u32 x, u32 y) { - if (x == 0 || y == 0) - return 0; - return x / gcd(x, y) * y; + return lcmImpl_(x, y); } template <> @@ -754,4 +702,28 @@ f32 MathCalcCommon::logTable(f32 x) return cLogTbl[index].log_val + (cLogTbl[index].log_delta * rest) + (more * ln2()); } +template <> +s64 MathCalcCommon::gcd(s64 x, s64 y) +{ + return gcdImpl_(x, y); +} + +template <> +s64 MathCalcCommon::lcm(s64 x, s64 y) +{ + return lcmImpl_(x, y); +} + +template <> +u64 MathCalcCommon::gcd(u64 x, u64 y) +{ + return gcdImpl_(x, y); +} + +template <> +u64 MathCalcCommon::lcm(u64 x, u64 y) +{ + return lcmImpl_(x, y); +} + } // namespace sead diff --git a/modules/src/prim/seadStringBuilder.cpp b/modules/src/prim/seadStringBuilder.cpp index e7ac5b11..cb89b2a0 100644 --- a/modules/src/prim/seadStringBuilder.cpp +++ b/modules/src/prim/seadStringBuilder.cpp @@ -6,10 +6,10 @@ namespace sead { -template <> -s32 StringBuilder::copy(const char* src, s32 copy_length) +template +s32 StringBuilderBase::copyImpl_(const T* src, s32 copy_length) { - char* dst = mBuffer; + T* dst = mBuffer; const s32 buffer_size = mBufferSize; SEAD_ASSERT_MSG(src, "str must not be null"); if (dst == src) @@ -27,13 +27,13 @@ s32 StringBuilder::copy(const char* src, s32 copy_length) if (copy_length >= 1) { - MemUtil::copy(dst, src, copy_length * sizeof(char)); - dst[copy_length] = SafeStringBase::cNullChar; + MemUtil::copy(dst, src, copy_length * sizeof(T)); + dst[copy_length] = SafeStringBase::cNullChar; } else { copy_length = 0; - *dst = SafeStringBase::cNullChar; + *dst = SafeStringBase::cNullChar; } mLength = copy_length; @@ -41,37 +41,15 @@ s32 StringBuilder::copy(const char* src, s32 copy_length) } template <> -s32 WStringBuilder::copy(const char16* src, s32 copy_length) +s32 StringBuilder::copy(const char* src, s32 copy_length) { - char16* dst = mBuffer; - const s32 buffer_size = mBufferSize; - SEAD_ASSERT_MSG(src, "str must not be null"); - if (dst == src) - return 0; - - if (copy_length == -1) - copy_length = calcStrLength_(src); - - if (copy_length >= buffer_size) - { - SEAD_ASSERT_MSG(false, "Buffer overflow. (Buffer Size: %d, Copy Size: %d)", buffer_size, - copy_length); - copy_length = buffer_size - 1; - } - - if (copy_length >= 1) - { - MemUtil::copy(dst, src, copy_length * sizeof(char16)); - dst[copy_length] = SafeStringBase::cNullChar; - } - else - { - copy_length = 0; - *dst = SafeStringBase::cNullChar; - } + return copyImpl_(src, copy_length); +} - mLength = copy_length; - return copy_length; +template <> +s32 WStringBuilder::copy(const char16* src, s32 copy_length) +{ + return copyImpl_(src, copy_length); } template <> @@ -132,14 +110,14 @@ StringBuilderBase* StringBuilderBase::createImpl_(s32 buffer_size, Heap* h } } -template <> -bool StringBuilder::endsWith(const char* suffix) const +template +bool StringBuilderBase::endsWithImpl_(const T* suffix) const { const s32 sub_str_len = calcStrLength_(suffix); if (sub_str_len == 0) return true; - const char* strc = mBuffer; + const T* strc = mBuffer; const s32 len = calcLength(); if (len < sub_str_len) @@ -154,30 +132,21 @@ bool StringBuilder::endsWith(const char* suffix) const } template <> -bool WStringBuilder::endsWith(const char16* suffix) const +bool StringBuilder::endsWith(const char* suffix) const { - const s32 sub_str_len = calcStrLength_(suffix); - if (sub_str_len == 0) - return true; - - const char16* strc = mBuffer; - - const s32 len = calcLength(); - if (len < sub_str_len) - return false; - - for (s32 i = 0; i < sub_str_len; ++i) - { - if (strc[len - sub_str_len + i] != suffix[i]) - return false; - } - return true; + return endsWithImpl_(suffix); } template <> -s32 StringBuilder::copyAt(s32 at_, const char* src, s32 copy_length) +bool WStringBuilder::endsWith(const char16* suffix) const +{ + return endsWithImpl_(suffix); +} + +template +s32 StringBuilderBase::copyAtImpl_(s32 at, const T* src, s32 copy_length) { - char* dst = getMutableStringTop_(); + T* dst = getMutableStringTop_(); const s32 buffer_size = mBufferSize; SEAD_ASSERT_MSG(src, "str must not be null"); @@ -186,13 +155,12 @@ s32 StringBuilder::copyAt(s32 at_, const char* src, s32 copy_length) copy_length = calcStrLength_(src); s32 len = this->calcLength(); - s32 at = at_; - if (at_ < 0) + if (at < 0) { - const s32 at_new = len + at_ + 1; + const s32 at_new = len + at + 1; if (at_new < 0) { - SEAD_ASSERT_MSG(false, "at(%d) out of range[%d, %d]", at_, -len - 1, len); + SEAD_ASSERT_MSG(false, "at(%d) out of range[%d, %d]", at, -len - 1, len); at = 0; goto check_buffer_overflow; } @@ -201,7 +169,7 @@ s32 StringBuilder::copyAt(s32 at_, const char* src, s32 copy_length) if (len < at) { - SEAD_ASSERT_MSG(false, "at(%d) out of range[%d, %d]", at_, -len - 1, len); + SEAD_ASSERT_MSG(false, "at(%d) out of range[%d, %d]", at, -len - 1, len); copy_length = 0; return copy_length; } @@ -217,9 +185,9 @@ s32 StringBuilder::copyAt(s32 at_, const char* src, s32 copy_length) if (copy_length < 1) return 0; - MemUtil::copy(dst + at, src, copy_length * sizeof(char)); + MemUtil::copy(dst + at, src, copy_length * sizeof(T)); if (mLength < at + copy_length) - dst[at + copy_length] = SafeStringBase::cNullChar; + dst[at + copy_length] = SafeStringBase::cNullChar; if (mLength < at + copy_length) mLength = at + copy_length; @@ -227,61 +195,21 @@ s32 StringBuilder::copyAt(s32 at_, const char* src, s32 copy_length) } template <> -s32 WStringBuilder::copyAt(s32 at_, const char16* src, s32 copy_length) +s32 StringBuilder::copyAt(s32 at, const char* src, s32 copy_length) { - char16* dst = getMutableStringTop_(); - const s32 buffer_size = mBufferSize; - - SEAD_ASSERT_MSG(src, "str must not be null"); - - if (copy_length == -1) - copy_length = calcStrLength_(src); - - s32 len = this->calcLength(); - s32 at = at_; - if (at_ < 0) - { - const s32 at_new = len + at_ + 1; - if (at_new < 0) - { - SEAD_ASSERT_MSG(false, "at(%d) out of range[%d, %d]", at_, -len - 1, len); - at = 0; - goto check_buffer_overflow; - } - at = at_new; - } - - if (len < at) - { - SEAD_ASSERT_MSG(false, "at(%d) out of range[%d, %d]", at_, -len - 1, len); - copy_length = 0; - return copy_length; - } - -check_buffer_overflow: - if (at + copy_length >= buffer_size) - { - SEAD_ASSERT_MSG(false, "Buffer overflow. (Buffer Size: %d, At: %d, Copy Length: %d)", - buffer_size, at, copy_length); - copy_length = buffer_size - at - 1; - } - - if (copy_length < 1) - return 0; - - MemUtil::copy(dst + at, src, copy_length * sizeof(char16)); - if (mLength < at + copy_length) - dst[at + copy_length] = SafeStringBase::cNullChar; - - if (mLength < at + copy_length) - mLength = at + copy_length; - return copy_length; + return copyAtImpl_(at, src, copy_length); } template <> -s32 StringBuilder::cutOffCopy(const char* src, s32 copy_length) +s32 WStringBuilder::copyAt(s32 at, const char16* src, s32 copy_length) { - char* dst = mBuffer; + return copyAtImpl_(at, src, copy_length); +} + +template +s32 StringBuilderBase::cutOffCopyImpl_(const T* src, s32 copy_length) +{ + T* dst = mBuffer; const s32 buffer_size = mBufferSize; SEAD_ASSERT_MSG(src, "str must not be null"); if (dst == src) @@ -295,13 +223,13 @@ s32 StringBuilder::cutOffCopy(const char* src, s32 copy_length) if (copy_length >= 1) { - MemUtil::copy(dst, src, copy_length * sizeof(char)); - dst[copy_length] = SafeStringBase::cNullChar; + MemUtil::copy(dst, src, copy_length * sizeof(T)); + dst[copy_length] = SafeStringBase::cNullChar; } else { copy_length = 0; - *dst = SafeStringBase::cNullChar; + *dst = SafeStringBase::cNullChar; } mLength = copy_length; @@ -309,39 +237,21 @@ s32 StringBuilder::cutOffCopy(const char* src, s32 copy_length) } template <> -s32 WStringBuilder::cutOffCopy(const char16* src, s32 copy_length) +s32 StringBuilder::cutOffCopy(const char* src, s32 copy_length) { - char16* dst = mBuffer; - const s32 buffer_size = mBufferSize; - SEAD_ASSERT_MSG(src, "str must not be null"); - if (dst == src) - return 0; - - if (copy_length == -1) - copy_length = calcStrLength_(src); - - if (copy_length >= buffer_size) - copy_length = buffer_size - 1; - - if (copy_length >= 1) - { - MemUtil::copy(dst, src, copy_length * sizeof(char16)); - dst[copy_length] = SafeStringBase::cNullChar; - } - else - { - copy_length = 0; - *dst = SafeStringBase::cNullChar; - } - - mLength = copy_length; - return copy_length; + return cutOffCopyImpl_(src, copy_length); } template <> -s32 StringBuilder::cutOffCopyAt(s32 at_, const char* src, s32 copy_length) +s32 WStringBuilder::cutOffCopy(const char16* src, s32 copy_length) { - char* dst = getMutableStringTop_(); + return cutOffCopyImpl_(src, copy_length); +} + +template +s32 StringBuilderBase::cutOffCopyAtImpl_(s32 at, const T* src, s32 copy_length) +{ + T* dst = getMutableStringTop_(); const s32 buffer_size = mBufferSize; SEAD_ASSERT_MSG(src, "str must not be null"); @@ -350,13 +260,12 @@ s32 StringBuilder::cutOffCopyAt(s32 at_, const char* src, s32 copy_length) copy_length = calcStrLength_(src); s32 len = this->calcLength(); - s32 at = at_; - if (at_ < 0) + if (at < 0) { - const s32 at_new = len + at_ + 1; + const s32 at_new = len + at + 1; if (at_new < 0) { - SEAD_ASSERT_MSG(false, "at(%d) out of range[%d, %d]", at_, -len - 1, len); + SEAD_ASSERT_MSG(false, "at(%d) out of range[%d, %d]", at, -len - 1, len); at = 0; goto check_buffer_overflow; } @@ -365,7 +274,7 @@ s32 StringBuilder::cutOffCopyAt(s32 at_, const char* src, s32 copy_length) if (len < at) { - SEAD_ASSERT_MSG(false, "at(%d) out of range[%d, %d]", at_, -len - 1, len); + SEAD_ASSERT_MSG(false, "at(%d) out of range[%d, %d]", at, -len - 1, len); copy_length = 0; return copy_length; } @@ -377,9 +286,9 @@ s32 StringBuilder::cutOffCopyAt(s32 at_, const char* src, s32 copy_length) if (copy_length < 1) return 0; - MemUtil::copy(dst + at, src, copy_length * sizeof(char)); + MemUtil::copy(dst + at, src, copy_length * sizeof(T)); if (mLength < at + copy_length) - dst[at + copy_length] = SafeStringBase::cNullChar; + dst[at + copy_length] = SafeStringBase::cNullChar; if (mLength < at + copy_length) mLength = at + copy_length; @@ -387,57 +296,21 @@ s32 StringBuilder::cutOffCopyAt(s32 at_, const char* src, s32 copy_length) } template <> -s32 WStringBuilder::cutOffCopyAt(s32 at_, const char16* src, s32 copy_length) +s32 StringBuilder::cutOffCopyAt(s32 at, const char* src, s32 copy_length) { - char16* dst = getMutableStringTop_(); - const s32 buffer_size = mBufferSize; - - SEAD_ASSERT_MSG(src, "str must not be null"); - - if (copy_length == -1) - copy_length = calcStrLength_(src); - - s32 len = this->calcLength(); - s32 at = at_; - if (at_ < 0) - { - const s32 at_new = len + at_ + 1; - if (at_new < 0) - { - SEAD_ASSERT_MSG(false, "at(%d) out of range[%d, %d]", at_, -len - 1, len); - at = 0; - goto check_buffer_overflow; - } - at = at_new; - } - - if (len < at) - { - SEAD_ASSERT_MSG(false, "at(%d) out of range[%d, %d]", at_, -len - 1, len); - copy_length = 0; - return copy_length; - } - -check_buffer_overflow: - if (at + copy_length >= buffer_size) - copy_length = buffer_size - at - 1; - - if (copy_length < 1) - return 0; - - MemUtil::copy(dst + at, src, copy_length * sizeof(char16)); - if (mLength < at + copy_length) - dst[at + copy_length] = SafeStringBase::cNullChar; - - if (mLength < at + copy_length) - mLength = at + copy_length; - return copy_length; + return cutOffCopyAtImpl_(at, src, copy_length); } template <> -s32 StringBuilder::copyAtWithTerminate(s32 at_, const char* src, s32 copy_length) +s32 WStringBuilder::cutOffCopyAt(s32 at, const char16* src, s32 copy_length) +{ + return cutOffCopyAtImpl_(at, src, copy_length); +} + +template +s32 StringBuilderBase::copyAtWithTerminateImpl_(s32 at, const T* src, s32 copy_length) { - char* dst = getMutableStringTop_(); + T* dst = getMutableStringTop_(); const s32 buffer_size = mBufferSize; SEAD_ASSERT_MSG(src, "str must not be null"); @@ -446,13 +319,12 @@ s32 StringBuilder::copyAtWithTerminate(s32 at_, const char* src, s32 copy_length copy_length = calcStrLength_(src); s32 len = this->calcLength(); - s32 at = at_; - if (at_ < 0) + if (at < 0) { - const s32 at_new = len + at_ + 1; + const s32 at_new = len + at + 1; if (at_new < 0) { - SEAD_ASSERT_MSG(false, "at(%d) out of range[%d, %d]", at_, -len - 1, len); + SEAD_ASSERT_MSG(false, "at(%d) out of range[%d, %d]", at, -len - 1, len); at = 0; goto check_buffer_overflow; } @@ -461,7 +333,7 @@ s32 StringBuilder::copyAtWithTerminate(s32 at_, const char* src, s32 copy_length if (len < at) { - SEAD_ASSERT_MSG(false, "at(%d) out of range[%d, %d]", at_, -len - 1, len); + SEAD_ASSERT_MSG(false, "at(%d) out of range[%d, %d]", at, -len - 1, len); copy_length = 0; return copy_length; } @@ -477,8 +349,8 @@ s32 StringBuilder::copyAtWithTerminate(s32 at_, const char* src, s32 copy_length if (copy_length < 1) return 0; - MemUtil::copy(dst + at, src, copy_length * sizeof(char)); - dst[at + copy_length] = SafeStringBase::cNullChar; + MemUtil::copy(dst + at, src, copy_length * sizeof(T)); + dst[at + copy_length] = SafeStringBase::cNullChar; if (at <= mLength) mLength = at + copy_length; @@ -486,54 +358,15 @@ s32 StringBuilder::copyAtWithTerminate(s32 at_, const char* src, s32 copy_length } template <> -s32 WStringBuilder::copyAtWithTerminate(s32 at_, const char16* src, s32 copy_length) +s32 StringBuilder::copyAtWithTerminate(s32 at, const char* src, s32 copy_length) { - char16* dst = getMutableStringTop_(); - const s32 buffer_size = mBufferSize; - - SEAD_ASSERT_MSG(src, "str must not be null"); - - if (copy_length == -1) - copy_length = calcStrLength_(src); - - s32 len = this->calcLength(); - s32 at = at_; - if (at_ < 0) - { - const s32 at_new = len + at_ + 1; - if (at_new < 0) - { - SEAD_ASSERT_MSG(false, "at(%d) out of range[%d, %d]", at_, -len - 1, len); - at = 0; - goto check_buffer_overflow; - } - at = at_new; - } - - if (len < at) - { - SEAD_ASSERT_MSG(false, "at(%d) out of range[%d, %d]", at_, -len - 1, len); - copy_length = 0; - return copy_length; - } - -check_buffer_overflow: - if (at + copy_length >= buffer_size) - { - SEAD_ASSERT_MSG(false, "Buffer overflow. (Buffer Size: %d, At: %d, Copy Length: %d)", - buffer_size, at, copy_length); - copy_length = buffer_size - at - 1; - } - - if (copy_length < 1) - return 0; - - MemUtil::copy(dst + at, src, copy_length * sizeof(char16)); - dst[at + copy_length] = SafeStringBase::cNullChar; + return copyAtWithTerminateImpl_(at, src, copy_length); +} - if (at <= mLength) - mLength = at + copy_length; - return copy_length; +template <> +s32 WStringBuilder::copyAtWithTerminate(s32 at, const char16* src, s32 copy_length) +{ + return copyAtWithTerminateImpl_(at, src, copy_length); } template <> @@ -582,6 +415,7 @@ s32 StringBuilder::appendWithFormat(const char* format, ...) va_end(args); return ret; } + template <> s32 WStringBuilder::appendWithFormat(const char16* format, ...) { @@ -592,10 +426,10 @@ s32 WStringBuilder::appendWithFormat(const char16* format, ...) return ret; } -template <> -s32 StringBuilder::append(const char* str, s32 append_length) +template +s32 StringBuilderBase::appendImpl_(const T* str, s32 append_length) { - char* dst = getMutableStringTop_(); + T* dst = getMutableStringTop_(); const s32 buffer_size = mBufferSize; SEAD_ASSERT_MSG(str, "str must not be null"); @@ -615,60 +449,51 @@ s32 StringBuilder::append(const char* str, s32 append_length) if (append_length < 1) return 0; - MemUtil::copy(dst + at, str, append_length * sizeof(char)); - dst[at + append_length] = SafeStringBase::cNullChar; + MemUtil::copy(dst + at, str, append_length * sizeof(T)); + dst[at + append_length] = SafeStringBase::cNullChar; mLength = at + append_length; return append_length; } template <> -s32 WStringBuilder::append(const char16* str, s32 append_length) +s32 StringBuilder::append(const char* str, s32 append_length) { - char16* dst = getMutableStringTop_(); - const s32 buffer_size = mBufferSize; - - SEAD_ASSERT_MSG(str, "str must not be null"); - - if (append_length == -1) - append_length = calcStrLength_(str); + return appendImpl_(str, append_length); +} - const s32 at = this->calcLength(); +template <> +s32 WStringBuilder::append(const char16* str, s32 append_length) +{ + return appendImpl_(str, append_length); +} - if (at + append_length >= buffer_size) +// NON_MATCHING: regalloc differences +template +s32 StringBuilderBase::appendImpl_(T* buffer, s32* length_, const s32 buffer_size, T c, s32 num) +{ + if (num < 0) { - SEAD_ASSERT_MSG(false, "Buffer overflow. (Buffer Size: %d, At: %d, Str Length: %d)", - buffer_size, at, append_length); - append_length = buffer_size - at - 1; + SEAD_ASSERT_MSG(false, "append error. num < 0, num = %d", num); + return 0; } - if (append_length < 1) + if (num == 0) return 0; - MemUtil::copy(dst + at, str, append_length * sizeof(char16)); - dst[at + append_length] = SafeStringBase::cNullChar; - - mLength = at + append_length; - return append_length; -} - -// NON_MATCHING: regalloc differences -template -s32 appendImpl_(T* buffer_, s32* length_, const s32 buffer_size_, T c, s32 num) -{ const s32 length = *length_; - if (buffer_size_ <= num + length) + if (buffer_size <= num + length) { SEAD_ASSERT_MSG(false, "Buffer overflow. (Buffer Size: %d, Length: %d, Num: %d)", - buffer_size_, length, num); - num = buffer_size_ - length - 1; + buffer_size, length, num); + num = buffer_size - length - 1; } for (s32 i = 0; i < num; ++i) - buffer_[length + i] = c; + buffer[length + i] = c; - buffer_[length + num] = SafeStringBase::cNullChar; + buffer[length + num] = SafeStringBase::cNullChar; *length_ = length + num; return num; } @@ -676,38 +501,20 @@ s32 appendImpl_(T* buffer_, s32* length_, const s32 buffer_size_, T c, s32 num) template <> s32 StringBuilder::append(char c, s32 num) { - if (num < 0) - { - SEAD_ASSERT_MSG(false, "append error. num < 0, num = %d", num); - return 0; - } - - if (num == 0) - return 0; - return appendImpl_(mBuffer, &mLength, mBufferSize, c, num); } template <> s32 WStringBuilder::append(char16 c, s32 num) { - if (num < 0) - { - SEAD_ASSERT_MSG(false, "append error. num < 0, num = %d", num); - return 0; - } - - if (num == 0) - return 0; - return appendImpl_(mBuffer, &mLength, mBufferSize, c, num); } -template <> -s32 StringBuilder::chop(s32 chop_num) +template +s32 StringBuilderBase::chopImpl_(s32 chop_num) { s32 length = this->calcLength(); - char* buffer = getMutableStringTop_(); + T* buffer = getMutableStringTop_(); const auto fail = [=] { SEAD_ASSERT_MSG(false, "chop_num(%d) out of range[0, %d]", chop_num, length); }; @@ -726,59 +533,25 @@ s32 StringBuilder::chop(s32 chop_num) } const s32 new_length = length - chop_num; - buffer[new_length] = SafeStringBase::cNullChar; + buffer[new_length] = SafeStringBase::cNullChar; mLength = new_length; return chop_num; } template <> -s32 WStringBuilder::chop(s32 chop_num) +s32 StringBuilder::chop(s32 chop_num) { - s32 length = this->calcLength(); - char16* buffer = getMutableStringTop_(); - const auto fail = [=] { - SEAD_ASSERT_MSG(false, "chop_num(%d) out of range[0, %d]", chop_num, length); - }; - - if (chop_num < 0) - { - fail(); - return 0; - } - - if (chop_num > length) - { - fail(); - length = mLength; - chop_num = mLength; - } - - const s32 new_length = length - chop_num; - buffer[new_length] = SafeStringBase::cNullChar; - mLength = new_length; - return chop_num; + return chopImpl_(chop_num); } template <> -s32 StringBuilder::chopMatchedChar(char c) +s32 WStringBuilder::chop(s32 chop_num) { - const s32 length = this->calcLength(); - if (length < 1) - return 0; - - const s32 new_length = length - 1; - if (mBuffer[new_length] == c) - { - mBuffer[new_length] = SafeStringBase::cNullChar; - mLength = new_length; - return 1; - } - - return 0; + return chopImpl_(chop_num); } -template <> -s32 WStringBuilder::chopMatchedChar(char16 c) +template +s32 StringBuilderBase::chopMatchedCharImpl_(T c) { const s32 length = this->calcLength(); if (length < 1) @@ -787,48 +560,39 @@ s32 WStringBuilder::chopMatchedChar(char16 c) const s32 new_length = length - 1; if (mBuffer[new_length] == c) { - mBuffer[new_length] = SafeStringBase::cNullChar; - mLength = new_length; - return 1; - } - - return 0; -} - -template <> -s32 StringBuilder::chopMatchedChar(const char* characters) -{ - const s32 length = this->calcLength(); - if (length < 1) - return 0; - - char* buffer = getMutableStringTop_(); - for (const char* it = characters; *it; ++it) - { - if (buffer[length - 1] == *it) - { - buffer[length - 1] = SafeStringBase::cNullChar; - mLength = length - 1; - return 1; - } + mBuffer[new_length] = SafeStringBase::cNullChar; + mLength = new_length; + return 1; } return 0; } template <> -s32 WStringBuilder::chopMatchedChar(const char16* characters) +s32 StringBuilder::chopMatchedChar(char c) +{ + return chopMatchedCharImpl_(c); +} + +template <> +s32 WStringBuilder::chopMatchedChar(char16 c) +{ + return chopMatchedCharImpl_(c); +} + +template +s32 StringBuilderBase::chopMatchedCharImpl_(const T* characters) { const s32 length = this->calcLength(); if (length < 1) return 0; - char16* buffer = getMutableStringTop_(); - for (const char16* it = characters; *it; ++it) + T* buffer = getMutableStringTop_(); + for (const T* it = characters; *it; ++it) { if (buffer[length - 1] == *it) { - buffer[length - 1] = SafeStringBase::cNullChar; + buffer[length - 1] = SafeStringBase::cNullChar; mLength = length - 1; return 1; } @@ -838,25 +602,19 @@ s32 WStringBuilder::chopMatchedChar(const char16* characters) } template <> -s32 StringBuilder::chopUnprintableAsciiChar() +s32 StringBuilder::chopMatchedChar(const char* characters) { - const s32 length = this->calcLength(); - if (length < 1) - return 0; - - const s32 new_length = length - 1; - if (mBuffer[new_length] <= ' ' || mBuffer[new_length] == 0x7F) - { - mBuffer[new_length] = SafeStringBase::cNullChar; - mLength = new_length; - return 1; - } - - return 0; + return chopMatchedCharImpl_(characters); } template <> -s32 WStringBuilder::chopUnprintableAsciiChar() +s32 WStringBuilder::chopMatchedChar(const char16* characters) +{ + return chopMatchedCharImpl_(characters); +} + +template +s32 StringBuilderBase::chopUnprintableAsciiCharImpl_() { const s32 length = this->calcLength(); if (length < 1) @@ -865,7 +623,7 @@ s32 WStringBuilder::chopUnprintableAsciiChar() const s32 new_length = length - 1; if (mBuffer[new_length] <= ' ' || mBuffer[new_length] == 0x7F) { - mBuffer[new_length] = SafeStringBase::cNullChar; + mBuffer[new_length] = SafeStringBase::cNullChar; mLength = new_length; return 1; } @@ -874,41 +632,25 @@ s32 WStringBuilder::chopUnprintableAsciiChar() } template <> -s32 StringBuilder::rstrip(const char* characters) +s32 StringBuilder::chopUnprintableAsciiChar() { - const s32 length = this->calcLength(); - if (length <= 0) - return 0; - - char* buffer = mBuffer; - s32 new_length = length; - const auto should_strip = [characters, buffer](s32 idx) { - for (auto it = characters; *it; ++it) - { - if (buffer[idx] == *it) - return true; - } - return false; - }; - while (new_length >= 1 && should_strip(new_length - 1)) - --new_length; - - if (length <= new_length) - return 0; - - mBuffer[new_length] = SafeStringBase::cNullChar; - mLength = new_length; - return length - new_length; + return chopUnprintableAsciiCharImpl_(); } template <> -s32 WStringBuilder::rstrip(const char16* characters) +s32 WStringBuilder::chopUnprintableAsciiChar() +{ + return chopUnprintableAsciiCharImpl_(); +} + +template +s32 StringBuilderBase::rstripImpl_(const T* characters) { const s32 length = this->calcLength(); if (length <= 0) return 0; - char16* buffer = mBuffer; + T* buffer = mBuffer; s32 new_length = length; const auto should_strip = [characters, buffer](s32 idx) { for (auto it = characters; *it; ++it) @@ -924,42 +666,31 @@ s32 WStringBuilder::rstrip(const char16* characters) if (length <= new_length) return 0; - mBuffer[new_length] = SafeStringBase::cNullChar; + mBuffer[new_length] = SafeStringBase::cNullChar; mLength = new_length; return length - new_length; } -// NON_MATCHING: equivalent, two instruction reorders template <> -s32 StringBuilder::rstripUnprintableAsciiChars() +s32 StringBuilder::rstrip(const char* characters) { - const s32 length = this->calcLength(); - if (length <= 0) - return 0; - - char* buffer = mBuffer; - s32 new_length = length; - while (new_length >= 1 && (buffer[new_length - 1] <= 0x20 || buffer[new_length - 1] == 0x7F)) - --new_length; - - if (length <= new_length) - return 0; - - const s32 ret = length - new_length; - mBuffer[new_length] = SafeStringBase::cNullChar; - mLength = new_length; - return ret; + return rstripImpl_(characters); } -// NON_MATCHING: equivalent, two instruction reorders template <> -s32 WStringBuilder::rstripUnprintableAsciiChars() +s32 WStringBuilder::rstrip(const char16* characters) +{ + return rstripImpl_(characters); +} + +template +s32 StringBuilderBase::rstripUnprintableAsciiCharsImpl_() { const s32 length = this->calcLength(); if (length <= 0) return 0; - char16* buffer = mBuffer; + T* buffer = mBuffer; s32 new_length = length; while (new_length >= 1 && (buffer[new_length - 1] <= 0x20 || buffer[new_length - 1] == 0x7F)) --new_length; @@ -968,38 +699,26 @@ s32 WStringBuilder::rstripUnprintableAsciiChars() return 0; const s32 ret = length - new_length; - mBuffer[new_length] = SafeStringBase::cNullChar; + mBuffer[new_length] = SafeStringBase::cNullChar; mLength = new_length; return ret; } template <> -s32 StringBuilder::trim(s32 trim_length) +s32 StringBuilder::rstripUnprintableAsciiChars() { - char* mutableString = getMutableStringTop_(); - - if (trim_length >= mBufferSize) - { - SEAD_ASSERT_MSG(false, "trim_length(%d) out of bounds. [0, %d)", trim_length, mBufferSize); - return this->calcLength(); - } - - if (trim_length < 0) - { - SEAD_ASSERT_MSG(false, "trim_length(%d) out of bounds. [0, %d)", trim_length, mBufferSize); - trim_length = 0; - } - - mutableString[trim_length] = SafeStringBase::cNullChar; - if (trim_length < mLength) - mLength = trim_length; - return trim_length; + return rstripUnprintableAsciiCharsImpl_(); } - template <> -s32 WStringBuilder::trim(s32 trim_length) +s32 WStringBuilder::rstripUnprintableAsciiChars() +{ + return rstripUnprintableAsciiCharsImpl_(); +} + +template +s32 StringBuilderBase::trimImpl_(s32 trim_length) { - char16* mutableString = getMutableStringTop_(); + T* mutableString = getMutableStringTop_(); if (trim_length >= mBufferSize) { @@ -1013,40 +732,28 @@ s32 WStringBuilder::trim(s32 trim_length) trim_length = 0; } - mutableString[trim_length] = SafeStringBase::cNullChar; + mutableString[trim_length] = SafeStringBase::cNullChar; if (trim_length < mLength) mLength = trim_length; return trim_length; } template <> -s32 StringBuilder::trimMatchedString(const char* str) +s32 StringBuilder::trim(s32 trim_length) { - char* buffer = getMutableStringTop_(); - const s32 length = this->calcLength(); - - const s32 trim_str_length = calcStrLength_(str); - const s32 new_length = length - trim_str_length; - - if (length < trim_str_length) - return length; - - char* substring = &buffer[new_length]; - for (s32 i = 0; i < trim_str_length; ++i) - { - if (substring[i] != str[i]) - return length; - } - - buffer[new_length] = SafeStringBase::cNullChar; - mLength = new_length; - return new_length; + return trimImpl_(trim_length); } template <> -s32 WStringBuilder::trimMatchedString(const char16* str) +s32 WStringBuilder::trim(s32 trim_length) +{ + return trimImpl_(trim_length); +} + +template +s32 StringBuilderBase::trimMatchedStringImpl_(const T* str) { - char16* buffer = getMutableStringTop_(); + T* buffer = getMutableStringTop_(); const s32 length = this->calcLength(); const s32 trim_str_length = calcStrLength_(str); @@ -1055,41 +762,35 @@ s32 WStringBuilder::trimMatchedString(const char16* str) if (length < trim_str_length) return length; - char16* substring = &buffer[new_length]; + T* substring = &buffer[new_length]; for (s32 i = 0; i < trim_str_length; ++i) { if (substring[i] != str[i]) return length; } - buffer[new_length] = SafeStringBase::cNullChar; + buffer[new_length] = SafeStringBase::cNullChar; mLength = new_length; return new_length; } template <> -s32 StringBuilder::replaceChar(char old_char, char new_char) +s32 StringBuilder::trimMatchedString(const char* str) { - const s32 length = this->calcLength(); - char* buffer = getMutableStringTop_(); - - s32 replaced_count = 0; - for (s32 i = 0; i < length; ++i) - { - if (buffer[i] == old_char) - { - ++replaced_count; - buffer[i] = new_char; - } - } - return replaced_count; + return trimMatchedStringImpl_(str); } template <> -s32 WStringBuilder::replaceChar(char16 old_char, char16 new_char) +s32 WStringBuilder::trimMatchedString(const char16* str) +{ + return trimMatchedStringImpl_(str); +} + +template +s32 StringBuilderBase::replaceCharImpl_(T old_char, T new_char) { const s32 length = this->calcLength(); - char16* buffer = getMutableStringTop_(); + T* buffer = getMutableStringTop_(); s32 replaced_count = 0; for (s32 i = 0; i < length; ++i) @@ -1104,48 +805,22 @@ s32 WStringBuilder::replaceChar(char16 old_char, char16 new_char) } template <> -s32 StringBuilder::replaceCharList(const SafeString& old_chars, const SafeString& new_chars) +s32 StringBuilder::replaceChar(char old_char, char new_char) { - char* buffer = getMutableStringTop_(); - const s32 length = this->calcLength(); - - s32 old_chars_len = old_chars.calcLength(); - const s32 new_chars_len = new_chars.calcLength(); - - if (old_chars_len != new_chars_len) - { - SEAD_ASSERT_MSG(false, "old_chars(%s).length is not equal to new_chars(%s).length.", - old_chars.cstr(), new_chars.cstr()); - if (old_chars_len > new_chars_len) - old_chars_len = new_chars_len; - } - - const char* old_chars_c = old_chars.cstr(); - const char* new_chars_c = new_chars.cstr(); - - if (length < 1) - return 0; - - s32 replaced_count = 0; - for (s32 i = 0; i < length; ++i) - { - for (s32 character_idx = 0; character_idx < old_chars_len; ++character_idx) - { - if (buffer[i] == old_chars_c[character_idx]) - { - ++replaced_count; - buffer[i] = new_chars_c[character_idx]; - break; - } - } - } - return replaced_count; + return replaceCharImpl_(old_char, new_char); } template <> -s32 WStringBuilder::replaceCharList(const WSafeString& old_chars, const WSafeString& new_chars) +s32 WStringBuilder::replaceChar(char16 old_char, char16 new_char) +{ + return replaceCharImpl_(old_char, new_char); +} + +template +s32 StringBuilderBase::replaceCharListImpl_(const SafeStringBase& old_chars, + const SafeStringBase& new_chars) { - char16* buffer = getMutableStringTop_(); + T* buffer = getMutableStringTop_(); const s32 length = this->calcLength(); s32 old_chars_len = old_chars.calcLength(); @@ -1155,15 +830,23 @@ s32 WStringBuilder::replaceCharList(const WSafeString& old_chars, const WSafeStr { // Nintendo's code just uses the same format string for both T = char and T = char16_t, // which is undefined behavior and produces annoying format warnings, so let's fix it... - // There is no standard format specifier for char16_t strings :/ - SEAD_ASSERT_MSG(false, "old_chars(%p).length is not equal to new_chars(%p).length.", - old_chars.cstr(), new_chars.cstr()); + if constexpr (std::is_same()) + { + SEAD_ASSERT_MSG(false, "old_chars(%s).length is not equal to new_chars(%s).length.", + old_chars.cstr(), new_chars.cstr()); + } + else if constexpr (std::is_same()) + { + // There is no standard format specifier for char16_t strings :/ + SEAD_ASSERT_MSG(false, "old_chars(%p).length is not equal to new_chars(%p).length.", + old_chars.cstr(), new_chars.cstr()); + } if (old_chars_len > new_chars_len) old_chars_len = new_chars_len; } - const char16* old_chars_c = old_chars.cstr(); - const char16* new_chars_c = new_chars.cstr(); + const T* old_chars_c = old_chars.cstr(); + const T* new_chars_c = new_chars.cstr(); if (length < 1) return 0; @@ -1184,6 +867,18 @@ s32 WStringBuilder::replaceCharList(const WSafeString& old_chars, const WSafeStr return replaced_count; } +template <> +s32 StringBuilder::replaceCharList(const SafeString& old_chars, const SafeString& new_chars) +{ + return replaceCharListImpl_(old_chars, new_chars); +} + +template <> +s32 WStringBuilder::replaceCharList(const WSafeString& old_chars, const WSafeString& new_chars) +{ + return replaceCharListImpl_(old_chars, new_chars); +} + template template s32 StringBuilderBase::convertFromOtherType_(const OtherType* src, s32 src_size) @@ -1218,32 +913,47 @@ s32 StringBuilderBase::convertFromOtherType_(const OtherType* src, s32 src_si return copy_size; } +template +s32 StringBuilderBase::convertFromMultiByteStringImpl_(const char* str, s32 str_length) +{ + if constexpr (std::is_same()) + return copy(str, str_length); + else + return convertFromOtherType_(str, str_length); +} + +template +s32 StringBuilderBase::convertFromWideCharStringImpl_(const char16* str, s32 str_length) +{ + if constexpr (std::is_same()) + return copy(str, str_length); + else + return convertFromOtherType_(str, str_length); +} + template <> s32 StringBuilder::convertFromMultiByteString(const char* str, s32 str_length) { - return copy(str, str_length); + return convertFromMultiByteStringImpl_(str, str_length); } - template <> s32 StringBuilder::convertFromWideCharString(const char16* str, s32 str_length) { - return convertFromOtherType_(str, str_length); + return convertFromWideCharStringImpl_(str, str_length); } - template <> s32 WStringBuilder::convertFromMultiByteString(const char* str, s32 str_length) { - return convertFromOtherType_(str, str_length); + return convertFromMultiByteStringImpl_(str, str_length); } - template <> s32 WStringBuilder::convertFromWideCharString(const char16* str, s32 str_length) { - return copy(str, str_length); + return convertFromWideCharStringImpl_(str, str_length); } template -s32 StringBuilderBase::cutOffAppend(const T* str, s32 append_length) +s32 StringBuilderBase::cutOffAppendImpl_(const T* str, s32 append_length) { T* dst = getMutableStringTop_(); const s32 buffer_size = mBufferSize; @@ -1268,11 +978,20 @@ s32 StringBuilderBase::cutOffAppend(const T* str, s32 append_length) return append_length; } -template s32 StringBuilder::cutOffAppend(const char* str, s32 append_length); -template s32 WStringBuilder::cutOffAppend(const char16* str, s32 append_length); +template <> +s32 StringBuilder::cutOffAppend(const char* str, s32 append_length) +{ + return cutOffAppendImpl_(str, append_length); +} + +template <> +s32 WStringBuilder::cutOffAppend(const char16* str, s32 append_length) +{ + return cutOffAppendImpl_(str, append_length); +} template -s32 StringBuilderBase::cutOffAppend(T c, s32 num) +s32 StringBuilderBase::cutOffAppendImpl_(T c, s32 num) { if (num < 0) { @@ -1301,12 +1020,21 @@ s32 StringBuilderBase::cutOffAppend(T c, s32 num) return num; } -template s32 StringBuilder::cutOffAppend(char c, s32 num); -template s32 WStringBuilder::cutOffAppend(char16 c, s32 num); +template <> +s32 StringBuilder::cutOffAppend(char c, s32 num) +{ + return cutOffAppendImpl_(c, num); +} + +template <> +s32 WStringBuilder::cutOffAppend(char16 c, s32 num) +{ + return cutOffAppendImpl_(c, num); +} // NON_MATCHING: operands to some `add` instructions are swapped template -s32 StringBuilderBase::prepend(const T* str, s32 prepend_length) +s32 StringBuilderBase::prependImpl_(const T* str, s32 prepend_length) { T* buffer = getMutableStringTop_(); const s32 buffer_size = mBufferSize; @@ -1342,12 +1070,21 @@ s32 StringBuilderBase::prepend(const T* str, s32 prepend_length) return move_length + prepend_length - length; } -template s32 StringBuilder::prepend(const char* str, s32 prepend_length); -template s32 WStringBuilder::prepend(const char16* str, s32 prepend_length); +template <> +s32 StringBuilder::prepend(const char* str, s32 prepend_length) +{ + return prependImpl_(str, prepend_length); +} + +template <> +s32 WStringBuilder::prepend(const char16* str, s32 prepend_length) +{ + return prependImpl_(str, prepend_length); +} // NON_MATCHING: same regalloc issue as append() template -s32 StringBuilderBase::prepend(T c, s32 num) +s32 StringBuilderBase::prependImpl_(T c, s32 num) { if (num < 0) { @@ -1382,6 +1119,15 @@ s32 StringBuilderBase::prepend(T c, s32 num) return num + move_length - length; } -template s32 StringBuilder::prepend(char c, s32 length); -template s32 WStringBuilder::prepend(char16_t c, s32 length); +template <> +s32 StringBuilder::prepend(char c, s32 length) +{ + return prependImpl_(c, length); +} + +template <> +s32 WStringBuilder::prepend(char16_t c, s32 length) +{ + return prependImpl_(c, length); +} } // namespace sead