31 #ifndef KBLIB_STRINGOPS_H
32 #define KBLIB_STRINGOPS_H
42 #include <initializer_list>
45 #include <type_traits>
48 # include <string_view>
53 #if true or KBLIB_USE_CXX17
63 : contains_type<std::tuple<char, wchar_t, char16_t, char32_t
76 constexpr
bool is_character_v = is_character<C>::value;
86 template <typename T, bool = std::is_arithmetic<T>::value>
87 struct arithmetic_type {
97 struct arithmetic_type<T, true> {
103 template <
typename T>
104 using arithmetic_type_t =
typename arithmetic_type<T>::type;
113 template <
typename T,
typename = arithmetic_type_t<T>>
119 using type = std::string;
140 template <
typename T>
141 struct str_type<T, void> {
151 return std::forward<T>(in);
158 struct str_type<char, char> {
166 struct str_type<wchar_t, wchar_t> {
167 using type = wchar_t;
168 KBLIB_NODISCARD static auto convert(
wchar_t in) ->
wchar_t {
return in; }
174 struct str_type<char16_t, char16_t> {
175 using type = char16_t;
184 struct str_type<char32_t, char32_t> {
185 using type = char32_t;
195 struct str_type<char8_t, char8_t> {
196 using type = char8_t;
197 KBLIB_NODISCARD static auto convert(char8_t in) -> char8_t {
return in; }
203 template <
typename T>
204 using str_type_t =
typename str_type<T>::type;
216 template <
typename Str>
218 if constexpr (std::is_array_v<std::remove_reference_t<Str>>) {
220 }
else if constexpr (std::is_pointer_v<std::decay_t<Str>>) {
221 return std::char_traits<
std::decay_t<decltype(*str)>>::length(str);
222 }
else if constexpr (is_character_v<std::decay_t<Str>>) {
224 }
else if constexpr (std::is_integral_v<std::decay_t<Str>>) {
226 }
else if constexpr (std::is_floating_point_v<std::decay_t<Str>>) {
233 template <
typename CharT>
236 return std::char_traits<CharT>::length(str);
250 template <
typename string,
typename F,
typename... S>
251 auto append(
string&& out, F&& f, S&&... tail) ->
void {
252 if constexpr (is_character_v<std::decay_t<F>>) {
254 }
else if constexpr (std::is_arithmetic_v<std::decay_t<F>>) {
259 if constexpr (
sizeof...(S) > 0) {
260 append(out, tail...);
267 template <std::
size_t I,
typename T>
272 template <
class Idxs,
class... Ts>
275 template <std::size_t... Idxs,
typename... Ts>
276 struct values<
std::index_sequence<Idxs...>, Ts...> : value<Idxs, Ts>... {};
278 template <
typename string,
typename... S, std::size_t... I>
279 KBLIB_NODISCARD auto concat_impl(std::index_sequence<I...>, S&&... ins)
281 values<std::index_sequence<I...>, detail::str_type_t<S>...> buf{
282 {detail::str_type<S>::convert(std::forward<S>(ins))}...};
285 = (strsize(
static_cast<value<I, detail::str_type_t<S>
>&>(buf).v) + ...
288 append(ret,
static_cast<value<I, detail::str_type_t<S>
>&>(buf).v...);
304 template <
typename string = std::string,
typename F,
typename... S>
306 return detail::concat_impl<string>(
307 std::make_index_sequence<1 +
sizeof...(S)>{}, std::forward<F>(f),
308 std::forward<S>(ins)...);
318 template <
typename string = std::
string,
typename str>
319 KBLIB_NODISCARD auto concat(std::initializer_list<str> ins) ->
string {
322 ins.begin(), ins.end(), std::size_t{0},
323 [](std::size_t z,
const str& s) { return z + strsize(s); }));
324 for (
auto&& s : ins) {
340 KBLIB_NODISCARD auto operator()(
wchar_t c) ->
bool {
return isspace(c); }
344 for (
auto v :
" \t\r\n\f\v") {
352 for (
auto v : L
" \t\r\n\f\v") {
369 template <
typename range,
typename string = std::
string>
374 begin(in), end(in), std::size_t{},
375 [](std::size_t l,
const auto& x) {
return l + strsize(x); });
376 auto ret = *begin(in);
379 consumer([&](
const auto& x) { append(ret, joiner, x); }));
382 return typename value_type_linear<range>::type{};
395 template <
typename Container = std::vector<std::
string>,
typename Predicate,
400 typename Container::value_type::value_type>::value,
403 bool delim_run =
true;
404 const char* begpos{};
405 auto endpos = begpos;
406 for (
const auto& c : in) {
413 ret.emplace_back(begpos, &c - begpos);
414 }
else if (not spacer(c)) {
420 if (not delim_run and begpos != endpos) {
421 ret.emplace_back(begpos, endpos - begpos + 1);
432 template <
typename Container = std::vector<std::
string>,
typename String>
444 template <
typename Container = std::vector<std::
string>,
typename String>
446 const String& in,
typename Container::value_type::value_type delim)
449 bool delim_run =
true;
450 using CharT =
typename Container::value_type::value_type;
451 const CharT* begpos{};
452 auto endpos = begpos;
453 for (
const CharT& c : in) {
460 ret.emplace_back(begpos, &c - begpos);
461 }
else if (c != delim) {
467 if (not delim_run and begpos != endpos) {
468 ret.emplace_back(&*begpos, endpos - begpos + 1);
473 template <
typename Container = std::vector<std::
string>,
typename String>
476 bool delim_run =
true;
481 }
else if (c != delim) {
484 ret.back().push_back(c);
487 if (ret.back().empty()) {
500 template <
typename Container = std::vector<std::
string>,
typename String>
503 for (std::size_t pos1{}, pos2{str.find(delim)}; pos1 != str.npos;) {
504 ret.emplace_back(str, pos1, pos2 - pos1);
506 if (pos1 != str.npos) {
520 template <
typename Container = std::vector<std::
string>,
typename String,
525 typename Container::value_type::value_type>::value,
528 for (std::size_t pos1{}, pos2{str.find(delim)}; pos1 != str.npos;) {
529 ret.emplace_back(str, pos1, pos2 - pos1);
532 if (pos1 != str.npos) {
551 template <
typename string>
553 std::reverse(val.begin(), val.end());
559 template <
typename CharT>
563 template <
typename CharT,
typename IntT>
590 template <
typename string>
593 [](
auto c) { return detail::tolower(c); });
603 template <
typename string>
606 [](
auto c) { return detail::toupper(c); });
621 template <
typename string>
625 for (std::size_t i = 0; i < count; ++i) {
640 return std::string(count, val);
643 #if KBLIB_USE_STRING_VIEW
652 std::string_view needle) ->
bool {
653 return haystack.size() >= needle.size()
654 and haystack.compare(haystack.size() - needle.size(),
655 std::string_view::npos, needle)
667 return not haystack.empty() and haystack.back() == needle;
677 std::string_view needle) ->
bool {
678 return haystack.size() >= needle.size()
679 and haystack.compare(0, needle.size(), needle) == 0;
690 return not haystack.empty() and haystack.front() == needle;
Provides general-purpose algorithms, similar to the <algorithms> header.
auto to_char_type(IntT ch)
auto towlower(wchar_t ch)
auto to_int_type(CharT ch)
auto towupper(wchar_t ch)
constexpr auto size(const C &c) -> decltype(c.size())
The main namespace in which all entities from kblib are defined.
auto split_tokens(const String &in, Predicate spacer) -> return_assert_t< is_callable< Predicate, typename Container::value_type::value_type >::value, Container >
Split a string on all condensed delimiters.
constexpr auto exchange(T &obj, U &&new_value) -> T
constexpr auto size(const C &c) -> decltype(c.size())
auto consumer(F f) -> consume_iterator< F >
Creates a consume_iterator of deduced type F.
auto kbsplit2(const String &in, char delim=' ') -> Container
constexpr auto tolower(string str) -> string
Folds all characters in a string using the default execution character set to lowercase.
auto try_reserve(C &c, std::size_t s) noexcept(noexcept(c.reserve(s))) -> void
Attempt to reserve capacity in a container. No-op if unsupported.
constexpr auto range(Value min, Value max, Delta step=0) -> range_t< Value, Delta >
Constructs a range from beginning, end, and step amount. The range is half-open, that is min is in th...
constexpr auto ends_with(BidirIt1 begin1, BidirIt1 end1, BidirIt2 begin2, BidirIt2 end2, BinaryPred pred={}) -> enable_if_t<(is_bidirectional_iterator_v< BidirIt1 > and is_bidirectional_iterator_v< BidirIt2 >) and not(is_random_access_iterator_v< BidirIt1 > and is_random_access_iterator_v< BidirIt2 >), bool >
Checks if a given range ends with a particular subrange.
constexpr auto starts_with(InputIt1 begin1, EndIt1 end1, InputIt2 begin2, EndIt2 end2, BinaryPred pred) -> enable_if_t<(is_input_iterator_v< InputIt1 > and is_input_iterator_v< InputIt2 >) and not(is_random_access_iterator_v< InputIt1 > and is_random_access_iterator_v< InputIt2 >), bool >
Checks if a given range starts with a particular subrange.
auto reverse_str(string val) -> string
Reverses all the elements of its input.
auto to_string(Int num) -> std::string
typename std::decay< T >::type decay_t
auto split_dsv(const String &str, char delim) -> Container
Split a string on all instances of delim.
constexpr auto count_digits(Number val) -> enable_if_t< std::is_floating_point< Number >::value, int >
Calculates the number of decimal digits needed to represent a number, plus one for negative numbers.
constexpr auto accumulate(InputIt first, InputIt last, T init) -> T
A constexpr version of std::accumulate.
auto toupper(string str) -> string
Folds all characters in a string using the default execution character set to uppercase.
constexpr auto copy(InputIt first, EndIt last, OutputIt out) -> OutputIt
Copies all elements of [first, last) to out. It also allows for a sentinel end iterator.
typename return_assert< V, T >::type return_assert_t
constexpr auto find_in_if(ForwardIt begin, EndIt end, UnaryPredicate pred) noexcept(noexcept(kblib::invoke(pred, *begin))) -> size_t
Find the offset of the first element for which p returns true. It also allows for a sentinel end iter...
constexpr auto to_unsigned(I x) -> std::make_unsigned_t< I >
Cast integral argument to corresponding unsigned type.
constexpr auto repeat(std::size_t N, Callable func) noexcept(noexcept(func())) -> return_assert_t< is_invocable< Callable >::value, void >
Invoke a function N times.
constexpr auto transform(InputIt first, EndIt last, OutputIt d_first, UnaryOperation unary_op) -> OutputIt
transform applies the given function to a range and stores the result in another range,...
Provides macros and basic templates used by the rest of kblib.
#define KBLIB_NODISCARD
This internal macro is used to provide a fallback for [[nodiscard]] in C++14.
Contains some type traits not in the standard library that are useful in the implementation of kblib.