#pragma once
#include "ascii.h"
#include <util/generic/string.h>
#include <util/generic/strbuf.h>
#include <utility>
template <class It>
struct TIsAsciiSpaceAdapter {
bool operator()(const It& it) const noexcept {
return IsAsciiSpace(*it);
}
};
template <class It>
TIsAsciiSpaceAdapter<It> IsAsciiSpaceAdapter(It) {
return {};
}
template <class TChar>
struct TEqualsStripAdapter {
TEqualsStripAdapter(TChar ch)
: Ch(ch)
{
}
template <class It>
bool operator()(const It& it) const noexcept {
return *it == Ch;
}
const TChar Ch;
};
template <class TChar>
TEqualsStripAdapter<TChar> EqualsStripAdapter(TChar ch) {
return {ch};
}
template <class It, class TStripCriterion>
inline void StripRangeBegin(It& b, const It& e, TStripCriterion&& criterion) noexcept {
while (b < e && criterion(b)) {
++b;
}
}
template <class It>
inline void StripRangeBegin(It& b, const It& e) noexcept {
StripRangeBegin(b, e, IsAsciiSpaceAdapter(b));
}
template <class It, class TStripCriterion>
inline void StripRangeEnd(const It& b, It& e, TStripCriterion&& criterion) noexcept {
while (b < e && criterion(e - 1)) {
--e;
}
}
template <class It>
inline void StripRangeEnd(const It& b, It& e) noexcept {
StripRangeEnd(b, e, IsAsciiSpaceAdapter(b));
}
template <bool stripBeg, bool stripEnd>
struct TStripImpl {
template <class It, class TStripCriterion>
static inline bool StripRange(It& b, It& e, TStripCriterion&& criterion) noexcept {
const size_t oldLen = e - b;
if (stripBeg) {
StripRangeBegin(b, e, criterion);
}
if (stripEnd) {
StripRangeEnd(b, e, criterion);
}
const size_t newLen = e - b;
return newLen != oldLen;
}
template <class T, class TStripCriterion>
static inline bool StripString(const T& from, T& to, TStripCriterion&& criterion) {
auto b = from.begin();
auto e = from.end();
if (StripRange(b, e, criterion)) {
to = T(b, e - b);
return true;
}
to = from;
return false;
}
template <class T, class TStripCriterion>
static inline T StripString(const T& from, TStripCriterion&& criterion) {
T ret;
StripString(from, ret, criterion);
return ret;
}
template <class T>
static inline T StripString(const T& from) {
return StripString(from, IsAsciiSpaceAdapter(from.begin()));
}
};
template <class It, class TStripCriterion>
inline bool StripRange(It& b, It& e, TStripCriterion&& criterion) noexcept {
return TStripImpl<true, true>::StripRange(b, e, criterion);
}
template <class It>
inline bool StripRange(It& b, It& e) noexcept {
return StripRange(b, e, IsAsciiSpaceAdapter(b));
}
template <class It, class TStripCriterion>
inline bool Strip(It& b, size_t& len, TStripCriterion&& criterion) noexcept {
It e = b + len;
if (StripRange(b, e, criterion)) {
len = e - b;
return true;
}
return false;
}
template <class It>
inline bool Strip(It& b, size_t& len) noexcept {
return Strip(b, len, IsAsciiSpaceAdapter(b));
}
template <class T, class TStripCriterion>
static inline bool StripString(const T& from, T& to, TStripCriterion&& criterion) {
return TStripImpl<true, true>::StripString(from, to, criterion);
}
template <class T>
static inline bool StripString(const T& from, T& to) {
return StripString(from, to, IsAsciiSpaceAdapter(from.begin()));
}
template <class T, class TStripCriterion>
static inline T StripString(const T& from, TStripCriterion&& criterion) {
return TStripImpl<true, true>::StripString(from, criterion);
}
template <class T>
static inline T StripString(const T& from) {
return TStripImpl<true, true>::StripString(from);
}
template <class T>
static inline T StripStringLeft(const T& from) {
return TStripImpl<true, false>::StripString(from);
}
template <class T>
static inline T StripStringRight(const T& from) {
return TStripImpl<false, true>::StripString(from);
}
template <class T, class TStripCriterion>
static inline T StripStringLeft(const T& from, TStripCriterion&& criterion) {
return TStripImpl<true, false>::StripString(from, criterion);
}
template <class T, class TStripCriterion>
static inline T StripStringRight(const T& from, TStripCriterion&& criterion) {
return TStripImpl<false, true>::StripString(from, criterion);
}
/// Copies the given string removing leading and trailing spaces.
static inline bool Strip(const TString& from, TString& to) {
return StripString(from, to);
}
/// Removes leading and trailing spaces from the string.
inline TString& StripInPlace(TString& s) {
Strip(s, s);
return s;
}
/// Returns a copy of the given string with removed leading and trailing spaces.
inline TString Strip(const TString& s) Y_WARN_UNUSED_RESULT;
inline TString Strip(const TString& s) {
TString ret = s;
Strip(ret, ret);
return ret;
}
template <class TChar, class TWhitespaceFunc>
size_t CollapseImpl(TChar* s, size_t n, const TWhitespaceFunc& isWhitespace) {
size_t newLen = 0;
for (size_t i = 0; i < n; ++i, ++newLen) {
size_t nextNonSpace = i;
while (nextNonSpace < n && isWhitespace(s[nextNonSpace])) {
++nextNonSpace;
}
size_t numSpaces = nextNonSpace - i;
if (numSpaces > 1 || (numSpaces == 1 && s[i] != ' ')) {
s[newLen] = ' ';
i = nextNonSpace - 1;
} else {
s[newLen] = s[i];
}
}
return newLen;
}
template <class TStringType, class TWhitespaceFunc>
bool CollapseImpl(const TStringType& from, TStringType& to, size_t maxLen, const TWhitespaceFunc& isWhitespace) {
to = from;
maxLen = maxLen ? Min(maxLen, to.size()) : to.size();
for (size_t i = 0; i < maxLen; ++i) {
if (isWhitespace(to[i]) && (to[i] != ' ' || isWhitespace(to[i + 1]))) {
size_t tailSize = maxLen - i;
size_t newTailSize = CollapseImpl(to.begin() + i, tailSize, isWhitespace);
to.remove(i + newTailSize, tailSize - newTailSize);
return true;
}
}
return false;
}
bool Collapse(const TString& from, TString& to, size_t maxLen = 0);
/// Replaces several consequtive space symbols with one (processing is limited to maxLen bytes)
inline TString& CollapseInPlace(TString& s, size_t maxLen = 0) {
Collapse(s, s, maxLen);
return s;
}
/// Replaces several consequtive space symbols with one (processing is limited to maxLen bytes)
inline TString Collapse(const TString& s, size_t maxLen = 0) Y_WARN_UNUSED_RESULT;
inline TString Collapse(const TString& s, size_t maxLen) {
TString ret;
Collapse(s, ret, maxLen);
return ret;
}
void CollapseText(const TString& from, TString& to, size_t maxLen);
/// The same as Collapse() + truncates the string to maxLen.
/// @details An ellipsis is inserted at the end of the truncated line.
inline void CollapseText(TString& s, size_t maxLen) {
TString to;
CollapseText(s, to, maxLen);
s = to;
}