/
Mr.Stalin
/
FOnline-Engine
Обзор
Документация
Войти
/
Mr.Stalin
/
FOnline-Engine
Код
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
Source/Essentials/StringUtils.h
316 строк
13 KB
cvet
Alloc fixes (#192)
27 июл 2026, 14:30
Не верифицирован
27 июл 2026, 14:30
ba3760e
Код
Авторство
О чём код?
// __________ ___ ______ _ // / ____/ __ \____ / (_)___ ___ / ____/___ ____ _(_)___ ___ // / /_ / / / / __ \/ / / __ \/ _ \ / __/ / __ \/ __ `/ / __ \/ _ ` // / __/ / /_/ / / / / / / / / / __/ / /___/ / / / /_/ / / / / / __/ // /_/ \____/_/ /_/_/_/_/ /_/\___/ /_____/_/ /_/\__, /_/_/ /_/\___/ // /____/ // FOnline Engine // https://fonline.ru // https://github.com/cvet/fonline // // MIT License // // Copyright (c) 2006 - 2026, Anton Tsvetinskiy aka cvet <cvet@tut.by> // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // #pragma once #include "BasicCore.h" #include "Containers.h" #include "SmartPointers.h" FO_BEGIN_NAMESPACE class strvex { public: constexpr strvex() noexcept = default; constexpr explicit strvex(const char* s) noexcept : _sv {s} { } constexpr explicit strvex(string_view s) noexcept : _sv {s} { } strvex(const strvex&) = delete; strvex(strvex&&) noexcept = delete; auto operator=(const strvex&) -> strvex& = delete; auto operator=(strvex&&) noexcept -> strvex& = delete; constexpr ~strvex() = default; // ReSharper disable once CppNonExplicitConversionOperator constexpr operator string_view() const noexcept { return _sv; } constexpr auto operator==(const strvex& other) const noexcept -> bool { return _sv == other._sv; } constexpr auto operator==(string_view other) const noexcept -> bool { return _sv == other; } [[nodiscard]] auto strv() const noexcept -> string_view { return _sv; } [[nodiscard]] auto str() const noexcept -> string { return string(_sv); } [[nodiscard]] auto length() const noexcept -> size_t; [[nodiscard]] auto empty() const noexcept -> bool; [[nodiscard]] auto compare_ignore_case(string_view other) const noexcept -> bool; [[nodiscard]] auto compare_ignore_case_utf8(string_view other) const noexcept -> bool; [[nodiscard]] auto starts_with(char r) const noexcept -> bool; [[nodiscard]] auto starts_with(string_view r) const noexcept -> bool; [[nodiscard]] auto ends_with(char r) const noexcept -> bool; [[nodiscard]] auto ends_with(string_view r) const noexcept -> bool; [[nodiscard]] auto is_valid_utf8() const noexcept -> bool; [[nodiscard]] auto length_utf8() const noexcept -> size_t; [[nodiscard]] auto is_number() const noexcept -> bool; [[nodiscard]] auto is_non_finite_number() const noexcept -> bool; [[nodiscard]] auto is_explicit_bool() const noexcept -> bool; [[nodiscard]] auto to_int32() const noexcept -> int32_t; [[nodiscard]] auto to_uint32() const noexcept -> uint32_t; [[nodiscard]] auto to_int64() const noexcept -> int64_t; [[nodiscard]] auto to_float32() const noexcept -> float32_t; [[nodiscard]] auto to_float64() const noexcept -> float64_t; [[nodiscard]] auto to_bool() const noexcept -> bool; [[nodiscard]] auto split(char delimiter) const noexcept -> vector<string_view>; [[nodiscard]] auto split_to_int32(char delimiter) const noexcept -> vector<int32_t>; [[nodiscard]] auto tokenize() const noexcept -> vector<string_view>; auto substring_until(char separator) noexcept -> strvex&; auto substring_until(string_view separator) noexcept -> strvex&; auto substring_after(char separator) noexcept -> strvex&; auto substring_after(string_view separator) noexcept -> strvex&; auto trim() noexcept -> strvex&; auto trim(string_view chars) noexcept -> strvex&; auto ltrim(string_view chars) noexcept -> strvex&; auto rtrim(string_view chars) noexcept -> strvex&; auto extract_file_name() noexcept -> strvex&; auto erase_file_extension() noexcept -> strvex&; // Erase extension with dot protected: string_view _sv {}; }; static_assert(!std::is_polymorphic_v<strvex>); class strex : protected strvex { public: static constexpr size_t MAX_NUMBER_STRING_LENGTH = 80; struct safe_format_tag { } static constexpr safe_format {}; struct dynamic_format_tag { } static constexpr dynamic_format {}; constexpr strex() noexcept = default; constexpr explicit strex(const char* s) noexcept : strvex(s) { } constexpr explicit strex(string_view s) noexcept : strvex(s) { } constexpr explicit strex(string&& s) noexcept : strvex(), _s {std::move(s)} { _sv = _s; } // Formatting writes straight into the engine-allocated buffer. Do not switch these to std::format / // std::vformat: those return a std::string built with std::allocator, which both bypasses the // SafeAllocator out-of-memory contract and costs an extra copy into _s on every formatted call. template<typename... Args> explicit strex(std::format_string<Args...>&& format, Args&&... args) : strvex() { (void)std::format_to(std::back_inserter(_s), std::move(format), std::forward<Args>(args)...); _sv = _s; } template<typename... Args> explicit strex(safe_format_tag /*tag*/, std::format_string<Args...>&& format, Args&&... args) noexcept : strvex() { try { (void)std::format_to(std::back_inserter(_s), std::move(format), std::forward<Args>(args)...); } catch (const std::exception& ex) { BreakIntoDebugger(); try { // Formatting appends incrementally, so drop whatever partial output was produced _s.clear(); _s.append("Format error: "); _s.append(ex.what()); } catch (...) { // NOLINT(bugprone-empty-catch) // Bad alloc } } catch (...) { _s.clear(); } _sv = _s; } // std::make_format_args binds its arguments as non-const lvalue references, so the pack is passed by // name rather than forwarded; forwarding turns a caller's temporary into an xvalue that cannot bind template<typename... Args> explicit strex(dynamic_format_tag /*tag*/, string_view format, Args&&... args) : strvex() { (void)std::vformat_to(std::back_inserter(_s), format, std::make_format_args(args...)); _sv = _s; } strex(const strex&) = delete; strex(strex&&) noexcept = delete; auto operator=(const strex&) -> strex& = delete; auto operator=(strex&&) noexcept -> strex& = delete; constexpr ~strex() = default; // ReSharper disable once CppNonExplicitConversionOperator operator string&&() noexcept; // ReSharper disable once CppNonExplicitConversionOperator constexpr operator string_view() const noexcept { return _sv; } constexpr auto operator==(const strex& other) const noexcept -> bool { return _sv == other._sv; } constexpr auto operator==(string_view other) const noexcept -> bool { return _sv == other; } // ReSharper disable once CppInconsistentNaming [[nodiscard]] auto c_str() noexcept -> const char*; [[nodiscard]] auto str() noexcept -> string&&; [[nodiscard]] auto strv() const noexcept -> string_view { return strvex::strv(); } [[nodiscard]] auto length() const noexcept -> size_t { return strvex::length(); } [[nodiscard]] auto empty() const noexcept -> bool { return strvex::empty(); } [[nodiscard]] auto compare_ignore_case(string_view other) const noexcept -> bool { return strvex::compare_ignore_case(other); } [[nodiscard]] auto compare_ignore_case_utf8(string_view other) const noexcept -> bool { return strvex::compare_ignore_case_utf8(other); } [[nodiscard]] auto starts_with(char r) const noexcept -> bool { return strvex::starts_with(r); } [[nodiscard]] auto starts_with(string_view r) const noexcept -> bool { return strvex::starts_with(r); } [[nodiscard]] auto ends_with(char r) const noexcept -> bool { return strvex::ends_with(r); } [[nodiscard]] auto ends_with(string_view r) const noexcept -> bool { return strvex::ends_with(r); } [[nodiscard]] auto is_valid_utf8() const noexcept -> bool { return strvex::is_valid_utf8(); } [[nodiscard]] auto length_utf8() const noexcept -> size_t { return strvex::length_utf8(); } [[nodiscard]] auto is_number() const noexcept -> bool { return strvex::is_number(); } [[nodiscard]] auto is_non_finite_number() const noexcept -> bool { return strvex::is_non_finite_number(); } [[nodiscard]] auto is_explicit_bool() const noexcept -> bool { return strvex::is_explicit_bool(); } [[nodiscard]] auto to_int32() const noexcept -> int32_t { return strvex::to_int32(); } [[nodiscard]] auto to_uint32() const noexcept -> uint32_t { return strvex::to_uint32(); } [[nodiscard]] auto to_int64() const noexcept -> int64_t { return strvex::to_int64(); } [[nodiscard]] auto to_float32() const noexcept -> float32_t { return strvex::to_float32(); } [[nodiscard]] auto to_float64() const noexcept -> float64_t { return strvex::to_float64(); } [[nodiscard]] auto to_bool() const noexcept -> bool { return strvex::to_bool(); } [[nodiscard]] auto split(char delimiter) const noexcept -> vector<string>; [[nodiscard]] auto split_to_int32(char delimiter) const noexcept -> vector<int32_t> { return strvex::split_to_int32(delimiter); } [[nodiscard]] auto tokenize() const noexcept -> vector<string>; auto substring_until(char separator) noexcept -> strex&; auto substring_until(string_view separator) noexcept -> strex&; auto substring_after(char separator) noexcept -> strex&; auto substring_after(string_view separator) noexcept -> strex&; auto trim() noexcept -> strex&; auto trim(string_view chars) noexcept -> strex&; auto ltrim(string_view chars) noexcept -> strex&; auto rtrim(string_view chars) noexcept -> strex&; auto erase(char what) noexcept -> strex&; auto erase(char begin, char end) noexcept -> strex&; auto replace(char from, char to) noexcept -> strex&; auto replace(char from1, char from2, char to) noexcept -> strex&; auto replace(string_view from, string_view to) noexcept -> strex&; auto lower() noexcept -> strex&; auto lower_utf8() noexcept -> strex&; auto upper() noexcept -> strex&; auto upper_utf8() noexcept -> strex&; auto assignVolatile(const volatile char* str, size_t len) noexcept -> strex&; auto join(const_span<string_view> parts) noexcept -> strex&; auto join(const_span<string> parts) noexcept -> strex&; auto format_path() noexcept -> strex&; auto extract_dir() noexcept -> strex&; auto extract_file_name() noexcept -> strex&; auto get_file_extension() noexcept -> strex&; // Extension without dot and lowered auto erase_file_extension() noexcept -> strex&; // Erase extension with dot auto change_file_name(string_view new_name) -> strex&; auto change_file_extension(string_view new_ext) noexcept -> strex&; auto combine_path(string_view path) noexcept -> strex&; auto normalize_path_slashes() noexcept -> strex&; auto normalize_line_endings() noexcept -> strex&; #if FO_WINDOWS auto parse_wide_char(ptr<const wchar_t> str) noexcept -> strex&; [[nodiscard]] auto to_wide_char() const noexcept -> wstring; #endif private: void own_storage() noexcept; string _s {}; }; static_assert(!std::is_polymorphic_v<strex>); // ReSharper restore CppInconsistentNaming namespace utf8 { auto IsValid(uint32_t ucs) noexcept -> bool; auto DecodeStrNtLen(ptr<const char> str) noexcept -> size_t; auto Decode(ptr<const char> str, size_t& length) noexcept -> uint32_t; auto Encode(uint32_t ucs, char (&buf)[4]) noexcept -> size_t; auto Lower(uint32_t ucs) noexcept -> uint32_t; auto Upper(uint32_t ucs) noexcept -> uint32_t; } FO_END_NAMESPACE template<> struct std::formatter<FO_NAMESPACE strvex> : formatter<FO_NAMESPACE string_view> { template<typename FormatContext> // ReSharper disable once CppInconsistentNaming auto format(const FO_NAMESPACE strvex& value, FormatContext& ctx) const { return formatter<FO_NAMESPACE string_view>::format(value.strv(), ctx); } }; template<> struct std::formatter<FO_NAMESPACE strex> : formatter<FO_NAMESPACE string_view> { template<typename FormatContext> // ReSharper disable once CppInconsistentNaming auto format(const FO_NAMESPACE strex& value, FormatContext& ctx) const { return formatter<FO_NAMESPACE string_view>::format(value.strv(), ctx); } };