aboutsummaryrefslogtreecommitdiff
path: root/zencore/string.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'zencore/string.cpp')
-rw-r--r--zencore/string.cpp1004
1 files changed, 0 insertions, 1004 deletions
diff --git a/zencore/string.cpp b/zencore/string.cpp
deleted file mode 100644
index ad6ee78fc..000000000
--- a/zencore/string.cpp
+++ /dev/null
@@ -1,1004 +0,0 @@
-// Copyright Epic Games, Inc. All Rights Reserved.
-
-#include <zencore/memory.h>
-#include <zencore/string.h>
-#include <zencore/testing.h>
-
-#include <inttypes.h>
-#include <math.h>
-#include <stdio.h>
-#include <exception>
-#include <ostream>
-#include <stdexcept>
-
-#include <utf8.h>
-
-template<typename u16bit_iterator>
-void
-utf16to8_impl(u16bit_iterator StartIt, u16bit_iterator EndIt, ::zen::StringBuilderBase& OutString)
-{
- while (StartIt != EndIt)
- {
- uint32_t cp = utf8::internal::mask16(*StartIt++);
- // Take care of surrogate pairs first
- if (utf8::internal::is_lead_surrogate(cp))
- {
- uint32_t trail_surrogate = utf8::internal::mask16(*StartIt++);
- cp = (cp << 10) + trail_surrogate + utf8::internal::SURROGATE_OFFSET;
- }
- OutString.AppendCodepoint(cp);
- }
-}
-
-template<typename u32bit_iterator>
-void
-utf32to8_impl(u32bit_iterator StartIt, u32bit_iterator EndIt, ::zen::StringBuilderBase& OutString)
-{
- for (; StartIt != EndIt; ++StartIt)
- {
- wchar_t cp = *StartIt;
- OutString.AppendCodepoint(cp);
- }
-}
-
-//////////////////////////////////////////////////////////////////////////
-
-namespace zen {
-
-bool
-ToString(std::span<char> Buffer, uint64_t Num)
-{
- snprintf(Buffer.data(), Buffer.size(), "%" PRIu64, Num);
-
- return true;
-}
-bool
-ToString(std::span<char> Buffer, int64_t Num)
-{
- snprintf(Buffer.data(), Buffer.size(), "%" PRId64, Num);
-
- return true;
-}
-
-//////////////////////////////////////////////////////////////////////////
-
-const char*
-FilepathFindExtension(const std::string_view& Path, const char* ExtensionToMatch)
-{
- const size_t PathLen = Path.size();
-
- if (ExtensionToMatch)
- {
- size_t ExtLen = strlen(ExtensionToMatch);
-
- if (ExtLen > PathLen)
- return nullptr;
-
- const char* PathExtension = Path.data() + PathLen - ExtLen;
-
- if (StringEquals(PathExtension, ExtensionToMatch))
- return PathExtension;
-
- return nullptr;
- }
-
- if (PathLen == 0)
- return nullptr;
-
- // Look for extension introducer ('.')
-
- for (int64_t i = PathLen - 1; i >= 0; --i)
- {
- if (Path[i] == '.')
- return Path.data() + i;
- }
-
- return nullptr;
-}
-
-//////////////////////////////////////////////////////////////////////////
-
-void
-Utf8ToWide(const char8_t* Str8, WideStringBuilderBase& OutString)
-{
- Utf8ToWide(std::u8string_view(Str8), OutString);
-}
-
-void
-Utf8ToWide(const std::string_view& Str8, WideStringBuilderBase& OutString)
-{
- Utf8ToWide(std::u8string_view{reinterpret_cast<const char8_t*>(Str8.data()), Str8.size()}, OutString);
-}
-
-std::wstring
-Utf8ToWide(const std::string_view& Wstr)
-{
- ExtendableWideStringBuilder<128> String;
- Utf8ToWide(Wstr, String);
-
- return String.c_str();
-}
-
-void
-Utf8ToWide(const std::u8string_view& Str8, WideStringBuilderBase& OutString)
-{
- const char* str = (const char*)Str8.data();
- const size_t strLen = Str8.size();
-
- const char* endStr = str + strLen;
- size_t ByteCount = 0;
- size_t CurrentOutChar = 0;
-
- for (; str != endStr; ++str)
- {
- unsigned char Data = static_cast<unsigned char>(*str);
-
- if (!(Data & 0x80))
- {
- // ASCII
- OutString.Append(wchar_t(Data));
- continue;
- }
- else if (!ByteCount)
- {
- // Start of multi-byte sequence. Figure out how
- // many bytes we're going to consume
-
- size_t Count = 0;
-
- for (size_t Temp = Data; Temp & 0x80; Temp <<= 1)
- ++Count;
-
- ByteCount = Count - 1;
- CurrentOutChar = Data & (0xff >> (Count + 1));
- }
- else
- {
- --ByteCount;
-
- if ((Data & 0xc0) != 0x80)
- {
- break;
- }
-
- CurrentOutChar = (CurrentOutChar << 6) | (Data & 0x3f);
-
- if (!ByteCount)
- {
- OutString.Append(wchar_t(CurrentOutChar));
- CurrentOutChar = 0;
- }
- }
- }
-}
-
-void
-WideToUtf8(const wchar_t* Wstr, StringBuilderBase& OutString)
-{
- WideToUtf8(std::wstring_view{Wstr}, OutString);
-}
-
-void
-WideToUtf8(const std::wstring_view& Wstr, StringBuilderBase& OutString)
-{
-#if ZEN_SIZEOF_WCHAR_T == 2
- utf16to8_impl(begin(Wstr), end(Wstr), OutString);
-#else
- utf32to8_impl(begin(Wstr), end(Wstr), OutString);
-#endif
-}
-
-std::string
-WideToUtf8(const wchar_t* Wstr)
-{
- ExtendableStringBuilder<128> String;
- WideToUtf8(std::wstring_view{Wstr}, String);
-
- return String.c_str();
-}
-
-std::string
-WideToUtf8(const std::wstring_view Wstr)
-{
- ExtendableStringBuilder<128> String;
- WideToUtf8(std::wstring_view{Wstr.data(), Wstr.size()}, String);
-
- return String.c_str();
-}
-
-//////////////////////////////////////////////////////////////////////////
-
-enum NicenumFormat
-{
- kNicenum1024 = 0, // Print kilo, mega, tera, peta, exa..
- kNicenumBytes = 1, // Print single bytes ("13B"), kilo, mega, tera...
- kNicenumTime = 2, // Print nanosecs, microsecs, millisecs, seconds...
- kNicenumRaw = 3, // Print the raw number without any formatting
- kNicenumRawTime = 4 // Same as RAW, but print dashes ('-') for zero.
-};
-
-namespace {
- static const char* UnitStrings[3][7] = {
- /* kNicenum1024 */ {"", "K", "M", "G", "T", "P", "E"},
- /* kNicenumBytes */ {"B", "K", "M", "G", "T", "P", "E"},
- /* kNicenumTime */ {"ns", "us", "ms", "s", "?", "?", "?"}};
-
- static const int UnitsLen[] = {
- /* kNicenum1024 */ 6,
- /* kNicenumBytes */ 6,
- /* kNicenumTime */ 3};
-
- static const uint64_t KiloUnit[] = {
- /* kNicenum1024 */ 1024,
- /* kNicenumBytes */ 1024,
- /* kNicenumTime */ 1000};
-} // namespace
-
-/*
- * Convert a number to an appropriately human-readable output.
- */
-int
-NiceNumGeneral(uint64_t Num, std::span<char> Buffer, NicenumFormat Format)
-{
- switch (Format)
- {
- case kNicenumRaw:
- return snprintf(Buffer.data(), Buffer.size(), "%" PRIu64, (uint64_t)Num);
-
- case kNicenumRawTime:
- if (Num > 0)
- {
- return snprintf(Buffer.data(), Buffer.size(), "%" PRIu64, (uint64_t)Num);
- }
- else
- {
- return snprintf(Buffer.data(), Buffer.size(), "%s", "-");
- }
- break;
-
- case kNicenum1024:
- case kNicenumBytes:
- case kNicenumTime:
- default:
- break;
- }
-
- // Bring into range and select unit
-
- int Index = 0;
- uint64_t n = Num;
-
- {
- const uint64_t Unit = KiloUnit[Format];
- const int maxIndex = UnitsLen[Format];
-
- while (n >= Unit && Index < maxIndex)
- {
- n /= Unit;
- Index++;
- }
- }
-
- const char* u = UnitStrings[Format][Index];
-
- if ((Index == 0) || ((Num % (uint64_t)powl((int)KiloUnit[Format], Index)) == 0))
- {
- /*
- * If this is an even multiple of the base, always display
- * without any decimal precision.
- */
- return snprintf(Buffer.data(), Buffer.size(), "%" PRIu64 "%s", (uint64_t)n, u);
- }
- else
- {
- /*
- * We want to choose a precision that reflects the best choice
- * for fitting in 5 characters. This can get rather tricky when
- * we have numbers that are very close to an order of magnitude.
- * For example, when displaying 10239 (which is really 9.999K),
- * we want only a single place of precision for 10.0K. We could
- * develop some complex heuristics for this, but it's much
- * easier just to try each combination in turn.
- */
-
- int StrLen = 0;
-
- for (int i = 2; i >= 0; i--)
- {
- double Value = (double)Num / (uint64_t)powl((int)KiloUnit[Format], Index);
-
- /*
- * Don't print floating point values for time. Note,
- * we use floor() instead of round() here, since
- * round can result in undesirable results. For
- * example, if "num" is in the range of
- * 999500-999999, it will print out "1000us". This
- * doesn't happen if we use floor().
- */
- if (Format == kNicenumTime)
- {
- StrLen = snprintf(Buffer.data(), Buffer.size(), "%d%s", (unsigned int)floor(Value), u);
-
- if (StrLen <= 5)
- break;
- }
- else
- {
- StrLen = snprintf(Buffer.data(), Buffer.size(), "%.*f%s", i, Value, u);
-
- if (StrLen <= 5)
- break;
- }
- }
-
- return StrLen;
- }
-}
-
-size_t
-NiceNumToBuffer(uint64_t Num, std::span<char> Buffer)
-{
- return NiceNumGeneral(Num, Buffer, kNicenum1024);
-}
-
-size_t
-NiceBytesToBuffer(uint64_t Num, std::span<char> Buffer)
-{
- return NiceNumGeneral(Num, Buffer, kNicenumBytes);
-}
-
-size_t
-NiceByteRateToBuffer(uint64_t Num, uint64_t ElapsedMs, std::span<char> Buffer)
-{
- size_t n = 0;
-
- if (ElapsedMs)
- {
- n = NiceNumGeneral(Num * 1000 / ElapsedMs, Buffer, kNicenumBytes);
- }
- else
- {
- Buffer[n++] = '0';
- Buffer[n++] = 'B';
- }
-
- Buffer[n++] = '/';
- Buffer[n++] = 's';
- Buffer[n++] = '\0';
-
- return n;
-}
-
-size_t
-NiceLatencyNsToBuffer(uint64_t Nanos, std::span<char> Buffer)
-{
- return NiceNumGeneral(Nanos, Buffer, kNicenumTime);
-}
-
-size_t
-NiceTimeSpanMsToBuffer(uint64_t Millis, std::span<char> Buffer)
-{
- if (Millis < 1000)
- {
- return snprintf(Buffer.data(), Buffer.size(), "%" PRIu64 "ms", Millis);
- }
- else if (Millis < 10000)
- {
- return snprintf(Buffer.data(), Buffer.size(), "%.2fs", Millis / 1000.0);
- }
- else if (Millis < 60000)
- {
- return snprintf(Buffer.data(), Buffer.size(), "%.1fs", Millis / 1000.0);
- }
- else if (Millis < 60 * 60000)
- {
- return snprintf(Buffer.data(), Buffer.size(), "%" PRIu64 "m%02" PRIu64 "s", Millis / 60000, (Millis / 1000) % 60);
- }
- else
- {
- return snprintf(Buffer.data(), Buffer.size(), "%" PRIu64 "h%02" PRIu64 "m", Millis / 3600000, (Millis / 60000) % 60);
- }
-}
-
-//////////////////////////////////////////////////////////////////////////
-
-template<typename C>
-StringBuilderImpl<C>::~StringBuilderImpl()
-{
- if (m_IsDynamic)
- {
- FreeBuffer(m_Base, m_End - m_Base);
- }
-}
-
-template<typename C>
-void
-StringBuilderImpl<C>::Extend(size_t extraCapacity)
-{
- if (!m_IsExtendable)
- {
- Fail("exceeded capacity");
- }
-
- const size_t oldCapacity = m_End - m_Base;
- const size_t newCapacity = NextPow2(oldCapacity + extraCapacity);
-
- C* newBase = (C*)AllocBuffer(newCapacity);
-
- size_t pos = m_CurPos - m_Base;
- memcpy(newBase, m_Base, pos * sizeof(C));
-
- if (m_IsDynamic)
- {
- FreeBuffer(m_Base, oldCapacity);
- }
-
- m_Base = newBase;
- m_CurPos = newBase + pos;
- m_End = newBase + newCapacity;
- m_IsDynamic = true;
-}
-
-template<typename C>
-void*
-StringBuilderImpl<C>::AllocBuffer(size_t byteCount)
-{
- return Memory::Alloc(byteCount * sizeof(C));
-}
-
-template<typename C>
-void
-StringBuilderImpl<C>::FreeBuffer(void* buffer, size_t byteCount)
-{
- ZEN_UNUSED(byteCount);
-
- Memory::Free(buffer);
-}
-
-template<typename C>
-[[noreturn]] void
-StringBuilderImpl<C>::Fail(const char* reason)
-{
- throw std::runtime_error(reason);
-}
-
-// Instantiate templates once
-
-template class StringBuilderImpl<char>;
-template class StringBuilderImpl<wchar_t>;
-
-//////////////////////////////////////////////////////////////////////////
-//
-// Unit tests
-//
-
-#if ZEN_WITH_TESTS
-
-TEST_CASE("niceNum")
-{
- char Buffer[16];
-
- SUBCASE("raw")
- {
- NiceNumGeneral(1, Buffer, kNicenumRaw);
- CHECK(StringEquals(Buffer, "1"));
-
- NiceNumGeneral(10, Buffer, kNicenumRaw);
- CHECK(StringEquals(Buffer, "10"));
-
- NiceNumGeneral(100, Buffer, kNicenumRaw);
- CHECK(StringEquals(Buffer, "100"));
-
- NiceNumGeneral(1000, Buffer, kNicenumRaw);
- CHECK(StringEquals(Buffer, "1000"));
-
- NiceNumGeneral(10000, Buffer, kNicenumRaw);
- CHECK(StringEquals(Buffer, "10000"));
-
- NiceNumGeneral(100000, Buffer, kNicenumRaw);
- CHECK(StringEquals(Buffer, "100000"));
- }
-
- SUBCASE("1024")
- {
- NiceNumGeneral(1, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "1"));
-
- NiceNumGeneral(10, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "10"));
-
- NiceNumGeneral(100, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "100"));
-
- NiceNumGeneral(1000, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "1000"));
-
- NiceNumGeneral(10000, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "9.77K"));
-
- NiceNumGeneral(100000, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "97.7K"));
-
- NiceNumGeneral(1000000, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "977K"));
-
- NiceNumGeneral(10000000, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "9.54M"));
-
- NiceNumGeneral(100000000, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "95.4M"));
-
- NiceNumGeneral(1000000000, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "954M"));
-
- NiceNumGeneral(10000000000, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "9.31G"));
-
- NiceNumGeneral(100000000000, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "93.1G"));
-
- NiceNumGeneral(1000000000000, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "931G"));
-
- NiceNumGeneral(10000000000000, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "9.09T"));
-
- NiceNumGeneral(100000000000000, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "90.9T"));
-
- NiceNumGeneral(1000000000000000, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "909T"));
-
- NiceNumGeneral(10000000000000000, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "8.88P"));
-
- NiceNumGeneral(100000000000000000, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "88.8P"));
-
- NiceNumGeneral(1000000000000000000, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "888P"));
-
- NiceNumGeneral(10000000000000000000ull, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "8.67E"));
-
- // pow2
-
- NiceNumGeneral(0, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "0"));
-
- NiceNumGeneral(1, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "1"));
-
- NiceNumGeneral(1024, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "1K"));
-
- NiceNumGeneral(1024 * 1024, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "1M"));
-
- NiceNumGeneral(1024 * 1024 * 1024, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "1G"));
-
- NiceNumGeneral(1024llu * 1024 * 1024 * 1024, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "1T"));
-
- NiceNumGeneral(1024llu * 1024 * 1024 * 1024 * 1024, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "1P"));
-
- NiceNumGeneral(1024llu * 1024 * 1024 * 1024 * 1024 * 1024, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "1E"));
-
- // pow2-1
-
- NiceNumGeneral(1023, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "1023"));
-
- NiceNumGeneral(2047, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "2.00K"));
-
- NiceNumGeneral(9 * 1024 - 1, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "9.00K"));
-
- NiceNumGeneral(10 * 1024 - 1, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "10.0K"));
-
- NiceNumGeneral(10 * 1024 - 5, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "10.0K"));
-
- NiceNumGeneral(10 * 1024 - 6, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "9.99K"));
-
- NiceNumGeneral(10 * 1024 - 10, Buffer, kNicenum1024);
- CHECK(StringEquals(Buffer, "9.99K"));
- }
-
- SUBCASE("time")
- {
- NiceNumGeneral(1, Buffer, kNicenumTime);
- CHECK(StringEquals(Buffer, "1ns"));
-
- NiceNumGeneral(100, Buffer, kNicenumTime);
- CHECK(StringEquals(Buffer, "100ns"));
-
- NiceNumGeneral(1000, Buffer, kNicenumTime);
- CHECK(StringEquals(Buffer, "1us"));
-
- NiceNumGeneral(10000, Buffer, kNicenumTime);
- CHECK(StringEquals(Buffer, "10us"));
-
- NiceNumGeneral(100000, Buffer, kNicenumTime);
- CHECK(StringEquals(Buffer, "100us"));
-
- NiceNumGeneral(1000000, Buffer, kNicenumTime);
- CHECK(StringEquals(Buffer, "1ms"));
-
- NiceNumGeneral(10000000, Buffer, kNicenumTime);
- CHECK(StringEquals(Buffer, "10ms"));
-
- NiceNumGeneral(100000000, Buffer, kNicenumTime);
- CHECK(StringEquals(Buffer, "100ms"));
-
- NiceNumGeneral(1000000000, Buffer, kNicenumTime);
- CHECK(StringEquals(Buffer, "1s"));
-
- NiceNumGeneral(10000000000, Buffer, kNicenumTime);
- CHECK(StringEquals(Buffer, "10s"));
-
- NiceNumGeneral(100000000000, Buffer, kNicenumTime);
- CHECK(StringEquals(Buffer, "100s"));
-
- NiceNumGeneral(1000000000000, Buffer, kNicenumTime);
- CHECK(StringEquals(Buffer, "1000s"));
-
- NiceNumGeneral(10000000000000, Buffer, kNicenumTime);
- CHECK(StringEquals(Buffer, "10000s"));
-
- NiceNumGeneral(100000000000000, Buffer, kNicenumTime);
- CHECK(StringEquals(Buffer, "100000s"));
- }
-
- SUBCASE("bytes")
- {
- NiceNumGeneral(1, Buffer, kNicenumBytes);
- CHECK(StringEquals(Buffer, "1B"));
-
- NiceNumGeneral(10, Buffer, kNicenumBytes);
- CHECK(StringEquals(Buffer, "10B"));
-
- NiceNumGeneral(100, Buffer, kNicenumBytes);
- CHECK(StringEquals(Buffer, "100B"));
-
- NiceNumGeneral(1000, Buffer, kNicenumBytes);
- CHECK(StringEquals(Buffer, "1000B"));
-
- NiceNumGeneral(10000, Buffer, kNicenumBytes);
- CHECK(StringEquals(Buffer, "9.77K"));
- }
-
- SUBCASE("byteRate")
- {
- NiceByteRateToBuffer(1, 1, Buffer);
- CHECK(StringEquals(Buffer, "1000B/s"));
-
- NiceByteRateToBuffer(1000, 1000, Buffer);
- CHECK(StringEquals(Buffer, "1000B/s"));
-
- NiceByteRateToBuffer(1024, 1, Buffer);
- CHECK(StringEquals(Buffer, "1000K/s"));
-
- NiceByteRateToBuffer(1024, 1000, Buffer);
- CHECK(StringEquals(Buffer, "1K/s"));
- }
-
- SUBCASE("timespan")
- {
- NiceTimeSpanMsToBuffer(1, Buffer);
- CHECK(StringEquals(Buffer, "1ms"));
-
- NiceTimeSpanMsToBuffer(900, Buffer);
- CHECK(StringEquals(Buffer, "900ms"));
-
- NiceTimeSpanMsToBuffer(1000, Buffer);
- CHECK(StringEquals(Buffer, "1.00s"));
-
- NiceTimeSpanMsToBuffer(1900, Buffer);
- CHECK(StringEquals(Buffer, "1.90s"));
-
- NiceTimeSpanMsToBuffer(19000, Buffer);
- CHECK(StringEquals(Buffer, "19.0s"));
-
- NiceTimeSpanMsToBuffer(60000, Buffer);
- CHECK(StringEquals(Buffer, "1m00s"));
-
- NiceTimeSpanMsToBuffer(600000, Buffer);
- CHECK(StringEquals(Buffer, "10m00s"));
-
- NiceTimeSpanMsToBuffer(3600000, Buffer);
- CHECK(StringEquals(Buffer, "1h00m"));
-
- NiceTimeSpanMsToBuffer(36000000, Buffer);
- CHECK(StringEquals(Buffer, "10h00m"));
-
- NiceTimeSpanMsToBuffer(360000000, Buffer);
- CHECK(StringEquals(Buffer, "100h00m"));
- }
-}
-
-void
-string_forcelink()
-{
-}
-
-TEST_CASE("StringBuilder")
-{
- StringBuilder<64> sb;
-
- SUBCASE("Empty init")
- {
- const char* str = sb.c_str();
-
- CHECK(StringLength(str) == 0);
- }
-
- SUBCASE("Append single character")
- {
- sb.Append('a');
-
- const char* str = sb.c_str();
- CHECK(StringLength(str) == 1);
- CHECK(str[0] == 'a');
-
- sb.Append('b');
- str = sb.c_str();
- CHECK(StringLength(str) == 2);
- CHECK(str[0] == 'a');
- CHECK(str[1] == 'b');
- }
-
- SUBCASE("Append string")
- {
- sb.Append("a");
-
- const char* str = sb.c_str();
- CHECK(StringLength(str) == 1);
- CHECK(str[0] == 'a');
-
- sb.Append("b");
- str = sb.c_str();
- CHECK(StringLength(str) == 2);
- CHECK(str[0] == 'a');
- CHECK(str[1] == 'b');
-
- sb.Append("cdefghijklmnopqrstuvwxyz");
- CHECK(sb.Size() == 26);
-
- sb.Append("abcdefghijklmnopqrstuvwxyz");
- CHECK(sb.Size() == 52);
-
- sb.Append("abcdefghijk");
- CHECK(sb.Size() == 63);
- }
-}
-
-TEST_CASE("ExtendableStringBuilder")
-{
- ExtendableStringBuilder<16> sb;
-
- SUBCASE("Empty init")
- {
- const char* str = sb.c_str();
-
- CHECK(StringLength(str) == 0);
- }
-
- SUBCASE("Short append")
- {
- sb.Append("abcd");
- CHECK(sb.IsDynamic() == false);
- }
-
- SUBCASE("Short+long append")
- {
- sb.Append("abcd");
- CHECK(sb.IsDynamic() == false);
- // This should trigger a dynamic buffer allocation since the required
- // capacity exceeds the internal fixed buffer.
- sb.Append("abcdefghijklmnopqrstuvwxyz");
- CHECK(sb.IsDynamic() == true);
- CHECK(sb.Size() == 30);
- CHECK(sb.Size() == StringLength(sb.c_str()));
- }
-}
-
-TEST_CASE("WideStringBuilder")
-{
- WideStringBuilder<64> sb;
-
- SUBCASE("Empty init")
- {
- const wchar_t* str = sb.c_str();
-
- CHECK(StringLength(str) == 0);
- }
-
- SUBCASE("Append single character")
- {
- sb.Append(L'a');
-
- const wchar_t* str = sb.c_str();
- CHECK(StringLength(str) == 1);
- CHECK(str[0] == L'a');
-
- sb.Append(L'b');
- str = sb.c_str();
- CHECK(StringLength(str) == 2);
- CHECK(str[0] == L'a');
- CHECK(str[1] == L'b');
- }
-
- SUBCASE("Append string")
- {
- sb.Append(L"a");
-
- const wchar_t* str = sb.c_str();
- CHECK(StringLength(str) == 1);
- CHECK(str[0] == L'a');
-
- sb.Append(L"b");
- str = sb.c_str();
- CHECK(StringLength(str) == 2);
- CHECK(str[0] == L'a');
- CHECK(str[1] == L'b');
-
- sb.Append(L"cdefghijklmnopqrstuvwxyz");
- CHECK(sb.Size() == 26);
-
- sb.Append(L"abcdefghijklmnopqrstuvwxyz");
- CHECK(sb.Size() == 52);
-
- sb.Append(L"abcdefghijk");
- CHECK(sb.Size() == 63);
- }
-}
-
-TEST_CASE("ExtendableWideStringBuilder")
-{
- ExtendableWideStringBuilder<16> sb;
-
- SUBCASE("Empty init")
- {
- CHECK(sb.Size() == 0);
-
- const wchar_t* str = sb.c_str();
- CHECK(StringLength(str) == 0);
- }
-
- SUBCASE("Short append")
- {
- sb.Append(L"abcd");
- CHECK(sb.IsDynamic() == false);
- }
-
- SUBCASE("Short+long append")
- {
- sb.Append(L"abcd");
- CHECK(sb.IsDynamic() == false);
- // This should trigger a dynamic buffer allocation since the required
- // capacity exceeds the internal fixed buffer.
- sb.Append(L"abcdefghijklmnopqrstuvwxyz");
- CHECK(sb.IsDynamic() == true);
- CHECK(sb.Size() == 30);
- CHECK(sb.Size() == StringLength(sb.c_str()));
- }
-}
-
-TEST_CASE("utf8")
-{
- SUBCASE("utf8towide")
- {
- // TODO: add more extensive testing here - this covers a very small space
-
- WideStringBuilder<32> wout;
- Utf8ToWide(u8"abcdefghi", wout);
- CHECK(StringEquals(L"abcdefghi", wout.c_str()));
-
- wout.Reset();
-
- Utf8ToWide(u8"abc���", wout);
- CHECK(StringEquals(L"abc���", wout.c_str()));
- }
-
- SUBCASE("widetoutf8")
- {
- // TODO: add more extensive testing here - this covers a very small space
-
- StringBuilder<32> out;
-
- WideToUtf8(L"abcdefghi", out);
- CHECK(StringEquals("abcdefghi", out.c_str()));
-
- out.Reset();
-
- WideToUtf8(L"abc���", out);
- CHECK(StringEquals(u8"abc���", out.c_str()));
- }
-}
-
-TEST_CASE("filepath")
-{
- CHECK(FilepathFindExtension("foo\\bar\\baz.txt", ".txt") != nullptr);
- CHECK(FilepathFindExtension("foo\\bar\\baz.txt", ".zap") == nullptr);
-
- CHECK(FilepathFindExtension("foo\\bar\\baz.txt") != nullptr);
- CHECK(FilepathFindExtension("foo\\bar\\baz.txt") == std::string_view(".txt"));
-
- CHECK(FilepathFindExtension(".txt") == std::string_view(".txt"));
-}
-
-TEST_CASE("string")
-{
- using namespace std::literals;
-
- SUBCASE("hash_djb2")
- {
- CHECK(HashStringAsLowerDjb2("AbcdZ"sv) == HashStringDjb2("abcdz"sv));
- CHECK(HashStringAsLowerDjb2("aBCd"sv) == HashStringDjb2("abcd"sv));
- CHECK(HashStringAsLowerDjb2("aBCd"sv) == HashStringDjb2(ToLower("aBCd"sv)));
- }
-
- SUBCASE("tolower")
- {
- CHECK_EQ(ToLower("te!st"sv), "te!st"sv);
- CHECK_EQ(ToLower("TE%St"sv), "te%st"sv);
- }
-
- SUBCASE("StrCaseCompare")
- {
- CHECK(StrCaseCompare("foo", "FoO") == 0);
- CHECK(StrCaseCompare("Bar", "bAs") < 0);
- CHECK(StrCaseCompare("bAr", "Bas") < 0);
- CHECK(StrCaseCompare("BBr", "Bar") > 0);
- CHECK(StrCaseCompare("Bbr", "BAr") > 0);
- CHECK(StrCaseCompare("foo", "FoO", 3) == 0);
- CHECK(StrCaseCompare("Bar", "bAs", 3) < 0);
- CHECK(StrCaseCompare("BBr", "Bar", 2) > 0);
- }
-
- SUBCASE("ForEachStrTok")
- {
- const auto Tokens = "here,is,my,different,tokens"sv;
- int32_t ExpectedTokenCount = 5;
- int32_t TokenCount = 0;
- StringBuilder<512> Sb;
-
- TokenCount = ForEachStrTok(Tokens, ',', [&Sb](const std::string_view& Token) {
- if (Sb.Size())
- {
- Sb << ",";
- }
- Sb << Token;
- return true;
- });
-
- CHECK(TokenCount == ExpectedTokenCount);
- CHECK(Sb.ToString() == Tokens);
-
- ExpectedTokenCount = 1;
- const auto Str = "mosdef"sv;
-
- Sb.Reset();
- TokenCount = ForEachStrTok(Str, ' ', [&Sb](const std::string_view& Token) {
- Sb << Token;
- return true;
- });
- CHECK(Sb.ToString() == Str);
- CHECK(TokenCount == ExpectedTokenCount);
-
- ExpectedTokenCount = 0;
- TokenCount = ForEachStrTok(""sv, ',', [](const std::string_view&) { return true; });
- CHECK(TokenCount == ExpectedTokenCount);
- }
-}
-
-#endif
-
-} // namespace zen