From 132dc4cf8f539ba1e39a9bb86c6cd389cfc3648a Mon Sep 17 00:00:00 2001 From: durswd Date: Fri, 21 Jul 2023 20:13:17 +0900 Subject: [PATCH] Separate string helper, Add test, Add methods in PathHelper --- Dev/Cpp/Effekseer/CMakeLists.txt | 1 + .../Effekseer/Backend/GraphicsDevice.h | 1 + Dev/Cpp/Effekseer/Effekseer/Effekseer.Base.h | 203 ------- .../Effekseer/Effekseer.ResourceManager.h | 1 + .../Utils/Effekseer.CustomAllocator.h | 84 --- Dev/Cpp/Effekseer/Effekseer/Utils/String.h | 523 ++++++++++++++++++ Dev/Cpp/Test/CMakeLists.txt | 1 + Dev/Cpp/Test/Runtime/RuntimeTest.cpp | 31 +- Dev/Cpp/Test/Runtime/String.cpp | 120 ++++ 9 files changed, 648 insertions(+), 317 deletions(-) create mode 100644 Dev/Cpp/Effekseer/Effekseer/Utils/String.h create mode 100644 Dev/Cpp/Test/Runtime/String.cpp diff --git a/Dev/Cpp/Effekseer/CMakeLists.txt b/Dev/Cpp/Effekseer/CMakeLists.txt index 7ef7a628b3..03f89b4633 100644 --- a/Dev/Cpp/Effekseer/CMakeLists.txt +++ b/Dev/Cpp/Effekseer/CMakeLists.txt @@ -25,6 +25,7 @@ set(effekseer_public_h Effekseer/Network/Effekseer.Server.h Effekseer/Network/Effekseer.Client.h Effekseer/Utils/Effekseer.CustomAllocator.h + Effekseer/Utils/String.h Effekseer/IO/Effekseer.EfkEfcFactory.h Effekseer/SIMD/Base.h diff --git a/Dev/Cpp/Effekseer/Effekseer/Backend/GraphicsDevice.h b/Dev/Cpp/Effekseer/Effekseer/Backend/GraphicsDevice.h index ebeabcb144..2b966f6b15 100644 --- a/Dev/Cpp/Effekseer/Effekseer/Backend/GraphicsDevice.h +++ b/Dev/Cpp/Effekseer/Effekseer/Backend/GraphicsDevice.h @@ -5,6 +5,7 @@ #include "../Effekseer.Base.Pre.h" #include "../Effekseer.Color.h" #include "../Utils/Effekseer.CustomAllocator.h" +#include "../Utils/String.h" #include #include #include diff --git a/Dev/Cpp/Effekseer/Effekseer/Effekseer.Base.h b/Dev/Cpp/Effekseer/Effekseer/Effekseer.Base.h index 8a69b1cc24..0a32acd778 100644 --- a/Dev/Cpp/Effekseer/Effekseer/Effekseer.Base.h +++ b/Dev/Cpp/Effekseer/Effekseer/Effekseer.Base.h @@ -103,209 +103,6 @@ enum class BindType : int32_t Always = 2, }; -class StringHelper -{ -public: - template - static std::vector> Split(const std::basic_string& s, T delim) - { - std::vector> elems; - - size_t start = 0; - - for (size_t i = 0; i < s.size(); i++) - { - if (s[i] == delim) - { - elems.emplace_back(s.substr(start, i - start)); - start = i + 1; - } - } - - if (start == s.size()) - { - elems.emplace_back(std::basic_string()); - } - else - { - elems.emplace_back(s.substr(start, s.size() - start)); - } - - return elems; - } - - template - static std::basic_string Replace(std::basic_string target, std::basic_string from_, std::basic_string to_) - { - auto Pos = target.find(from_); - - while (Pos != std::basic_string::npos) - { - target.replace(Pos, from_.length(), to_); - Pos = target.find(from_, Pos + to_.length()); - } - - return target; - } - - template - static std::basic_string To(const U* str) - { - std::basic_string ret; - size_t len = 0; - while (str[len] != 0) - { - len++; - } - - ret.resize(len); - - for (size_t i = 0; i < len; i++) - { - ret[i] = static_cast(str[i]); - } - - return ret; - } - - template - static std::basic_string Join(const std::vector>& elems, std::basic_string separator) - { - std::basic_string ret; - - for (size_t i = 0; i < elems.size(); i++) - { - ret += elems[i]; - - if (i != elems.size() - 1) - { - ret += separator; - } - } - - return ret; - } -}; - -class PathHelper -{ -private: - template - static std::basic_string Normalize(const std::vector>& paths) - { - std::vector> elems; - - for (size_t i = 0; i < paths.size(); i++) - { - if (paths[i] == StringHelper::To("..")) - { - if (elems.size() > 0 && elems.back() != StringHelper::To("..")) - { - elems.pop_back(); - } - else - { - elems.push_back(StringHelper::To("..")); - } - } - else - { - elems.push_back(paths[i]); - } - } - - return StringHelper::Join(elems, StringHelper::To("/")); - } - -public: - template - static std::basic_string Normalize(const std::basic_string& path) - { - if (path.size() == 0) - return path; - - auto paths = - StringHelper::Split(StringHelper::Replace(path, StringHelper::To("\\"), StringHelper::To("/")), static_cast('/')); - - return Normalize(paths); - } - - template - static std::basic_string Relative(const std::basic_string& targetPath, const std::basic_string& basePath) - { - if (basePath.size() == 0 || targetPath.size() == 0) - { - return targetPath; - } - - auto targetPaths = StringHelper::Split(StringHelper::Replace(targetPath, StringHelper::To("\\"), StringHelper::To("/")), - static_cast('/')); - auto basePaths = - StringHelper::Split(StringHelper::Replace(basePath, StringHelper::To("\\"), StringHelper::To("/")), static_cast('/')); - - if (*(basePath.end() - 1) != static_cast('/') && *(basePath.end() - 1) != static_cast('\\')) - { - basePaths.pop_back(); - } - - int32_t offset = 0; - while (targetPaths.size() > offset && basePaths.size() > offset) - { - if (targetPaths[offset] == basePaths[offset]) - { - offset++; - } - else - { - break; - } - } - - std::basic_string ret; - - for (size_t i = offset; i < basePaths.size(); i++) - { - ret += StringHelper::To("../"); - } - - for (size_t i = offset; i < targetPaths.size(); i++) - { - ret += targetPaths[i]; - - if (i != targetPaths.size() - 1) - { - ret += StringHelper::To("/"); - } - } - - return ret; - } - - template - static std::basic_string Absolute(const std::basic_string& targetPath, const std::basic_string& basePath) - { - if (targetPath == StringHelper::To("")) - return StringHelper::To(""); - - if (basePath == StringHelper::To("")) - return targetPath; - - auto targetPaths = StringHelper::Split(StringHelper::Replace(targetPath, StringHelper::To("\\"), StringHelper::To("/")), - static_cast('/')); - auto basePaths = - StringHelper::Split(StringHelper::Replace(basePath, StringHelper::To("\\"), StringHelper::To("/")), static_cast('/')); - - if (*(basePath.end() - 1) != static_cast('/') && *(basePath.end() - 1) != static_cast('\\')) - { - basePaths.pop_back(); - } - - std::copy(targetPaths.begin(), targetPaths.end(), std::back_inserter(basePaths)); - - return Normalize(basePaths); - } -}; - } // namespace Effekseer #endif // __EFFEKSEER_BASE_H__ diff --git a/Dev/Cpp/Effekseer/Effekseer/Effekseer.ResourceManager.h b/Dev/Cpp/Effekseer/Effekseer/Effekseer.ResourceManager.h index f5ecf9c55d..c8080a5442 100644 --- a/Dev/Cpp/Effekseer/Effekseer/Effekseer.ResourceManager.h +++ b/Dev/Cpp/Effekseer/Effekseer/Effekseer.ResourceManager.h @@ -6,6 +6,7 @@ #include "Effekseer.Resource.h" #include "Model//ProceduralModelParameter.h" #include "Model/ProceduralModelGenerator.h" +#include "Utils/String.h" #include namespace Effekseer diff --git a/Dev/Cpp/Effekseer/Effekseer/Utils/Effekseer.CustomAllocator.h b/Dev/Cpp/Effekseer/Effekseer/Utils/Effekseer.CustomAllocator.h index 12880c6fbd..d2c93b15ef 100644 --- a/Dev/Cpp/Effekseer/Effekseer/Utils/Effekseer.CustomAllocator.h +++ b/Dev/Cpp/Effekseer/Effekseer/Utils/Effekseer.CustomAllocator.h @@ -216,90 +216,6 @@ using CustomUnorderedMap = std::unordered_map, class KeyEq = std::equal_to> using CustomAlignedUnorderedMap = std::unordered_map>>; -//---------------------------------------------------------------------------------- -// -//---------------------------------------------------------------------------------- -template -class StringView -{ - using Traits = std::char_traits; - -public: - StringView() - : ptr_(nullptr) - , size_(0) - { - } - - StringView(const T* ptr) - : ptr_(ptr) - , size_(Traits::length(ptr)) - { - } - - StringView(const T* ptr, size_t size) - : ptr_(ptr) - , size_(size) - { - } - - template - StringView(const T ptr[N]) - : ptr_(ptr) - , size_(N) - { - } - - StringView(const CustomString& str) - : ptr_(str.data()) - , size_(str.size()) - { - } - - const T* data() const - { - return ptr_; - } - - size_t size() const - { - return size_; - } - - bool operator==(const StringView& rhs) const - { - return size() == rhs.size() && Traits::compare(data(), rhs.data(), size()) == 0; - } - - bool operator!=(const StringView& rhs) const - { - return size() != rhs.size() || Traits::compare(data(), rhs.data(), size()) != 0; - } - - struct Hash - { - size_t operator()(const StringView& key) const - { - constexpr size_t basis = (sizeof(size_t) == 8) ? 14695981039346656037ULL : 2166136261U; - constexpr size_t prime = (sizeof(size_t) == 8) ? 1099511628211ULL : 16777619U; - - const uint8_t* data = reinterpret_cast(key.data()); - size_t count = key.size() * sizeof(T); - size_t val = basis; - for (size_t i = 0; i < count; i++) - { - val ^= static_cast(data[i]); - val *= prime; - } - return val; - } - }; - -private: - const T* ptr_; - size_t size_; -}; - } // namespace Effekseer #endif // __EFFEKSEER_BASE_PRE_H__ \ No newline at end of file diff --git a/Dev/Cpp/Effekseer/Effekseer/Utils/String.h b/Dev/Cpp/Effekseer/Effekseer/Utils/String.h new file mode 100644 index 0000000000..79523b4a61 --- /dev/null +++ b/Dev/Cpp/Effekseer/Effekseer/Utils/String.h @@ -0,0 +1,523 @@ +#ifndef __EFFEKSEER_STRING_H__ +#define __EFFEKSEER_STRING_H__ + +#include +#include +#include +#include + +#include "Effekseer.CustomAllocator.h" + +namespace Effekseer +{ + +template +class StringView +{ + using Traits = std::char_traits; + +public: + StringView() + : ptr_(nullptr) + , size_(0) + { + } + + StringView(const T* ptr) + : ptr_(ptr) + , size_(Traits::length(ptr)) + { + } + + StringView(const T* ptr, size_t size) + : ptr_(ptr) + , size_(size) + { + } + + template + StringView(const T ptr[N]) + : ptr_(ptr) + , size_(N) + { + } + + StringView(const CustomString& str) + : ptr_(str.data()) + , size_(str.size()) + { + } + + const T* data() const + { + return ptr_; + } + + size_t size() const + { + return size_; + } + + bool operator==(const StringView& rhs) const + { + return size() == rhs.size() && Traits::compare(data(), rhs.data(), size()) == 0; + } + + bool operator!=(const StringView& rhs) const + { + return size() != rhs.size() || Traits::compare(data(), rhs.data(), size()) != 0; + } + + struct Hash + { + size_t operator()(const StringView& key) const + { + constexpr size_t basis = (sizeof(size_t) == 8) ? 14695981039346656037ULL : 2166136261U; + constexpr size_t prime = (sizeof(size_t) == 8) ? 1099511628211ULL : 16777619U; + + const uint8_t* data = reinterpret_cast(key.data()); + size_t count = key.size() * sizeof(T); + size_t val = basis; + for (size_t i = 0; i < count; i++) + { + val ^= static_cast(data[i]); + val *= prime; + } + return val; + } + }; + +private: + const T* ptr_; + size_t size_; +}; + +template +class FixedSizeString +{ + using Traits = std::char_traits; + +public: + FixedSizeString() + : size_(0) + { + data_[0] = 0; + } + + FixedSizeString(const T* ptr) + { + size_t original_length = Traits::length(ptr); + size_ = std::min(data_.size() - 1, original_length); + memcpy(data_.data(), ptr, size_ * sizeof(T)); + data_[size_] = 0; + } + + FixedSizeString substr(size_t pos = 0, + size_t n = std::string::npos) const + { + FixedSizeString ret; + if (n == std::string::npos) + { + ret.size_ = size_ - pos; + } + else + { + ret.size_ = n; + } + + memcpy(ret.data_.data(), data_.data() + pos, ret.size_ * sizeof(T)); + ret.data_[ret.size_] = 0; + + return ret; + } + + T& operator[](size_t i) + { + return data_[i]; + } + + T operator[](size_t i) const + { + return data_[i]; + } + + T back() const + { + return data_[size_ - 1]; + } + + const T* data() const + { + return data_.data(); + } + + size_t size() const + { + return size_; + } + + FixedSizeString& operator+=(const FixedSizeString& c) + { + const auto new_size = std::min(this->size_ + c.size_, static_cast(N)); + const auto copied_size = new_size - this->size_; + + memcpy(data_.data() + size_, c.data_.data(), copied_size * sizeof(T)); + size_ = new_size; + data_[new_size] = 0; + return *this; + } + + FixedSizeString& operator+=(const T& c) + { + if (size_ < data_.size() - 2) + { + data_[size_] = c; + data_[size_ + 1] = 0; + size_ += 1; + } + + return *this; + } + + bool operator==(const FixedSizeString& rhs) const + { + return size() == rhs.size() && Traits::compare(data(), rhs.data(), size()) == 0; + } + + bool operator!=(const FixedSizeString& rhs) const + { + return size() != rhs.size() || Traits::compare(data(), rhs.data(), size()) != 0; + } + +private: + std::array data_; + size_t size_; +}; + +class StringHelper +{ +public: + template + static std::vector> Split(const std::basic_string& s, T delim) + { + std::vector> elems; + + size_t start = 0; + + for (size_t i = 0; i < s.size(); i++) + { + if (s[i] == delim) + { + elems.emplace_back(s.substr(start, i - start)); + start = i + 1; + } + } + + if (start == s.size()) + { + elems.emplace_back(std::basic_string()); + } + else + { + elems.emplace_back(s.substr(start, s.size() - start)); + } + + return elems; + } + + template + static std::basic_string Replace(std::basic_string target, std::basic_string from_, std::basic_string to_) + { + auto Pos = target.find(from_); + + while (Pos != std::basic_string::npos) + { + target.replace(Pos, from_.length(), to_); + Pos = target.find(from_, Pos + to_.length()); + } + + return target; + } + + template + static std::basic_string To(const U* str) + { + std::basic_string ret; + size_t len = 0; + while (str[len] != 0) + { + len++; + } + + ret.resize(len); + + for (size_t i = 0; i < len; i++) + { + ret[i] = static_cast(str[i]); + } + + return ret; + } + + template + static std::basic_string Join(const std::vector>& elems, std::basic_string separator) + { + std::basic_string ret; + + for (size_t i = 0; i < elems.size(); i++) + { + ret += elems[i]; + + if (i != elems.size() - 1) + { + ret += separator; + } + } + + return ret; + } +}; + +class PathHelper +{ +private: + template + static std::basic_string Normalize(const std::vector>& paths) + { + std::vector> elems; + + for (size_t i = 0; i < paths.size(); i++) + { + if (paths[i] == StringHelper::To("..")) + { + if (elems.size() > 0 && elems.back() != StringHelper::To("..")) + { + elems.pop_back(); + } + else + { + elems.push_back(StringHelper::To("..")); + } + } + else + { + elems.push_back(paths[i]); + } + } + + return StringHelper::Join(elems, StringHelper::To("/")); + } + + template + static STRING GetDirectoryName(const STRING& path) + { + if (path.size() == 0) + { + return STRING(); + } + + int last_separator = -1; + for (size_t i = 0; i < path.size(); i++) + { + if (IsSeparator(path[i])) + { + last_separator = i; + } + } + + if (last_separator >= 0) + { + return path.substr(0, last_separator + 1); + } + return STRING(); + } + + template + static STRING GetFilenameWithoutExt(const STRING& path) + { + if (path.size() == 0) + { + return STRING(); + } + + int last_separator = -1; + for (size_t i = 0; i < path.size(); i++) + { + if (IsSeparator(path[i])) + { + last_separator = i; + } + } + last_separator++; + + int last_dot = -1; + for (size_t i = last_separator; i < path.size(); i++) + { + if (path[i] == static_cast('.')) + { + last_dot = i; + } + } + + if (last_dot >= 0) + { + return path.substr(last_separator, last_dot - last_separator); + } + return path.substr(last_separator, path.size() - last_separator); + } + + template + static STRING Combine(const STRING& path1, const STRING& path2) + { + STRING ret = path1; + if (!IsSeparator(ret.back())) + { + ret += static_cast('/'); + } + ret += path2; + + for (size_t i = 0; i < ret.size(); i++) + { + if (ret[i] == static_cast('\\')) + { + ret[i] = static_cast('/'); + } + } + + return ret; + } + +public: + template + static bool IsSeparator(T s) + { + return s == static_cast('/') || s == static_cast('\\'); + } + + template + static std::basic_string Normalize(const std::basic_string& path) + { + if (path.size() == 0) + return path; + + auto paths = + StringHelper::Split(StringHelper::Replace(path, StringHelper::To("\\"), StringHelper::To("/")), static_cast('/')); + + return Normalize(paths); + } + + template + static std::basic_string Relative(const std::basic_string& targetPath, const std::basic_string& basePath) + { + if (basePath.size() == 0 || targetPath.size() == 0) + { + return targetPath; + } + + auto targetPaths = StringHelper::Split(StringHelper::Replace(targetPath, StringHelper::To("\\"), StringHelper::To("/")), + static_cast('/')); + auto basePaths = + StringHelper::Split(StringHelper::Replace(basePath, StringHelper::To("\\"), StringHelper::To("/")), static_cast('/')); + + if (*(basePath.end() - 1) != static_cast('/') && *(basePath.end() - 1) != static_cast('\\')) + { + basePaths.pop_back(); + } + + int32_t offset = 0; + while (targetPaths.size() > offset && basePaths.size() > offset) + { + if (targetPaths[offset] == basePaths[offset]) + { + offset++; + } + else + { + break; + } + } + + std::basic_string ret; + + for (size_t i = offset; i < basePaths.size(); i++) + { + ret += StringHelper::To("../"); + } + + for (size_t i = offset; i < targetPaths.size(); i++) + { + ret += targetPaths[i]; + + if (i != targetPaths.size() - 1) + { + ret += StringHelper::To("/"); + } + } + + return ret; + } + + template + static std::basic_string Absolute(const std::basic_string& targetPath, const std::basic_string& basePath) + { + if (targetPath.size() == 0) + return std::basic_string(); + + if (basePath.size() == 0) + return targetPath; + + auto targetPaths = StringHelper::Split(StringHelper::Replace(targetPath, StringHelper::To("\\"), StringHelper::To("/")), + static_cast('/')); + auto basePaths = + StringHelper::Split(StringHelper::Replace(basePath, StringHelper::To("\\"), StringHelper::To("/")), static_cast('/')); + + if (*(basePath.end() - 1) != static_cast('/') && *(basePath.end() - 1) != static_cast('\\')) + { + basePaths.pop_back(); + } + + std::copy(targetPaths.begin(), targetPaths.end(), std::back_inserter(basePaths)); + + return Normalize(basePaths); + } + + template + static std::basic_string GetDirectoryName(const std::basic_string& path) + { + return GetDirectoryName, T>(path); + } + + template + static FixedSizeString GetDirectoryName(const FixedSizeString& path) + { + return GetDirectoryName, T>(path); + } + + template + static std::basic_string GetFilenameWithoutExt(const std::basic_string& path) + { + return GetFilenameWithoutExt, T>(path); + } + + template + static FixedSizeString GetFilenameWithoutExt(const FixedSizeString& path) + { + return GetFilenameWithoutExt, T>(path); + } + + template + static std::basic_string Combine(const std::basic_string& path1, const std::basic_string& path2) + { + return Combine, T>(path1, path2); + } + + template + static FixedSizeString Combine(const FixedSizeString& path1, const FixedSizeString& path2) + { + return Combine, T>(path1, path2); + } +}; + +} // namespace Effekseer + +#endif diff --git a/Dev/Cpp/Test/CMakeLists.txt b/Dev/Cpp/Test/CMakeLists.txt index d0195d8db3..158e31a3ff 100644 --- a/Dev/Cpp/Test/CMakeLists.txt +++ b/Dev/Cpp/Test/CMakeLists.txt @@ -13,6 +13,7 @@ set(effekseer_test_src Runtime/TextureFormats.cpp Runtime/Vertex.cpp Runtime/ResourceManager.cpp + Runtime/String.cpp Runtime/Network.cpp Runtime/Math.cpp Runtime/Misc.cpp diff --git a/Dev/Cpp/Test/Runtime/RuntimeTest.cpp b/Dev/Cpp/Test/Runtime/RuntimeTest.cpp index e191eef9d8..9f74addb3f 100644 --- a/Dev/Cpp/Test/Runtime/RuntimeTest.cpp +++ b/Dev/Cpp/Test/Runtime/RuntimeTest.cpp @@ -541,34 +541,6 @@ void CustomAllocatorTest() m[1] = 10; } -void StringAndPathHelperTest() -{ - - if (Effekseer::StringHelper::To("hoge") != std::u16string(u"hoge")) - throw ""; - - if (Effekseer::StringHelper::To("hoge") != std::u32string(U"hoge")) - throw ""; - - if (Effekseer::PathHelper::Normalize(std::u16string(u"/a/../b/c")) != std::u16string(u"/b/c")) - throw ""; - - if (Effekseer::PathHelper::Normalize(std::u16string(u"a/../b/c")) != std::u16string(u"b/c")) - throw ""; - - if (Effekseer::PathHelper::Normalize(std::u16string(u"../b/c")) != std::u16string(u"../b/c")) - throw ""; - - if (Effekseer::PathHelper::Absolute(std::u16string(u"d/c"), std::u16string(u"/a/b/c")) != std::u16string(u"/a/b/d/c")) - throw ""; - - if (Effekseer::PathHelper::Absolute(std::u16string(u"../d/c"), std::u16string(u"/a/b/c")) != std::u16string(u"/a/d/c")) - throw ""; - - if (Effekseer::PathHelper::Relative(std::u16string(u"/a/b/e"), std::u16string(u"/a/b/c")) != std::u16string(u"e")) - throw ""; -} - void DX11DefferedContextTest() { #ifdef _WIN32 @@ -923,8 +895,6 @@ void LODsTest() #if defined(__linux__) || defined(__APPLE__) || defined(WIN32) -TestRegister Runtime_StringAndPathHelperTest("Runtime.StringAndPathHelperTest", []() -> void { StringAndPathHelperTest(); }); - TestRegister Runtime_CustomAllocatorTest("Runtime.CustomAllocatorTest", []() -> void { CustomAllocatorTest(); }); TestRegister Runtime_InstanceDisposeTest("Runtime.InstanceDisposeTest", []() -> void { InstanceDisposeTest(); }); @@ -956,4 +926,5 @@ TestRegister Runtime_RenderLimitTest("Runtime.RenderLimitTest", []() -> void { R TestRegister Runtime_SRGBLinearTest("Runtime.SRGBLinearTest", []() -> void { SRGBLinearTest(); }); TestRegister Runtime_LODsTest("Runtime.LODsTest", []() -> void { LODsTest(); }); + #endif \ No newline at end of file diff --git a/Dev/Cpp/Test/Runtime/String.cpp b/Dev/Cpp/Test/Runtime/String.cpp new file mode 100644 index 0000000000..7912070645 --- /dev/null +++ b/Dev/Cpp/Test/Runtime/String.cpp @@ -0,0 +1,120 @@ +#include "../TestHelper.h" +#include +#include + +#define TEST_EQUAL_STR(x, y) \ + if ((x) != (y)) \ + { \ + std::cout << "Test failed : " << __LINE__ << std::endl; \ + abort(); \ + } + +void FixedSizeStringTest() +{ + TEST_EQUAL_STR((std::u16string(u"1234")), (Effekseer::FixedSizeString(u"12345").data())); + + TEST_EQUAL_STR((std::u16string(u"12345").substr(0)), (Effekseer::FixedSizeString(u"12345").substr(0).data())); + TEST_EQUAL_STR((std::u16string(u"12345").substr(0, 2)), (Effekseer::FixedSizeString(u"12345").substr(0, 2).data())); + TEST_EQUAL_STR((std::u16string(u"12345").substr(1)), (Effekseer::FixedSizeString(u"12345").substr(1).data())); + TEST_EQUAL_STR((std::u16string(u"12345").substr(1, 2)), (Effekseer::FixedSizeString(u"12345").substr(1, 2).data())); + + TEST_EQUAL_STR((std::u16string(u"1234").back()), (Effekseer::FixedSizeString(u"1234").back())); + + { + auto v1 = std::u16string(u"1234"); + auto v2 = Effekseer::FixedSizeString(u"1234"); + v1 += '5'; + v2 += '5'; + TEST_EQUAL_STR(v1, v2.data()); + } + + { + auto v1 = std::u16string(u"1234"); + auto v2 = Effekseer::FixedSizeString(u"1234"); + v1 += u"5678"; + v2 += u"5678"; + TEST_EQUAL_STR(v1, v2.data()); + } +} + +void StringAndPathHelperTest() +{ + if (Effekseer::StringHelper::To("hoge") != std::u16string(u"hoge")) + throw ""; + + if (Effekseer::StringHelper::To("hoge") != std::u32string(U"hoge")) + throw ""; + + if (Effekseer::PathHelper::Normalize(std::u16string(u"/a/../b/c")) != std::u16string(u"/b/c")) + throw ""; + + if (Effekseer::PathHelper::Normalize(std::u16string(u"a/../b/c")) != std::u16string(u"b/c")) + throw ""; + + if (Effekseer::PathHelper::Normalize(std::u16string(u"../b/c")) != std::u16string(u"../b/c")) + throw ""; + + if (Effekseer::PathHelper::Absolute(std::u16string(u"d/c"), std::u16string(u"/a/b/c")) != std::u16string(u"/a/b/d/c")) + throw ""; + + if (Effekseer::PathHelper::Absolute(std::u16string(u"../d/c"), std::u16string(u"/a/b/c")) != std::u16string(u"/a/d/c")) + throw ""; + + if (Effekseer::PathHelper::Relative(std::u16string(u"/a/b/e"), std::u16string(u"/a/b/c")) != std::u16string(u"e")) + throw ""; + + if (Effekseer::PathHelper::GetDirectoryName(std::u16string(u"/a/b/e")) != std::u16string(u"/a/b/")) + throw ""; + + if (Effekseer::PathHelper::GetDirectoryName(Effekseer::FixedSizeString(u"/a/b/e")) != Effekseer::FixedSizeString(u"/a/b/")) + throw ""; + + if (Effekseer::PathHelper::GetDirectoryName(std::u16string(u"/a/b/e/")) != std::u16string(u"/a/b/e/")) + throw ""; + + if (Effekseer::PathHelper::GetDirectoryName(std::u16string(u"/a")) != std::u16string(u"/")) + throw ""; + + if (Effekseer::PathHelper::GetDirectoryName(std::u16string(u"")) != std::u16string(u"")) + throw ""; + + if (Effekseer::PathHelper::GetFilenameWithoutExt(std::u16string(u"")) != std::u16string(u"")) + throw ""; + + if (Effekseer::PathHelper::GetFilenameWithoutExt(std::u16string(u"a")) != std::u16string(u"a")) + throw ""; + + if (Effekseer::PathHelper::GetFilenameWithoutExt(std::u16string(u"/a")) != std::u16string(u"a")) + throw ""; + + if (Effekseer::PathHelper::GetFilenameWithoutExt(std::u16string(u"/b/a")) != std::u16string(u"a")) + throw ""; + + if (Effekseer::PathHelper::GetFilenameWithoutExt(std::u16string(u"a.a.a")) != std::u16string(u"a.a")) + throw ""; + + if (Effekseer::PathHelper::GetFilenameWithoutExt(std::u16string(u"/b/a.a.a")) != std::u16string(u"a.a")) + throw ""; + + TEST_EQUAL_STR((std::u16string(u"a.a")), (Effekseer::PathHelper::GetFilenameWithoutExt(Effekseer::FixedSizeString(u"/b/a.a.a")).data())); + + TEST_EQUAL_STR((std::u16string(u"b/a")), (Effekseer::PathHelper::Combine(std::u16string(u"b"), std::u16string(u"a")))); + + TEST_EQUAL_STR((std::u16string(u"b/a")), (Effekseer::PathHelper::Combine(std::u16string(u"b/"), std::u16string(u"a")))); + + TEST_EQUAL_STR((std::u16string(u"/b/a")), (Effekseer::PathHelper::Combine(std::u16string(u"/b"), std::u16string(u"a")))); + + TEST_EQUAL_STR((std::u16string(u"/b/a/")), (Effekseer::PathHelper::Combine(std::u16string(u"/b/"), std::u16string(u"a/")))); + + TEST_EQUAL_STR((std::u16string(u"/b/a/")), (Effekseer::PathHelper::Combine(Effekseer::FixedSizeString(u"/b/"), Effekseer::FixedSizeString(u"a/")).data())); +} + +#if defined(__linux__) || defined(__APPLE__) || defined(WIN32) + +TestRegister Runtime_FixedSizeStringTest("Runtime.FixedSizeStringTest", []() -> void + { FixedSizeStringTest(); }); + +TestRegister Runtime_StringAndPathHelperTest("Runtime.StringAndPathHelperTest", []() -> void + { StringAndPathHelperTest(); }); + +#endif \ No newline at end of file