From 27f39d2ac08e40fc705135cba6898bc3166e0e71 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Mon, 8 Dec 2025 03:07:49 +0100 Subject: [PATCH] fmt: add more string_view versions of string functions --- Utilities/StrFmt.cpp | 82 ++++++++- Utilities/StrUtil.h | 49 +++++- Utilities/cheat_info.cpp | 4 +- Utilities/cheat_info.h | 2 +- rpcs3/Crypto/unpkg.cpp | 12 +- rpcs3/Emu/Cell/SPUCommonRecompiler.cpp | 8 +- rpcs3/Emu/Cell/SPURecompiler.h | 2 +- rpcs3/Emu/Cell/lv2/sys_usbd.cpp | 5 +- rpcs3/Emu/Io/PadHandler.h | 2 +- rpcs3/Emu/Io/RB3MidiDrums.cpp | 9 +- rpcs3/Emu/Io/camera_config.cpp | 4 +- rpcs3/Emu/Io/camera_config.h | 4 +- rpcs3/Emu/Io/midi_config_types.cpp | 4 +- rpcs3/Emu/Io/midi_config_types.h | 3 +- rpcs3/Emu/Io/pad_config.cpp | 2 +- rpcs3/Emu/Io/pad_config.h | 2 +- rpcs3/Emu/NP/np_dnshook.cpp | 3 +- rpcs3/Emu/NP/rpcn_config.cpp | 3 +- rpcs3/Emu/RSX/Program/ShaderParam.h | 8 +- rpcs3/Emu/System.cpp | 18 +- rpcs3/Emu/VFS.cpp | 10 +- rpcs3/Input/evdev_joystick_handler.cpp | 2 +- rpcs3/Input/keyboard_pad_handler.cpp | 2 +- rpcs3/Input/mm_joystick_handler.cpp | 2 +- rpcs3/Loader/disc.cpp | 8 +- rpcs3/rpcs3_version.cpp | 4 +- rpcs3/rpcs3qt/cheat_manager.cpp | 6 +- rpcs3/rpcs3qt/cheat_manager.h | 2 +- rpcs3/rpcs3qt/memory_string_searcher.cpp | 6 +- rpcs3/rpcs3qt/microphone_creator.cpp | 12 +- rpcs3/rpcs3qt/microphone_creator.h | 2 +- rpcs3/rpcs3qt/midi_creator.cpp | 4 +- rpcs3/rpcs3qt/midi_creator.h | 2 +- rpcs3/tests/test_fmt.cpp | 209 +++++++++++++++++++++++ rpcs3/util/media_utils.cpp | 4 +- rpcs3/util/sysinfo.cpp | 2 +- 36 files changed, 413 insertions(+), 90 deletions(-) diff --git a/Utilities/StrFmt.cpp b/Utilities/StrFmt.cpp index c628a90a8a..4431769f3a 100644 --- a/Utilities/StrFmt.cpp +++ b/Utilities/StrFmt.cpp @@ -83,7 +83,8 @@ std::string fmt::win_error_to_string(unsigned long error, void* module_handle) if (FormatMessageW((module_handle ? FORMAT_MESSAGE_FROM_HMODULE : FORMAT_MESSAGE_FROM_SYSTEM) | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, module_handle, error, 0, reinterpret_cast(&message_buffer), 0, nullptr)) { - message = fmt::format("%s (0x%x)", fmt::trim(wchar_to_utf8(message_buffer), " \t\n\r\f\v"), error); + const std::string utf8 = wchar_to_utf8(message_buffer); + message = fmt::format("%s (0x%x)", fmt::trim_sv(utf8, " \t\n\r\f\v"), error); } else { @@ -823,6 +824,50 @@ std::vector fmt::split(std::string_view source, std::initializer_li return result; } +std::vector fmt::split_sv(std::string_view source, std::initializer_list separators, bool is_skip_empty) +{ + std::vector result; + + for (usz index = 0; index < source.size();) + { + usz pos = -1; + usz sep_size = 0; + + for (auto& separator : separators) + { + if (usz pos0 = source.find(separator, index); pos0 < pos) + { + pos = pos0; + sep_size = separator.size(); + } + } + + if (!sep_size) + { + result.emplace_back(&source[index], source.size() - index); + return result; + } + + std::string_view piece = {&source[index], pos - index}; + + index = pos + sep_size; + + if (piece.empty() && is_skip_empty) + { + continue; + } + + result.emplace_back(std::move(piece)); + } + + if (result.empty() && !is_skip_empty) + { + result.emplace_back(); + } + + return result; +} + std::string fmt::trim(const std::string& source, std::string_view values) { const usz begin = source.find_first_not_of(values); @@ -838,6 +883,21 @@ std::string fmt::trim(const std::string& source, std::string_view values) return source.substr(begin, end + 1 - begin); } +std::string_view fmt::trim_sv(std::string_view source, std::string_view values) +{ + const usz begin = source.find_first_not_of(values); + + if (begin == source.npos) + return {}; + + const usz end = source.find_last_not_of(values); + + if (end == source.npos) + return source.substr(begin); + + return source.substr(begin, end + 1 - begin); +} + std::string fmt::trim_front(const std::string& source, std::string_view values) { const usz begin = source.find_first_not_of(values); @@ -848,12 +908,32 @@ std::string fmt::trim_front(const std::string& source, std::string_view values) return source.substr(begin); } +std::string_view fmt::trim_front_sv(std::string_view source, std::string_view values) +{ + const usz begin = source.find_first_not_of(values); + + if (begin == source.npos) + return {}; + + return source.substr(begin); +} + void fmt::trim_back(std::string& source, std::string_view values) { const usz index = source.find_last_not_of(values); source.resize(index + 1); } +std::string_view fmt::trim_back_sv(std::string_view source, std::string_view values) +{ + const usz index = source.find_last_not_of(values); + if (index == std::string_view::npos) + return {}; + + source.remove_suffix(source.size() - (index + 1)); + return source; +} + std::string fmt::to_upper(std::string_view string) { std::string result; diff --git a/Utilities/StrUtil.h b/Utilities/StrUtil.h index 285718ac21..b5df886164 100644 --- a/Utilities/StrUtil.h +++ b/Utilities/StrUtil.h @@ -139,57 +139,90 @@ namespace fmt // Splits the string into a vector of strings using the separators. The vector may contain empty strings unless is_skip_empty is true. std::vector split(std::string_view source, std::initializer_list separators, bool is_skip_empty = true); + // Splits the string_view into a vector of string_views using the separators. The vector may contain empty string_views unless is_skip_empty is true. + std::vector split_sv(std::string_view source, std::initializer_list separators, bool is_skip_empty = true); + // Removes all preceding and trailing characters specified by 'values' from 'source'. std::string trim(const std::string& source, std::string_view values = " \t"); + // Removes all preceding and trailing characters specified by 'values' from 'source' and returns the result. + std::string_view trim_sv(std::string_view source, std::string_view values = " \t"); + // Removes all preceding characters specified by 'values' from 'source'. std::string trim_front(const std::string& source, std::string_view values = " \t"); + // Removes all preceding characters specified by 'values' from 'source' and returns the result. + std::string_view trim_front_sv(std::string_view source, std::string_view values = " \t"); + // Removes all trailing characters specified by 'values' from 'source'. void trim_back(std::string& source, std::string_view values = " \t"); + // Removes all trailing characters specified by 'values' from 'source' and returns the result. + std::string_view trim_back_sv(std::string_view source, std::string_view values = " \t"); + template - std::string merge(const T& source, const std::string& separator) + std::string merge(const T& source, std::string_view separator) { if (source.empty()) { return {}; } + usz total = (source.size() - 1) * separator.size(); + for (const auto& s : source) + { + total += s.size(); + } + std::string result; + result.reserve(total); auto it = source.begin(); auto end = source.end(); + for (--end; it != end; ++it) { - result += std::string{*it} + separator; + result.append(*it); + + if (!separator.empty()) + result.append(separator); } - return result + std::string{source.back()}; + return result.append(source.back()); } template - std::string merge(std::initializer_list sources, const std::string& separator) + std::string merge(std::initializer_list sources, std::string_view separator) { if (!sources.size()) { return {}; } + usz total = (sources.size() - 1) * separator.size(); + for (const auto& s : sources) + { + if (s.empty()) continue; + total += s.size() + (s.size() - 1) * separator.size(); + } + std::string result; + result.reserve(total); + bool first = true; for (const auto& v : sources) { if (first) { - result = fmt::merge(v, separator); - first = false; + first = false; } - else + else if (!separator.empty()) { - result += separator + fmt::merge(v, separator); + result.append(separator); } + + result.append(fmt::merge(v, separator)); } return result; diff --git a/Utilities/cheat_info.cpp b/Utilities/cheat_info.cpp index a16be2767f..cc8934f15a 100644 --- a/Utilities/cheat_info.cpp +++ b/Utilities/cheat_info.cpp @@ -27,9 +27,9 @@ void fmt_class_string::format(std::string& out, u64 arg) }); } -bool cheat_info::from_str(const std::string& cheat_line) +bool cheat_info::from_str(std::string_view cheat_line) { - auto cheat_vec = fmt::split(cheat_line, {"@@@"}, false); + const auto cheat_vec = fmt::split(cheat_line, {"@@@"}, false); s64 val64 = 0; if (cheat_vec.size() != 5 || !try_to_int64(&val64, cheat_vec[2], 0, cheat_type_max - 1)) diff --git a/Utilities/cheat_info.h b/Utilities/cheat_info.h index 3ceb32716b..a109d86e56 100644 --- a/Utilities/cheat_info.h +++ b/Utilities/cheat_info.h @@ -28,6 +28,6 @@ struct cheat_info u32 offset{}; std::string red_script{}; - bool from_str(const std::string& cheat_line); + bool from_str(std::string_view cheat_line); std::string to_str() const; }; diff --git a/rpcs3/Crypto/unpkg.cpp b/rpcs3/Crypto/unpkg.cpp index bc7481fcd6..de23f5f1ba 100644 --- a/rpcs3/Crypto/unpkg.cpp +++ b/rpcs3/Crypto/unpkg.cpp @@ -598,15 +598,15 @@ bool package_reader::read_param_sfo() const bool is_psp = (entry.type & PKG_FILE_ENTRY_PSP) != 0u; - std::string name(entry.name_size + BUF_PADDING, '\0'); + std::string name_buf(entry.name_size + BUF_PADDING, '\0'); - if (usz read_size = decrypt(entry.name_offset, entry.name_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), name.data()); read_size < entry.name_size) + if (usz read_size = decrypt(entry.name_offset, entry.name_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), name_buf.data()); read_size < entry.name_size) { pkg_log.error("PKG name could not be read (size=0x%x, offset=0x%x)", entry.name_size, entry.name_offset); continue; } - fmt::trim_back(name, "\0"sv); + std::string_view name = fmt::trim_back_sv(name_buf, "\0"sv); // We're looking for the PARAM.SFO file, if there is any if (usz ndelim = name.find_first_not_of('/'); ndelim == umax || name.substr(ndelim) != "PARAM.SFO") @@ -854,18 +854,18 @@ bool package_reader::fill_data(std::map& all_instal break; } - std::string name(entry.name_size + BUF_PADDING, '\0'); + std::string name_buf(entry.name_size + BUF_PADDING, '\0'); const bool is_psp = (entry.type & PKG_FILE_ENTRY_PSP) != 0u; - if (const usz read_size = decrypt(entry.name_offset, entry.name_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), name.data()); read_size < entry.name_size) + if (const usz read_size = decrypt(entry.name_offset, entry.name_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), name_buf.data()); read_size < entry.name_size) { num_failures++; pkg_log.error("PKG name could not be read (size=0x%x, offset=0x%x)", entry.name_size, entry.name_offset); break; } - fmt::trim_back(name, "\0"sv); + std::string_view name = fmt::trim_back_sv(name_buf, "\0"sv); std::string path = m_install_path + vfs::escape(name); diff --git a/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp b/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp index d23903997f..2fbb08a97d 100644 --- a/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp @@ -7320,7 +7320,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s } // spu_log.success("PUTLLC0 Pattern Detected! (put_pc=0x%x, %s) (putllc0=%d, putllc16+0=%d, all=%d)", pattern.put_pc, func_hash, ++stats.nowrite, ++stats.single, +stats.all); - // add_pattern(false, inst_attr::putllc0, pattern.put_pc - lsa, value.data); + // add_pattern(inst_attr::putllc0, pattern.put_pc - lsa, value.data); continue; } @@ -7411,7 +7411,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s if (allow_pattern) { - add_pattern(false, inst_attr::putllc16, pattern.put_pc - result.entry_point, value.data); + add_pattern(inst_attr::putllc16, pattern.put_pc - result.entry_point, value.data); } spu_log.success("PUTLLC16 Pattern Detected! (mem_count=%d, put_pc=0x%x, pc_rel=%d, offset=0x%x, const=%u, two_regs=%d, reg=%u, runtime=%d, 0x%x-%s, pattern-hash=%s) (putllc0=%d, putllc16+0=%d, all=%d)" @@ -7433,7 +7433,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s if (inst_attr attr = m_inst_attrs[(read_pc - entry_point) / 4]; attr == inst_attr::none) { - add_pattern(false, inst_attr::rchcnt_loop, read_pc - result.entry_point, 0); + add_pattern(inst_attr::rchcnt_loop, read_pc - result.entry_point, 0); spu_log.error("Channel Loop Pattern Detected! Report to developers! (read_pc=0x%x, branch_pc=0x%x, branch_target=0x%x, 0x%x-%s)", read_pc, pattern.branch_pc, pattern.branch_target, entry_point, func_hash); } @@ -8519,7 +8519,7 @@ std::array& block_reg_info::evaluate_start_state(const s return walkby_state; } -void spu_recompiler_base::add_pattern(bool fill_all, inst_attr attr, u32 start, u64 info) +void spu_recompiler_base::add_pattern(inst_attr attr, u32 start, u64 info) { m_patterns[start] = pattern_info{info}; m_inst_attrs[start / 4] = attr; diff --git a/rpcs3/Emu/Cell/SPURecompiler.h b/rpcs3/Emu/Cell/SPURecompiler.h index 6bddb5a035..57d842e69d 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.h +++ b/rpcs3/Emu/Cell/SPURecompiler.h @@ -402,7 +402,7 @@ protected: std::unordered_map m_patterns; - void add_pattern(bool fill_all, inst_attr attr, u32 start, u64 info); + void add_pattern(inst_attr attr, u32 start, u64 info); private: // For private use diff --git a/rpcs3/Emu/Cell/lv2/sys_usbd.cpp b/rpcs3/Emu/Cell/lv2/sys_usbd.cpp index fd5257b03a..78183293e7 100644 --- a/rpcs3/Emu/Cell/lv2/sys_usbd.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_usbd.cpp @@ -321,7 +321,7 @@ static void LIBUSB_CALL log_cb(libusb_context* /*ctx*/, enum libusb_log_level le if (!str) return; - const std::string msg = fmt::trim(str, " \t\n"); + const std::string_view msg = fmt::trim_sv(str, " \t\n"); switch (level) { @@ -555,7 +555,8 @@ usb_handler_thread::usb_handler_thread() usb_devices.push_back(std::make_shared(usb_info, get_new_location())); } - const std::vector devices_list = fmt::split(g_cfg.io.midi_devices.to_string(), { "@@@" }); + const std::string midi_devices = g_cfg.io.midi_devices.to_string(); + const std::vector devices_list = fmt::split_sv(midi_devices, { "@@@" }); for (usz index = 0; index < std::min(max_midi_devices, devices_list.size()); index++) { const midi_device device = midi_device::from_string(::at32(devices_list, index)); diff --git a/rpcs3/Emu/Io/PadHandler.h b/rpcs3/Emu/Io/PadHandler.h index e9fc166d93..a27e0bcc50 100644 --- a/rpcs3/Emu/Io/PadHandler.h +++ b/rpcs3/Emu/Io/PadHandler.h @@ -205,7 +205,7 @@ protected: std::set key_codes; const std::string& def = cfg_string.def; - const std::vector names = cfg_pad::get_buttons(cfg_string); + const std::vector names = cfg_pad::get_buttons(cfg_string.to_string()); T def_code = umax; for (const std::string& nam : names) diff --git a/rpcs3/Emu/Io/RB3MidiDrums.cpp b/rpcs3/Emu/Io/RB3MidiDrums.cpp index 67ff121d77..61b172bbdd 100644 --- a/rpcs3/Emu/Io/RB3MidiDrums.cpp +++ b/rpcs3/Emu/Io/RB3MidiDrums.cpp @@ -177,7 +177,7 @@ Note str_to_note(const std::string_view name) std::optional> parse_midi_override(const std::string_view config) { - auto split = fmt::split(config, {"="}); + const auto split = fmt::split_sv(config, {"="}); if (split.size() != 2) { return {}; @@ -236,8 +236,9 @@ std::unordered_map create_id_to_note_mapping() }; // Apply configured overrides. - const std::vector segments = fmt::split(g_cfg_rb3drums.midi_overrides.to_string(), {","}); - for (const std::string& segment : segments) + const std::string midi_overrides = g_cfg_rb3drums.midi_overrides.to_string(); + const std::vector segments = fmt::split_sv(midi_overrides, {","}); + for (const std::string_view& segment : segments) { if (const auto midi_override = parse_midi_override(segment)) { @@ -259,7 +260,7 @@ std::vector parse_combo(const std::string_view name, const std::string_view return {}; } std::vector notes; - const auto& note_names = fmt::split(csv, {","}); + const auto note_names = fmt::split_sv(csv, {","}); for (const auto& note_name : note_names) { const auto note = str_to_note(note_name); diff --git a/rpcs3/Emu/Io/camera_config.cpp b/rpcs3/Emu/Io/camera_config.cpp index d7071b05c3..f498de72b1 100644 --- a/rpcs3/Emu/Io/camera_config.cpp +++ b/rpcs3/Emu/Io/camera_config.cpp @@ -36,7 +36,7 @@ void cfg_camera::save() const } } -cfg_camera::camera_setting cfg_camera::get_camera_setting(const std::string& camera, bool& success) +cfg_camera::camera_setting cfg_camera::get_camera_setting(std::string_view camera, bool& success) { camera_setting setting; const std::string value = cameras.get_value(camera); @@ -64,7 +64,7 @@ std::string cfg_camera::camera_setting::to_string() const return fmt::format("%d,%d,%f,%f,%d", width, height, min_fps, max_fps, format); } -void cfg_camera::camera_setting::from_string(const std::string& text) +void cfg_camera::camera_setting::from_string(std::string_view text) { if (text.empty()) { diff --git a/rpcs3/Emu/Io/camera_config.h b/rpcs3/Emu/Io/camera_config.h index a918dea458..1c576e32c1 100644 --- a/rpcs3/Emu/Io/camera_config.h +++ b/rpcs3/Emu/Io/camera_config.h @@ -19,9 +19,9 @@ struct cfg_camera final : cfg::node static constexpr u32 member_count = 5; std::string to_string() const; - void from_string(const std::string& text); + void from_string(std::string_view text); }; - camera_setting get_camera_setting(const std::string& camera, bool& success); + camera_setting get_camera_setting(std::string_view camera, bool& success); void set_camera_setting(const std::string& camera, const camera_setting& setting); const std::string path; diff --git a/rpcs3/Emu/Io/midi_config_types.cpp b/rpcs3/Emu/Io/midi_config_types.cpp index abe976ee93..0105da3d51 100644 --- a/rpcs3/Emu/Io/midi_config_types.cpp +++ b/rpcs3/Emu/Io/midi_config_types.cpp @@ -27,11 +27,11 @@ void fmt_class_string::format(std::string& out, u64 arg) fmt::append(out, "%sßßß%s", obj.type, obj.name); } -midi_device midi_device::from_string(const std::string& str) +midi_device midi_device::from_string(std::string_view str) { midi_device res{}; - if (const std::vector parts = fmt::split(str, {"ßßß"}); !parts.empty()) + if (const std::vector parts = fmt::split_sv(str, {"ßßß"}); !parts.empty()) { u64 result; diff --git a/rpcs3/Emu/Io/midi_config_types.h b/rpcs3/Emu/Io/midi_config_types.h index 9d2f40adf1..d21cbfbfce 100644 --- a/rpcs3/Emu/Io/midi_config_types.h +++ b/rpcs3/Emu/Io/midi_config_types.h @@ -1,6 +1,7 @@ #pragma once #include +#include static constexpr usz max_midi_devices = 3; @@ -17,5 +18,5 @@ struct midi_device midi_device_type type{}; std::string name; - static midi_device from_string(const std::string& str); + static midi_device from_string(std::string_view str); }; diff --git a/rpcs3/Emu/Io/pad_config.cpp b/rpcs3/Emu/Io/pad_config.cpp index 614d972716..937626076e 100644 --- a/rpcs3/Emu/Io/pad_config.cpp +++ b/rpcs3/Emu/Io/pad_config.cpp @@ -5,7 +5,7 @@ extern std::string g_input_config_override; -std::vector cfg_pad::get_buttons(const std::string& str) +std::vector cfg_pad::get_buttons(std::string_view str) { std::vector vec = fmt::split(str, {","}); diff --git a/rpcs3/Emu/Io/pad_config.h b/rpcs3/Emu/Io/pad_config.h index fa695c4941..7dd4bd6323 100644 --- a/rpcs3/Emu/Io/pad_config.h +++ b/rpcs3/Emu/Io/pad_config.h @@ -25,7 +25,7 @@ struct cfg_pad final : cfg::node cfg_pad() {}; cfg_pad(node* owner, const std::string& name) : cfg::node(owner, name) {} - static std::vector get_buttons(const std::string& str); + static std::vector get_buttons(std::string_view str); static std::string get_buttons(std::vector vec); u8 get_motor_speed(VibrateMotor& motor, f32 multiplier) const; diff --git a/rpcs3/Emu/NP/np_dnshook.cpp b/rpcs3/Emu/NP/np_dnshook.cpp index a035947e1f..515cba5fc6 100644 --- a/rpcs3/Emu/NP/np_dnshook.cpp +++ b/rpcs3/Emu/NP/np_dnshook.cpp @@ -28,7 +28,8 @@ namespace np dnshook::dnshook() { // Init switch map for dns - auto swaps = fmt::split(g_cfg.net.swap_list.to_string(), {"&&"}); + const std::string swap_list = g_cfg.net.swap_list.to_string(); + const auto swaps = fmt::split_sv(swap_list, {"&&"}); for (usz i = 0; i < swaps.size(); i++) { auto host_and_ip = fmt::split(swaps[i], {"="}); diff --git a/rpcs3/Emu/NP/rpcn_config.cpp b/rpcs3/Emu/NP/rpcn_config.cpp index 204091d295..0b5cabe768 100644 --- a/rpcs3/Emu/NP/rpcn_config.cpp +++ b/rpcs3/Emu/NP/rpcn_config.cpp @@ -79,7 +79,8 @@ std::string cfg_rpcn::get_host() const std::vector> cfg_rpcn::get_hosts() { std::vector> vec_hosts; - auto hosts_list = fmt::split(hosts.to_string(), {"|||"}); + const std::string host_str = hosts.to_string(); + const auto hosts_list = fmt::split_sv(host_str, {"|||"}); for (const auto& cur_host : hosts_list) { diff --git a/rpcs3/Emu/RSX/Program/ShaderParam.h b/rpcs3/Emu/RSX/Program/ShaderParam.h index 266ab51cbd..6131f36ae9 100644 --- a/rpcs3/Emu/RSX/Program/ShaderParam.h +++ b/rpcs3/Emu/RSX/Program/ShaderParam.h @@ -244,10 +244,10 @@ public: std::vector swizzles; ShaderVariable() = default; - ShaderVariable(const std::string& var) + ShaderVariable(std::string_view var) { // Separate 'double destination' variables 'X=Y=SRC' - std::string simple_var; + std::string_view simple_var; const auto eq_pos = var.find('='); if (eq_pos != umax) @@ -267,11 +267,11 @@ public: simple_var = simple_var.substr(brace_pos); } - auto var_blocks = fmt::split(simple_var, { "." }); + const auto var_blocks = fmt::split_sv(simple_var, { "." }); ensure((!var_blocks.empty())); - name = prefix + var_blocks[0]; + name = prefix + std::string(var_blocks[0]); if (var_blocks.size() == 1) { diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index dd6c3506b2..651c220b60 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -1866,8 +1866,8 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch, // PS1 Classic located in dev_hdd0/game sys_log.notice("PS1 Game: %s, %s", m_title_id, m_title); - const std::string tail = m_path.substr(hdd0_game.size()); - const std::string dirname = fmt::trim_front(tail, fs::delim).substr(0, tail.find_first_of(fs::delim)); + const std::string_view tail = std::string_view(m_path).substr(hdd0_game.size()); + const std::string dirname = std::string(fmt::trim_front_sv(tail, fs::delim).substr(0, tail.find_first_of(fs::delim))); const std::string game_path = "/dev_hdd0/game/" + dirname; argv.resize(9); @@ -1894,8 +1894,8 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch, // PSP Remaster located in dev_hdd0/game sys_log.notice("PSP Remaster Game: %s, %s", m_title_id, m_title); - const std::string tail = m_path.substr(hdd0_game.size()); - const std::string dirname = fmt::trim_front(tail, fs::delim).substr(0, tail.find_first_of(fs::delim)); + const std::string_view tail = std::string_view(m_path).substr(hdd0_game.size()); + const std::string dirname = std::string(fmt::trim_front_sv(tail, fs::delim).substr(0, tail.find_first_of(fs::delim))); const std::string game_path = "/dev_hdd0/game/" + dirname; argv.resize(2); @@ -1913,7 +1913,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch, // Add HG games not in HDD0 to games.yml [[maybe_unused]] const games_config::result res = m_games_config.add_external_hdd_game(m_title_id, game_dir); - const std::string dir = fmt::trim(game_dir.substr(fs::get_parent_dir_view(game_dir).size() + 1), fs::delim); + const std::string dir = std::string(fmt::trim_sv(std::string_view(game_dir).substr(fs::get_parent_dir_view(game_dir).size() + 1), fs::delim)); vfs::mount("/dev_hdd0/game/" + dir, game_dir + '/'); } } @@ -2265,10 +2265,10 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch, auto unescape = [](std::string_view path) { // Unescape from host FS - std::vector escaped = fmt::split(path, {std::string_view{&fs::delim[0], 1}, std::string_view{&fs::delim[1], 1}}); + const std::vector escaped = fmt::split_sv(path, {std::string_view{&fs::delim[0], 1}, std::string_view{&fs::delim[1], 1}}); std::vector result; - for (auto& sv : escaped) - result.emplace_back(vfs::unescape(sv)); + for (const auto& sv : escaped) + result.push_back(vfs::unescape(sv)); return fmt::merge(result, "/"); }; @@ -2315,7 +2315,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch, game_dir = game_dir.substr(0, game_dir.size() - 4); } - const std::string dir = fmt::trim(game_dir.substr(fs::get_parent_dir_view(game_dir).size() + 1), fs::delim); + const std::string dir = std::string(fmt::trim_sv(std::string_view(game_dir).substr(fs::get_parent_dir_view(game_dir).size() + 1), fs::delim)); m_dir = "/dev_hdd0/game/" + dir + '/'; argv[0] = m_dir + unescape(resolved_path.substr(GetCallbacks().resolve_path(game_dir).size())); diff --git a/rpcs3/Emu/VFS.cpp b/rpcs3/Emu/VFS.cpp index 8484c57246..f5963ca7c1 100644 --- a/rpcs3/Emu/VFS.cpp +++ b/rpcs3/Emu/VFS.cpp @@ -137,7 +137,7 @@ bool vfs::unmount(std::string_view vpath) return false; } - const std::vector entry_list = fmt::split(vpath, {"/"}); + const std::vector entry_list = fmt::split_sv(vpath, {"/"}); if (entry_list.empty()) { @@ -166,7 +166,7 @@ bool vfs::unmount(std::string_view vpath) } // Get the current name based on the depth - const std::string& name = ::at32(entry_list, depth); + const std::string_view name = ::at32(entry_list, depth); // Go through all children of this node for (auto it = dir.dirs.begin(); it != dir.dirs.end();) @@ -456,10 +456,10 @@ std::string vfs::retrieve(std::string_view path, const vfs_directory* node, std: auto unescape_path = [](std::string_view path) { // Unescape from host FS - std::vector escaped = fmt::split(path, {std::string_view{&fs::delim[0], 1}, std::string_view{&fs::delim[1], 1}}); + const std::vector escaped = fmt::split_sv(path, {std::string_view{&fs::delim[0], 1}, std::string_view{&fs::delim[1], 1}}); std::vector result; - for (auto& sv : escaped) - result.emplace_back(vfs::unescape(sv)); + for (const auto& sv : escaped) + result.push_back(vfs::unescape(sv)); return fmt::merge(result, "/"); }; diff --git a/rpcs3/Input/evdev_joystick_handler.cpp b/rpcs3/Input/evdev_joystick_handler.cpp index 6ddb0ff989..03f2016c27 100644 --- a/rpcs3/Input/evdev_joystick_handler.cpp +++ b/rpcs3/Input/evdev_joystick_handler.cpp @@ -1346,7 +1346,7 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr pad) const auto find_buttons = [&](const cfg::string& name) -> std::set { - const std::vector names = cfg_pad::get_buttons(name); + const std::vector names = cfg_pad::get_buttons(name.to_string()); // In evdev we store indices to an EvdevButton vector in our pad objects instead of the usual key codes. std::set indices; diff --git a/rpcs3/Input/keyboard_pad_handler.cpp b/rpcs3/Input/keyboard_pad_handler.cpp index c9da8dcb29..e70cf8d45b 100644 --- a/rpcs3/Input/keyboard_pad_handler.cpp +++ b/rpcs3/Input/keyboard_pad_handler.cpp @@ -835,7 +835,7 @@ std::string keyboard_pad_handler::GetKeyName(const u32& keyCode) std::set keyboard_pad_handler::GetKeyCodes(const cfg::string& cfg_string) { std::set key_codes; - for (const std::string& key_name : cfg_pad::get_buttons(cfg_string)) + for (const std::string& key_name : cfg_pad::get_buttons(cfg_string.to_string())) { if (u32 code = GetKeyCode(QString::fromStdString(key_name)); code != Qt::NoButton) { diff --git a/rpcs3/Input/mm_joystick_handler.cpp b/rpcs3/Input/mm_joystick_handler.cpp index cbe9b60223..fed1f428df 100644 --- a/rpcs3/Input/mm_joystick_handler.cpp +++ b/rpcs3/Input/mm_joystick_handler.cpp @@ -148,7 +148,7 @@ std::vector mm_joystick_handler::list_devices() template std::set mm_joystick_handler::find_keys(const cfg::string& cfg_string) const { - return find_keys(cfg_pad::get_buttons(cfg_string)); + return find_keys(cfg_pad::get_buttons(cfg_string.to_string())); } template diff --git a/rpcs3/Loader/disc.cpp b/rpcs3/Loader/disc.cpp index b2ea4dc855..9ae33e42e0 100644 --- a/rpcs3/Loader/disc.cpp +++ b/rpcs3/Loader/disc.cpp @@ -96,7 +96,7 @@ namespace disc for (usz i = 0; i < lines.size(); i++) { - const std::string& line = lines[i]; + const std::string_view line = lines[i]; const usz pos = line.find('='); if (pos == umax) @@ -104,12 +104,12 @@ namespace disc continue; } - const std::string key = fmt::trim(line.substr(0, pos)); - std::string value; + const std::string_view key = fmt::trim_sv(line.substr(0, pos)); + std::string_view value; if (pos != (line.size() - 1)) { - value = fmt::trim(line.substr(pos + 1)); + value = fmt::trim_sv(line.substr(pos + 1)); } if (value.empty() && i != (lines.size() - 1) && line.size() != 1) diff --git a/rpcs3/rpcs3_version.cpp b/rpcs3/rpcs3_version.cpp index 8d789d2ba9..ab18b56caf 100644 --- a/rpcs3/rpcs3_version.cpp +++ b/rpcs3/rpcs3_version.cpp @@ -17,11 +17,11 @@ namespace rpcs3 std::pair get_commit_and_hash() { - const auto commit_and_hash = fmt::split(RPCS3_GIT_VERSION, {"-"}); + auto commit_and_hash = fmt::split(RPCS3_GIT_VERSION, {"-"}); if (commit_and_hash.size() != 2) return std::make_pair("0", "00000000"); - return std::make_pair(commit_and_hash[0], commit_and_hash[1]); + return std::make_pair(std::move(commit_and_hash[0]), std::move(commit_and_hash[1])); } // TODO: Make this accessible from cmake and keep in sync with MACOSX_BUNDLE_BUNDLE_VERSION. diff --git a/rpcs3/rpcs3qt/cheat_manager.cpp b/rpcs3/rpcs3qt/cheat_manager.cpp index e6b760a0a2..a24a2cd5fc 100644 --- a/rpcs3/rpcs3qt/cheat_manager.cpp +++ b/rpcs3/rpcs3qt/cheat_manager.cpp @@ -129,11 +129,11 @@ void cheat_engine::save() const cheat_file.write(out.c_str(), out.size()); } -void cheat_engine::import_cheats_from_str(const std::string& str_cheats) +void cheat_engine::import_cheats_from_str(std::string_view str_cheats) { - auto cheats_vec = fmt::split(str_cheats, {"^^^"}); + const auto cheats_vec = fmt::split_sv(str_cheats, {"^^^"}); - for (auto& cheat_line : cheats_vec) + for (const auto& cheat_line : cheats_vec) { cheat_info new_cheat; if (new_cheat.from_str(cheat_line)) diff --git a/rpcs3/rpcs3qt/cheat_manager.h b/rpcs3/rpcs3qt/cheat_manager.h index 458c7400b9..b915faa8a2 100644 --- a/rpcs3/rpcs3qt/cheat_manager.h +++ b/rpcs3/rpcs3qt/cheat_manager.h @@ -25,7 +25,7 @@ public: cheat_info* get(const std::string& game, const u32 offset); bool erase(const std::string& game, const u32 offset); - void import_cheats_from_str(const std::string& str_cheats); + void import_cheats_from_str(std::string_view str_cheats); std::string export_cheats_to_str() const; void save() const; diff --git a/rpcs3/rpcs3qt/memory_string_searcher.cpp b/rpcs3/rpcs3qt/memory_string_searcher.cpp index c55cb8144d..de8ee1814f 100644 --- a/rpcs3/rpcs3qt/memory_string_searcher.cpp +++ b/rpcs3/rpcs3qt/memory_string_searcher.cpp @@ -115,11 +115,7 @@ u64 memory_viewer_panel::OnSearch(std::string wstr, u32 mode) } // Concat strings - wstr.clear(); - for (const std::string& part : parts) - { - wstr += part; - } + wstr = fmt::merge(parts, {}); if (const usz pos = wstr.find_first_not_of(hex_chars); pos != umax) { diff --git a/rpcs3/rpcs3qt/microphone_creator.cpp b/rpcs3/rpcs3qt/microphone_creator.cpp index 2821fd82e4..c44449c544 100644 --- a/rpcs3/rpcs3qt/microphone_creator.cpp +++ b/rpcs3/rpcs3qt/microphone_creator.cpp @@ -61,23 +61,23 @@ std::array microphone_creator::get_selection_list() const std::string microphone_creator::set_device(u32 num, const QString& text) { - ensure(num < m_sel_list.size()); + std::string& device = ::at32(m_sel_list, num); if (text == get_none()) - m_sel_list[num].clear(); + device.clear(); else - m_sel_list[num] = text.toStdString(); + device = text.toStdString(); return m_sel_list[0] + "@@@" + m_sel_list[1] + "@@@" + m_sel_list[2] + "@@@" + m_sel_list[3] + "@@@"; } -void microphone_creator::parse_devices(const std::string& list) +void microphone_creator::parse_devices(std::string_view list) { m_sel_list = {}; - const std::vector devices_list = fmt::split(list, { "@@@" }); + std::vector devices_list = fmt::split(list, { "@@@" }); for (usz index = 0; index < std::min(m_sel_list.size(), devices_list.size()); index++) { - m_sel_list[index] = devices_list[index]; + m_sel_list[index] = std::move(devices_list[index]); } } diff --git a/rpcs3/rpcs3qt/microphone_creator.h b/rpcs3/rpcs3qt/microphone_creator.h index 95a3827c93..37b2672083 100644 --- a/rpcs3/rpcs3qt/microphone_creator.h +++ b/rpcs3/rpcs3qt/microphone_creator.h @@ -17,7 +17,7 @@ public: microphone_creator(); QString get_none(); std::string set_device(u32 num, const QString& text); - void parse_devices(const std::string& list); + void parse_devices(std::string_view list); void refresh_list(); QStringList get_microphone_list() const; std::array get_selection_list() const; diff --git a/rpcs3/rpcs3qt/midi_creator.cpp b/rpcs3/rpcs3qt/midi_creator.cpp index 57476af3d6..d4ad70d5e9 100644 --- a/rpcs3/rpcs3qt/midi_creator.cpp +++ b/rpcs3/rpcs3qt/midi_creator.cpp @@ -104,11 +104,11 @@ std::string midi_creator::set_device(u32 num, const midi_device& device) return result; } -void midi_creator::parse_devices(const std::string& list) +void midi_creator::parse_devices(std::string_view list) { m_sel_list = {}; - const std::vector devices_list = fmt::split(list, { "@@@" }); + const std::vector devices_list = fmt::split_sv(list, { "@@@" }); for (usz index = 0; index < std::min(m_sel_list.size(), devices_list.size()); index++) { m_sel_list[index] = midi_device::from_string(devices_list[index]); diff --git a/rpcs3/rpcs3qt/midi_creator.h b/rpcs3/rpcs3qt/midi_creator.h index cfcbae3ebc..5a8cb05fd6 100644 --- a/rpcs3/rpcs3qt/midi_creator.h +++ b/rpcs3/rpcs3qt/midi_creator.h @@ -14,7 +14,7 @@ public: midi_creator(); QString get_none(); std::string set_device(u32 num, const midi_device& device); - void parse_devices(const std::string& list); + void parse_devices(std::string_view list); void refresh_list(); QStringList get_midi_list() const; std::array get_selection_list() const; diff --git a/rpcs3/tests/test_fmt.cpp b/rpcs3/tests/test_fmt.cpp index e44b4adab0..95c31d17c6 100644 --- a/rpcs3/tests/test_fmt.cpp +++ b/rpcs3/tests/test_fmt.cpp @@ -25,6 +25,26 @@ namespace fmt EXPECT_EQ("b"s, fmt::trim(" aba ", " a")); } + TEST(StrUtil, TrimSv) + { + EXPECT_EQ(""sv, fmt::trim_sv("", "")); + EXPECT_EQ(""sv, fmt::trim_sv("", " ")); + EXPECT_EQ(""sv, fmt::trim_sv("", "a ")); + EXPECT_EQ(" "sv, fmt::trim_sv(" ", "")); + EXPECT_EQ(""sv, fmt::trim_sv(" ", " ")); + EXPECT_EQ("a"sv, fmt::trim_sv("a ", " ")); + EXPECT_EQ("a"sv, fmt::trim_sv(" a", " ")); + EXPECT_EQ("a a"sv, fmt::trim_sv("a a", " ")); + EXPECT_EQ("a a"sv, fmt::trim_sv("a a ", " ")); + EXPECT_EQ("a a"sv, fmt::trim_sv(" a a", " ")); + EXPECT_EQ("a a"sv, fmt::trim_sv(" a a ", " ")); + EXPECT_EQ("a a"sv, fmt::trim_sv("a a ", " ")); + EXPECT_EQ("a a"sv, fmt::trim_sv(" a a ", " ")); + EXPECT_EQ("a a"sv, fmt::trim_sv(" a a", " ")); + EXPECT_EQ(""sv, fmt::trim_sv(" a a ", " a")); + EXPECT_EQ("b"sv, fmt::trim_sv(" aba ", " a")); + } + TEST(StrUtil, TrimFront) { EXPECT_EQ(""s, fmt::trim_front("", "")); @@ -45,6 +65,26 @@ namespace fmt EXPECT_EQ("ba "s, fmt::trim_front(" aba ", " a")); } + TEST(StrUtil, TrimFrontSv) + { + EXPECT_EQ(""sv, fmt::trim_front_sv("", "")); + EXPECT_EQ(""sv, fmt::trim_front_sv("", " ")); + EXPECT_EQ(""sv, fmt::trim_front_sv("", "a ")); + EXPECT_EQ(" "sv, fmt::trim_front_sv(" ", "")); + EXPECT_EQ(""sv, fmt::trim_front_sv(" ", " ")); + EXPECT_EQ("a "sv, fmt::trim_front_sv("a ", " ")); + EXPECT_EQ("a"sv, fmt::trim_front_sv(" a", " ")); + EXPECT_EQ("a a"sv, fmt::trim_front_sv("a a", " ")); + EXPECT_EQ("a a "sv, fmt::trim_front_sv("a a ", " ")); + EXPECT_EQ("a a"sv, fmt::trim_front_sv(" a a", " ")); + EXPECT_EQ("a a "sv, fmt::trim_front_sv(" a a ", " ")); + EXPECT_EQ("a a "sv, fmt::trim_front_sv("a a ", " ")); + EXPECT_EQ("a a "sv, fmt::trim_front_sv(" a a ", " ")); + EXPECT_EQ("a a"sv, fmt::trim_front_sv(" a a", " ")); + EXPECT_EQ(""sv, fmt::trim_front_sv(" a a ", " a")); + EXPECT_EQ("ba "sv, fmt::trim_front_sv(" aba ", " a")); + } + TEST(StrUtil, TrimBack) { std::string str; @@ -112,6 +152,26 @@ namespace fmt EXPECT_EQ(" ab"s, str); } + TEST(StrUtil, TrimBackSv) + { + EXPECT_EQ(""sv, fmt::trim_back_sv({}, "")); + EXPECT_EQ(""sv, fmt::trim_back_sv({}, " ")); + EXPECT_EQ(""sv, fmt::trim_back_sv({}, "a ")); + EXPECT_EQ(" "sv, fmt::trim_back_sv(" ", "")); + EXPECT_EQ(""sv, fmt::trim_back_sv(" ", " ")); + EXPECT_EQ("a"sv, fmt::trim_back_sv("a ", " ")); + EXPECT_EQ(" a"sv, fmt::trim_back_sv(" a", " ")); + EXPECT_EQ("a a"sv, fmt::trim_back_sv("a a", " ")); + EXPECT_EQ("a a"sv, fmt::trim_back_sv("a a ", " ")); + EXPECT_EQ(" a a"sv, fmt::trim_back_sv(" a a", " ")); + EXPECT_EQ(" a a"sv, fmt::trim_back_sv(" a a ", " ")); + EXPECT_EQ("a a"sv, fmt::trim_back_sv("a a ", " ")); + EXPECT_EQ(" a a"sv, fmt::trim_back_sv(" a a ", " ")); + EXPECT_EQ(" a a"sv, fmt::trim_back_sv(" a a", " ")); + EXPECT_EQ(""sv, fmt::trim_back_sv(" a a ", " a")); + EXPECT_EQ(" ab"sv, fmt::trim_back_sv(" aba ", " a")); + } + TEST(StrUtil, ToUpperToLower) { const std::string lowercase = "abcdefghijklmnopqrstuvwxyzäüöß0123456789 .,-<#+"; @@ -340,6 +400,155 @@ namespace fmt EXPECT_EQ(vec({"This", "is", "test!"}), fmt::split(" This is a test! ", {"a", " ", "b"}, true)); } + TEST(StrUtil, SplitSv) + { + using vec = std::vector; + + EXPECT_EQ(vec{""}, fmt::split_sv("", {}, false)); + EXPECT_EQ(vec{""}, fmt::split_sv("", {""}, false)); + EXPECT_EQ(vec{""}, fmt::split_sv("", {" "}, false)); + EXPECT_EQ(vec{""}, fmt::split_sv("", {"a"}, false)); + EXPECT_EQ(vec{""}, fmt::split_sv("", {"a "}, false)); + EXPECT_EQ(vec{""}, fmt::split_sv("", {"a b"}, false)); + EXPECT_EQ(vec{""}, fmt::split_sv("", {"a", " "}, false)); + EXPECT_EQ(vec{""}, fmt::split_sv("", {"a", " ", "b"}, false)); + + EXPECT_EQ(vec{" "}, fmt::split_sv(" ", {}, false)); + EXPECT_EQ(vec{" "}, fmt::split_sv(" ", {""}, false)); + EXPECT_EQ(vec{""}, fmt::split_sv(" ", {" "}, false)); + EXPECT_EQ(vec{" "}, fmt::split_sv(" ", {"a"}, false)); + EXPECT_EQ(vec{" "}, fmt::split_sv(" ", {"a "}, false)); + EXPECT_EQ(vec{" "}, fmt::split_sv(" ", {"a b"}, false)); + EXPECT_EQ(vec{""}, fmt::split_sv(" ", {"a", " "}, false)); + EXPECT_EQ(vec{""}, fmt::split_sv(" ", {"a", " ", "b"}, false)); + + EXPECT_EQ(vec{" "}, fmt::split_sv(" ", {}, false)); + EXPECT_EQ(vec{" "}, fmt::split_sv(" ", {""}, false)); + EXPECT_EQ(vec({"", ""}), fmt::split_sv(" ", {" "}, false)); + EXPECT_EQ(vec{" "}, fmt::split_sv(" ", {"a"}, false)); + EXPECT_EQ(vec{" "}, fmt::split_sv(" ", {"a "}, false)); + EXPECT_EQ(vec{" "}, fmt::split_sv(" ", {"a b"}, false)); + EXPECT_EQ(vec({"", ""}), fmt::split_sv(" ", {"a", " "}, false)); + EXPECT_EQ(vec({"", ""}), fmt::split_sv(" ", {"a", " ", "b"}, false)); + + EXPECT_EQ(vec{"a"}, fmt::split_sv("a", {}, false)); + EXPECT_EQ(vec{"a"}, fmt::split_sv("a", {""}, false)); + EXPECT_EQ(vec{"a"}, fmt::split_sv("a", {" "}, false)); + EXPECT_EQ(vec{""}, fmt::split_sv("a", {"a"}, false)); + EXPECT_EQ(vec{"a"}, fmt::split_sv("a", {"a "}, false)); + EXPECT_EQ(vec{"a"}, fmt::split_sv("a", {"a b"}, false)); + EXPECT_EQ(vec{""}, fmt::split_sv("a", {"a", " "}, false)); + EXPECT_EQ(vec{""}, fmt::split_sv("a", {"a", " ", "b"}, false)); + + EXPECT_EQ(vec{"aa"}, fmt::split_sv("aa", {}, false)); + EXPECT_EQ(vec{"aa"}, fmt::split_sv("aa", {""}, false)); + EXPECT_EQ(vec{"aa"}, fmt::split_sv("aa", {" "}, false)); + EXPECT_EQ(vec({"", ""}), fmt::split_sv("aa", {"a"}, false)); + EXPECT_EQ(vec{"aa"}, fmt::split_sv("aa", {"a "}, false)); + EXPECT_EQ(vec{"aa"}, fmt::split_sv("aa", {"a b"}, false)); + EXPECT_EQ(vec({"", ""}), fmt::split_sv("aa", {"a", " "}, false)); + EXPECT_EQ(vec({"", ""}), fmt::split_sv("aa", {"a", " ", "b"}, false)); + + EXPECT_EQ(vec{"a b"}, fmt::split_sv("a b", {}, false)); + EXPECT_EQ(vec{"a b"}, fmt::split_sv("a b", {""}, false)); + EXPECT_EQ(vec({"a", "b"}), fmt::split_sv("a b", {" "}, false)); + EXPECT_EQ(vec({"", " b"}), fmt::split_sv("a b", {"a"}, false)); + EXPECT_EQ(vec({"", "b"}), fmt::split_sv("a b", {"a "}, false)); + EXPECT_EQ(vec{""}, fmt::split_sv("a b", {"a b"}, false)); + EXPECT_EQ(vec({"", "", "b"}), fmt::split_sv("a b", {"a", " "}, false)); + EXPECT_EQ(vec({"", "", ""}), fmt::split_sv("a b", {"a", " ", "b"}, false)); + + EXPECT_EQ(vec{"a b c c b a"}, fmt::split_sv("a b c c b a", {}, false)); + EXPECT_EQ(vec{"a b c c b a"}, fmt::split_sv("a b c c b a", {""}, false)); + EXPECT_EQ(vec({"a", "b", "c", "c", "b", "a"}), fmt::split_sv("a b c c b a", {" "}, false)); + EXPECT_EQ(vec({"", " b c c b "}), fmt::split_sv("a b c c b a", {"a"}, false)); + EXPECT_EQ(vec({"", "b c c b a"}), fmt::split_sv("a b c c b a", {"a "}, false)); + EXPECT_EQ(vec({"", " c c b a"}), fmt::split_sv("a b c c b a", {"a b"}, false)); + EXPECT_EQ(vec({"", "", "b", "c", "c", "b", ""}), fmt::split_sv("a b c c b a", {"a", " "}, false)); + EXPECT_EQ(vec({"", "", "", "", "c", "c", "", "", ""}), fmt::split_sv("a b c c b a", {"a", " ", "b"}, false)); + + EXPECT_EQ(vec{" This is a test! "}, fmt::split_sv(" This is a test! ", {}, false)); + EXPECT_EQ(vec{" This is a test! "}, fmt::split_sv(" This is a test! ", {""}, false)); + EXPECT_EQ(vec({"", "This", "is", "a", "test!"}), fmt::split_sv(" This is a test! ", {" "}, false)); + EXPECT_EQ(vec({" This is ", " test! "}), fmt::split_sv(" This is a test! ", {"a"}, false)); + EXPECT_EQ(vec({" This is ", "test! "}), fmt::split_sv(" This is a test! ", {"a "}, false)); + EXPECT_EQ(vec{" This is a test! "}, fmt::split_sv(" This is a test! ", {"a b"}, false)); + EXPECT_EQ(vec({"", "This", "is", "", "", "test!"}), fmt::split_sv(" This is a test! ", {"a", " "}, false)); + EXPECT_EQ(vec({"", "This", "is", "", "", "test!"}), fmt::split_sv(" This is a test! ", {"a", " ", "b"}, false)); + + EXPECT_EQ(vec{}, fmt::split_sv("", {}, true)); + EXPECT_EQ(vec{}, fmt::split_sv("", {""}, true)); + EXPECT_EQ(vec{}, fmt::split_sv("", {" "}, true)); + EXPECT_EQ(vec{}, fmt::split_sv("", {"a"}, true)); + EXPECT_EQ(vec{}, fmt::split_sv("", {"a "}, true)); + EXPECT_EQ(vec{}, fmt::split_sv("", {"a b"}, true)); + EXPECT_EQ(vec{}, fmt::split_sv("", {"a", " "}, true)); + EXPECT_EQ(vec{}, fmt::split_sv("", {"a", " ", "b"}, true)); + + EXPECT_EQ(vec{" "}, fmt::split_sv(" ", {}, true)); + EXPECT_EQ(vec{" "}, fmt::split_sv(" ", {""}, true)); + EXPECT_EQ(vec{}, fmt::split_sv(" ", {" "}, true)); + EXPECT_EQ(vec{" "}, fmt::split_sv(" ", {"a"}, true)); + EXPECT_EQ(vec{" "}, fmt::split_sv(" ", {"a "}, true)); + EXPECT_EQ(vec{" "}, fmt::split_sv(" ", {"a b"}, true)); + EXPECT_EQ(vec{}, fmt::split_sv(" ", {"a", " "}, true)); + EXPECT_EQ(vec{}, fmt::split_sv(" ", {"a", " ", "b"}, true)); + + EXPECT_EQ(vec{" "}, fmt::split_sv(" ", {}, true)); + EXPECT_EQ(vec{" "}, fmt::split_sv(" ", {""}, true)); + EXPECT_EQ(vec{}, fmt::split_sv(" ", {" "}, true)); + EXPECT_EQ(vec{" "}, fmt::split_sv(" ", {"a"}, true)); + EXPECT_EQ(vec{" "}, fmt::split_sv(" ", {"a "}, true)); + EXPECT_EQ(vec{" "}, fmt::split_sv(" ", {"a b"}, true)); + EXPECT_EQ(vec{}, fmt::split_sv(" ", {"a", " "}, true)); + EXPECT_EQ(vec{}, fmt::split_sv(" ", {"a", " ", "b"}, true)); + + EXPECT_EQ(vec{"a"}, fmt::split_sv("a", {}, true)); + EXPECT_EQ(vec{"a"}, fmt::split_sv("a", {""}, true)); + EXPECT_EQ(vec{"a"}, fmt::split_sv("a", {" "}, true)); + EXPECT_EQ(vec{}, fmt::split_sv("a", {"a"}, true)); + EXPECT_EQ(vec{"a"}, fmt::split_sv("a", {"a "}, true)); + EXPECT_EQ(vec{"a"}, fmt::split_sv("a", {"a b"}, true)); + EXPECT_EQ(vec{}, fmt::split_sv("a", {"a", " "}, true)); + EXPECT_EQ(vec{}, fmt::split_sv("a", {"a", " ", "b"}, true)); + + EXPECT_EQ(vec{"aa"}, fmt::split_sv("aa", {}, true)); + EXPECT_EQ(vec{"aa"}, fmt::split_sv("aa", {""}, true)); + EXPECT_EQ(vec{"aa"}, fmt::split_sv("aa", {" "}, true)); + EXPECT_EQ(vec{}, fmt::split_sv("aa", {"a"}, true)); + EXPECT_EQ(vec{"aa"}, fmt::split_sv("aa", {"a "}, true)); + EXPECT_EQ(vec{"aa"}, fmt::split_sv("aa", {"a b"}, true)); + EXPECT_EQ(vec{}, fmt::split_sv("aa", {"a", " "}, true)); + EXPECT_EQ(vec{}, fmt::split_sv("aa", {"a", " ", "b"}, true)); + + EXPECT_EQ(vec{"a b"}, fmt::split_sv("a b", {}, true)); + EXPECT_EQ(vec{"a b"}, fmt::split_sv("a b", {""}, true)); + EXPECT_EQ(vec({"a", "b"}), fmt::split_sv("a b", {" "}, true)); + EXPECT_EQ(vec{" b"}, fmt::split_sv("a b", {"a"}, true)); + EXPECT_EQ(vec{"b"}, fmt::split_sv("a b", {"a "}, true)); + EXPECT_EQ(vec{}, fmt::split_sv("a b", {"a b"}, true)); + EXPECT_EQ(vec{"b"}, fmt::split_sv("a b", {"a", " "}, true)); + EXPECT_EQ(vec{}, fmt::split_sv("a b", {"a", " ", "b"}, true)); + + EXPECT_EQ(vec{"a b c c b a"}, fmt::split_sv("a b c c b a", {}, true)); + EXPECT_EQ(vec{"a b c c b a"}, fmt::split_sv("a b c c b a", {""}, true)); + EXPECT_EQ(vec({"a", "b", "c", "c", "b", "a"}), fmt::split_sv("a b c c b a", {" "}, true)); + EXPECT_EQ(vec{" b c c b "}, fmt::split_sv("a b c c b a", {"a"}, true)); + EXPECT_EQ(vec{"b c c b a"}, fmt::split_sv("a b c c b a", {"a "}, true)); + EXPECT_EQ(vec{" c c b a"}, fmt::split_sv("a b c c b a", {"a b"}, true)); + EXPECT_EQ(vec({"b", "c", "c", "b"}), fmt::split_sv("a b c c b a", {"a", " "}, true)); + EXPECT_EQ(vec({"c", "c"}), fmt::split_sv("a b c c b a", {"a", " ", "b"}, true)); + + EXPECT_EQ(vec{" This is a test! "}, fmt::split_sv(" This is a test! ", {}, true)); + EXPECT_EQ(vec{" This is a test! "}, fmt::split_sv(" This is a test! ", {""}, true)); + EXPECT_EQ(vec({"This", "is", "a", "test!"}), fmt::split_sv(" This is a test! ", {" "}, true)); + EXPECT_EQ(vec({" This is ", " test! "}), fmt::split_sv(" This is a test! ", {"a"}, true)); + EXPECT_EQ(vec({" This is ", "test! "}), fmt::split_sv(" This is a test! ", {"a "}, true)); + EXPECT_EQ(vec{" This is a test! "}, fmt::split_sv(" This is a test! ", {"a b"}, true)); + EXPECT_EQ(vec({"This", "is", "test!"}), fmt::split_sv(" This is a test! ", {"a", " "}, true)); + EXPECT_EQ(vec({"This", "is", "test!"}), fmt::split_sv(" This is a test! ", {"a", " ", "b"}, true)); + } + TEST(StrUtil, Merge) { using vec = std::vector; diff --git a/rpcs3/util/media_utils.cpp b/rpcs3/util/media_utils.cpp index d4f450ab69..60a337e750 100644 --- a/rpcs3/util/media_utils.cpp +++ b/rpcs3/util/media_utils.cpp @@ -82,8 +82,8 @@ namespace utils return; } - std::string msg = line; - fmt::trim_back(msg, "\n\r\t "); + std::string msg_buf = line; + std::string_view msg = fmt::trim_back_sv(msg_buf, "\n\r\t "); if (level <= AV_LOG_ERROR) media_log.error("av_log: %s", msg); diff --git a/rpcs3/util/sysinfo.cpp b/rpcs3/util/sysinfo.cpp index bf9376239c..94563e8d10 100755 --- a/rpcs3/util/sysinfo.cpp +++ b/rpcs3/util/sysinfo.cpp @@ -850,7 +850,7 @@ static const bool s_tsc_freq_evaluated = []() -> bool printf("[TSC calibration] Available clock sources: '%s'\n", clock_sources.c_str()); // Check if the Kernel has blacklisted the TSC - const auto available_clocks = fmt::split(clock_sources, { " " }); + const auto available_clocks = fmt::split_sv(clock_sources, { " " }); const bool tsc_reliable = std::find(available_clocks.begin(), available_clocks.end(), "tsc") != available_clocks.end(); if (!tsc_reliable)