Skip to content

Commit

Permalink
util/LocaleString: add SplitAtCharMB()
Browse files Browse the repository at this point in the history
  • Loading branch information
MaxKellermann committed Sep 1, 2024
1 parent 339e56f commit 7a5bf44
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 2 deletions.
3 changes: 1 addition & 2 deletions src/BasicMarquee.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ using std::string_view_literals::operator""sv;
std::string_view
BasicMarquee::ScrollString() const noexcept
{
const char *p = AtCharMB(buffer, offset);
return TruncateAtWidthMB(p, width);
return TruncateAtWidthMB(SplitAtCharMB(buffer, offset).second, width);
}

bool
Expand Down
9 changes: 9 additions & 0 deletions src/util/LocaleString.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

#pragma once

#include "util/StringSplit.hxx"

#include <cstddef>
#include <string_view>

Expand Down Expand Up @@ -48,6 +50,13 @@ PrevCharMB(const char *start, const char *reference) noexcept;
const char *
AtCharMB(std::string_view s, size_t i) noexcept;

inline std::pair<std::string_view, std::string_view>
SplitAtCharMB(std::string_view s, std::size_t i) noexcept
{
const char *p = AtCharMB(s, i);
return Partition(s, p - s.data());
}

/**
* Returns the number of terminal cells occupied by this multi-byte
* string.
Expand Down
93 changes: 93 additions & 0 deletions src/util/StringSplit.hxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// SPDX-License-Identifier: BSD-2-Clause
// author: Max Kellermann <[email protected]>

#pragma once

#include <algorithm>
#include <string_view>
#include <type_traits>

template<typename T>
constexpr std::pair<std::basic_string_view<T>, std::basic_string_view<T>>
Partition(const std::basic_string_view<T> haystack,
const typename std::basic_string_view<T>::size_type position) noexcept
{
return {
haystack.substr(0, position),
haystack.substr(position),
};
}

template<typename T>
constexpr std::pair<std::basic_string_view<T>, std::basic_string_view<T>>
Partition(const std::basic_string_view<T> haystack,
const typename std::basic_string_view<T>::const_pointer position) noexcept
{
return Partition(haystack, position - haystack.data());
}

template<typename T>
requires(!std::is_same_v<typename std::basic_string_view<T>::const_pointer,
typename std::basic_string_view<T>::const_iterator>)
constexpr std::pair<std::basic_string_view<T>, std::basic_string_view<T>>
Partition(const std::basic_string_view<T> haystack,
const typename std::basic_string_view<T>::const_iterator i) noexcept
{
return Partition(haystack, i - haystack.begin());
}

template<typename T>
constexpr std::pair<std::basic_string_view<T>, std::basic_string_view<T>>
PartitionWithout(const std::basic_string_view<T> haystack,
const typename std::basic_string_view<T>::size_type separator) noexcept
{
return {
haystack.substr(0, separator),
haystack.substr(separator + 1),
};
}

/**
* Split the string at the first occurrence of the given character.
* If the character is not found, then the first value is the whole
* string and the second value is nullptr.
*/
template<typename T>
constexpr std::pair<std::basic_string_view<T>, std::basic_string_view<T>>
Split(const std::basic_string_view<T> haystack, const T ch) noexcept
{
const auto i = haystack.find(ch);
if (i == haystack.npos)
return {haystack, {}};

return PartitionWithout(haystack, i);
}

/**
* Split the string at the last occurrence of the given
* character. If the character is not found, then the first
* value is the whole string and the second value is nullptr.
*/
template<typename T>
constexpr std::pair<std::basic_string_view<T>, std::basic_string_view<T>>
SplitLast(const std::basic_string_view<T> haystack, const T ch) noexcept
{
const auto i = haystack.rfind(ch);
if (i == haystack.npos)
return {haystack, {}};

return PartitionWithout(haystack, i);
}

/**
* Find the first character that does not match the given predicate
* and split at this boundary.
*/
template<typename T, typename P>
constexpr std::pair<std::basic_string_view<T>, std::basic_string_view<T>>
SplitWhile(const std::basic_string_view<T> haystack, P &&predicate) noexcept
{
const auto i = std::find_if_not(haystack.begin(), haystack.end(),
std::forward<P>(predicate));
return Partition(haystack, i);
}

0 comments on commit 7a5bf44

Please sign in to comment.