Merge pull request #2168 from MaaAssistantArknights/feat/string_split_view

feat: 删除 `asst::utils::string_split_view`, 使用 `asst::views::split`
This commit is contained in:
Horror Proton
2022-10-06 10:52:57 +08:00
committed by GitHub
3 changed files with 48 additions and 210 deletions

View File

@@ -26,7 +26,10 @@ namespace asst::http
bool _analyze_status_line(std::string_view status_line)
{
size_t _word_count = 0;
for (const auto& word : utils::string_split(status_line, " ")) {
for (std::string_view word :
views::split(status_line, ' ') | views::transform([&](const auto& rng) -> std::string_view {
return utils::make_string_view(rng);
})) {
++_word_count;
if (_word_count == 1) {
if (!_accepted_protocol_version.contains(word)) {
@@ -78,10 +81,14 @@ namespace asst::http
requires std::is_constructible_v<std::string, Args...>
Response(Args&&... args) : m_raw_data(std::forward<Args>(args)...)
{
constexpr std::string_view delim = "\r\n";
std::string_view this_view = m_raw_data;
bool _is_status_line = true;
bool _is_data_line = false;
for (const auto& line : utils::string_split(this_view, "\r\n")) {
for (std::string_view line :
views::split(this_view, delim) | views::transform([&](const auto& rng) -> std::string_view {
return utils::make_string_view(rng);
})) {
// status
if (_is_status_line) {
if (!_analyze_status_line(line)) {

View File

@@ -5,6 +5,7 @@
#include <filesystem>
#include <fstream>
#include <memory>
#include <sstream>
#include <string>
@@ -25,6 +26,22 @@ namespace asst::utils
template <typename char_t = char>
using pair_of_string_view = std::pair<std::basic_string_view<char_t>, std::basic_string_view<char_t>>;
#ifdef ASST_USE_RANGES_RANGE_V3
// workaround for P2210R2
template <ranges::forward_range Rng>
requires(requires(Rng rng) { std::basic_string_view(std::addressof(*rng.begin()), ranges::distance(rng)); })
inline auto make_string_view(Rng rng)
{
return std::basic_string_view(std::addressof(*rng.begin()), ranges::distance(rng));
}
#else
template <ranges::contiguous_range Rng>
inline auto make_string_view(Rng rng)
{
return std::basic_string_view(rng.begin(), rng.end());
}
#endif
template <typename char_t>
inline void _string_replace_all(std::basic_string<char_t>& str, std::basic_string_view<char_t> old_value,
std::basic_string_view<char_t> new_value)
@@ -95,175 +112,6 @@ namespace asst::utils
return str;
}
// 延迟求值的 string_split分隔符可以为字符或字符串
template <typename char_t>
class string_split_view : public ranges::view_interface<string_split_view<char_t>>
{
private:
using base_string_view = std::basic_string_view<char_t>;
using base_string = std::basic_string<char_t>;
using string_iter = typename base_string_view::const_iterator;
base_string_view _rng {};
base_string_view _pat {};
base_string_view _nxt {};
class _iterator
{
private:
string_split_view* _pre = nullptr;
string_iter _cur = {};
base_string_view _nxt = {};
bool _trailing_empty = false;
public:
using iterator_concept = std::forward_iterator_tag;
using iterator_category = std::input_iterator_tag;
using value_type = base_string_view;
using difference_type = typename base_string_view::difference_type;
_iterator() = default;
constexpr _iterator(string_split_view& prev, string_iter curr, base_string_view next) noexcept
: _pre(std::addressof(prev)), _cur(curr), _nxt(next)
{}
[[nodiscard]] constexpr string_iter base() const noexcept { return _cur; }
[[nodiscard]] constexpr value_type operator*() const noexcept { return { _cur, _nxt.cbegin() }; }
constexpr _iterator& operator++()
{
auto _end = _pre->_rng.cend();
if (_cur = _nxt.cbegin(); _cur == _end) {
_trailing_empty = false;
return *this;
}
if (_cur = _nxt.cend(); _cur == _end) {
_trailing_empty = true;
_nxt = { _cur, _cur };
return *this;
}
if (size_t _len = _pre->_pat.length(); !_len) {
auto _beg = _cur + 1;
_nxt = { _beg, _beg };
}
else if (const auto _pos = base_string_view(_cur, _end).find(_pre->_pat);
_pos == base_string_view::npos) {
_nxt = { _end, _end };
}
else {
auto _beg = _cur + _pos;
_nxt = { _beg, _beg + _pre->_pat.length() };
}
return *this;
}
constexpr _iterator operator++(int)
{
auto _tmp = *this;
++*this;
return _tmp;
}
friend constexpr bool operator==(const _iterator& _lhs, const _iterator& _rhs) noexcept
{
return _lhs._cur == _rhs._cur && _lhs._trailing_empty == _rhs._trailing_empty;
}
};
public:
string_split_view() = default;
template <typename rng_t, typename pat_t>
requires std::convertible_to<pat_t, base_string_view>
constexpr string_split_view(rng_t&& rang, pat_t&& patt) noexcept
: _rng(std::forward<rng_t>(rang)), _pat(std::forward<pat_t>(patt))
{}
template <typename rng_t>
constexpr string_split_view(rng_t&&, char_t&&)
{
// 摆烂辣!解决不了临时变量导致 _pat 悬垂的问题
ASST_STATIC_ASSERT_FALSE("please use `views::split` instead ^_^", rng_t);
}
template <typename rng_t>
constexpr string_split_view(rng_t&& rang, const char_t& elem) noexcept
: _rng(std::forward<rng_t>(rang)), _pat(&elem, 1)
{}
[[nodiscard]] constexpr const base_string_view& base() const noexcept { return _rng; }
[[nodiscard]] constexpr auto begin()
{
const auto _beg = _rng.cbegin(), _end = _rng.cend();
if (_nxt.empty()) {
if (size_t _len = _pat.length(); !_len) {
auto _cur = _beg + 1;
_nxt = { _cur, _cur };
}
else if (const auto _pos = _rng.find(_pat); _pos == base_string_view::npos) {
_nxt = { _end, _end };
}
else {
auto _cur = _beg + _pos;
_nxt = { _cur, _cur + _pat.length() };
}
}
return _iterator { *this, _beg, _nxt };
}
[[nodiscard]] constexpr auto end() { return _iterator { *this, _rng.cend(), {} }; }
};
template <ranges::range str_t, class pat_t>
string_split_view(str_t, pat_t) -> string_split_view<typename str_t::value_type>;
template <class str_t, class pat_t>
string_split_view(str_t*, pat_t) -> string_split_view<typename std::remove_cv<str_t>::type>;
struct _string_split_fn
{
template <ranges::range str_t, class pat_t>
[[nodiscard]] constexpr auto operator()(str_t&& _str, pat_t&& _pat) const
noexcept(noexcept(string_split_view(std::forward<str_t>(_str), std::forward<pat_t>(_pat))))
requires requires { string_split_view(static_cast<str_t&&>(_str), static_cast<pat_t&&>(_pat)); }
{
return string_split_view(std::forward<str_t>(_str), std::forward<pat_t>(_pat));
}
};
inline constexpr _string_split_fn string_split;
// // 以低内存开销拆分一个字符串;注意当 src 析构后,返回值将失效
// template <typename str_t, typename char_t = typename str_t::value_type, typename delimiter_t>
// requires std::convertible_to<str_t, std::basic_string_view<char_t>> &&
// std::convertible_to<delimiter_t, std::basic_string_view<char_t>>
// inline std::vector<std::basic_string_view<char_t>> string_split(const str_t& src, delimiter_t delimiter,
// size_t split_count = -1)
// {
// std::basic_string_view<char_t> delimiter_view = delimiter;
// std::basic_string_view<char_t> str = src;
// typename std::basic_string<char_t>::size_type pos1 = 0;
// typename std::basic_string<char_t>::size_type pos2 = str.find(delimiter_view);
// std::vector<std::basic_string_view<char_t>> result;
// while (split_count-- && pos2 != str.npos) {
// result.emplace_back(str.substr(pos1, pos2 - pos1));
// pos1 = pos2 + delimiter_view.length();
// pos2 = str.find(delimiter_view, pos1);
// }
// if (pos1 != str.length()) result.emplace_back(str.substr(pos1));
// return result;
// }
inline std::string get_format_time()
{
char buff[128] = { 0 };
@@ -437,18 +285,3 @@ namespace asst::utils
}
}
} // namespace asst::utils
#if defined(ASST_USE_RANGES_RANGE_V3) || defined(ASST_USE_RANGES_STL)
#ifdef ASST_USE_RANGES_RANGE_V3
namespace ranges
#else // ASST_USE_RANGES_STL
namespace std::ranges
#endif
{
template <typename R>
inline constexpr bool enable_view<asst::utils::string_split_view<R>> = enable_view<std::basic_string_view<R>>;
template <typename R>
inline constexpr bool enable_borrowed_range<asst::utils::string_split_view<R>> =
enable_borrowed_range<std::basic_string_view<R>>;
}
#endif

View File

@@ -628,8 +628,15 @@ bool update_battle_chars_info(const std::filesystem::path& input_dir, const std:
bool update_recruitment_data(const std::filesystem::path& input_dir, const std::filesystem::path& output, bool is_base)
{
using namespace asst::utils;
using asst::ranges::find_if, asst::views::filter;
using asst::ranges::find_if, asst::ranges::range;
using asst::views::filter, asst::views::split, asst::views::transform, asst::views::drop_while;
using asst::utils::_string_replace_all;
auto not_empty = []<range Rng>(Rng str) -> bool { return !str.empty(); };
auto make_string_view = []<range Rng>(Rng str) -> std::string_view {
return asst::utils::make_string_view(str);
};
const auto& recruitment_file = input_dir / "gacha_table.json";
const auto& operators_file = input_dir / "character_table.json";
@@ -645,28 +652,19 @@ bool update_recruitment_data(const std::filesystem::path& input_dir, const std::
std::string recruitment_details = recruitment_opt->at("recruitDetail").as_string();
remove_xml(recruitment_details);
_string_replace_all(recruitment_details, "\\n", "");
auto splited = string_split(recruitment_details, "");
bool is_useless = true;
auto not_empty = [](std::string_view str) -> bool { return !str.empty(); };
for (auto s : splited | filter(not_empty)) {
if (s.find("Lancet-2") != std::string_view::npos) {
is_useless = false;
}
if (is_useless) {
continue;
}
#if 0
std::string_view s1 = (string_split(s, "\n") | filter(not_empty)).front();
#else
std::string_view s1;
if (auto s_splited = string_split(s, "\n") | filter(not_empty); !s_splited.empty()) {
s1 = s_splited.front();
}
else {
continue;
}
#endif
for (auto n : string_split(s1, "/") | filter(not_empty)) {
constexpr std::string_view star_delim = "";
auto items =
// 按照 ★ 分割
recruitment_details | split(star_delim) | filter(not_empty) | transform(make_string_view) |
// 忽略 Lancet-2 之前的东西
drop_while([&](std::string_view str) { return str.find("Lancet-2") == std::string_view::npos; }) |
// 按照 \n 分割,若非空则取第一个元素
transform([&](auto str) { return str | split('\n') | filter(not_empty); }) | filter(not_empty) |
transform([&](auto strs) { return make_string_view(strs.front()); });
for (std::string_view s : items) {
for (std::string_view n : s | split('/') | filter(not_empty) | transform(make_string_view)) {
std::string name(n);
trim(name);
chars_list.emplace_back(name);