Created
November 10, 2023 14:09
-
-
Save lennyerik/2b3aaf83e5a0176a5eb9235d089c4f97 to your computer and use it in GitHub Desktop.
A generic string splitting iterator in C++20
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <iterator> | |
#include <cstring> | |
template<typename T> | |
concept HasLengthMethod = requires(T t) { | |
{ t.length() } -> std::same_as<std::size_t>; | |
}; | |
template<typename T> | |
concept CanBePassedToStrlen = requires(T t) { | |
{ strlen(t) } -> std::same_as<std::size_t>; | |
}; | |
template<typename S> | |
requires (HasLengthMethod<S> || CanBePassedToStrlen<S> || std::same_as<S, char>) | |
std::size_t generic_strlen(S s) { | |
if constexpr (HasLengthMethod<S>) { | |
return s.length(); | |
} else if constexpr (CanBePassedToStrlen<S>) { | |
return strlen(s); | |
} else { | |
return 1; | |
} | |
} | |
template<typename D> | |
requires requires(D d) { | |
std::string_view("").find(d); | |
generic_strlen(d); | |
} | |
class Split { | |
public: | |
using iterator_category = std::forward_iterator_tag; | |
using difference_type = std::ptrdiff_t; | |
using value_type = std::string_view; | |
using pointer = std::string_view; | |
using reference = std::string_view; | |
Split(std::string_view input, D delimiter) : input(input), delimiter(delimiter) {} | |
reference operator*() const { | |
return this->input.substr(0, this->input.find(this->delimiter)); | |
} | |
pointer operator->() const { | |
return this->input.substr(0, this->input.find(this->delimiter)); | |
} | |
Split& operator++() { | |
const std::size_t pos = this->input.find(this->delimiter); | |
const std::size_t delimiter_len = generic_strlen(this->delimiter); | |
this->input = this->input.substr( | |
pos == std::string_view::npos ? this->input.length() : pos + delimiter_len | |
); | |
return *this; | |
} | |
friend bool operator==(const Split& a, const Split& b) { | |
return a.input.length() == b.input.length(); | |
} | |
friend bool operator!=(const Split& a, const Split& b) { | |
return a.input.length() != b.input.length(); | |
} | |
Split begin() { | |
return *this; | |
} | |
Split end() { | |
return Split("", this->delimiter); | |
} | |
private: | |
std::string_view input; | |
D delimiter; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment