#include "./filtered_string_view.h" namespace fsv { // Iterator implementation. auto filtered_string_view::begin() const noexcept -> iterator { // Our iterator might have to be incremented so that it's pointing to // the first valid. auto it = iterator{this->string, this->length, this->pred, this->string}; if (not std::invoke(this->pred, *it)) { ++it; } return it; } auto filtered_string_view::end() const noexcept -> iterator { return iterator{this->string, this->length, this->pred, this->string + this->length}; } auto filtered_string_view::cbegin() const noexcept -> const_iterator { return std::begin(*this); } auto filtered_string_view::cend() const noexcept -> const_iterator { return std::end(*this); } auto filtered_string_view::rbegin() const noexcept -> reverse_iterator { return std::reverse_iterator(std::end(*this)); } auto filtered_string_view::rend() const noexcept -> reverse_iterator { return std::reverse_iterator(std::begin(*this)); } auto filtered_string_view::crbegin() const noexcept -> const_reverse_iterator { return std::rbegin(*this); } auto filtered_string_view::crend() const noexcept -> const_reverse_iterator { return std::rend(*this); } filtered_string_view::iterator::iterator(const value_type* const& str, const std::size_t& len, const filter& pred, const value_type* const& i) noexcept : string(str) , length(&len) , predicate(&pred) , it(i) {} auto filtered_string_view::iterator::operator*() const noexcept -> reference { return *this->it; } auto filtered_string_view::iterator::operator->() const noexcept -> reference { return this->operator*(); } auto filtered_string_view::iterator::operator++() noexcept -> iterator& { do { ++this->it; if (not std::invoke(*this->predicate, *this->it)) { continue; } break; } while (this->it != this->string + *this->length); return *this; } auto filtered_string_view::iterator::operator++(int) noexcept -> iterator { iterator ret = *this; ++(*this); return ret; } auto filtered_string_view::iterator::operator--() noexcept -> iterator& { do { --this->it; if (not std::invoke(*this->predicate, *this->it)) { continue; } break; } while (this->it != this->string); return *this; } auto filtered_string_view::iterator::operator--(int) noexcept -> iterator { iterator ret = *this; --(*this); return ret; } auto operator==(const filtered_string_view::iterator& a, const filtered_string_view::iterator& b) noexcept -> bool { return a.it == b.it; } auto operator!=(const filtered_string_view::iterator& a, const filtered_string_view::iterator& b) noexcept -> bool { return not(a == b); } // Class methods implementation. filtered_string_view::filtered_string_view() noexcept : string(nullptr) , length(0) , pred(default_predicate) {} filtered_string_view::filtered_string_view(const std::string& str) noexcept : string(std::data(str)) , length(std::size(str)) , pred(default_predicate) {} filtered_string_view::filtered_string_view(const std::string& str, filter pred) noexcept : string(std::data(str)) , length(std::size(str)) , pred(pred) {} filtered_string_view::filtered_string_view(const char* str) noexcept : string(str) , length(std::strlen(str)) , pred(default_predicate) {} filtered_string_view::filtered_string_view(const char* str, filter pred) noexcept : string(str) , length(std::strlen(str)) , pred(pred) {} filtered_string_view::filtered_string_view(const filtered_string_view& other) noexcept : string(other.string) , length(other.length) , pred(other.pred) {} filtered_string_view::filtered_string_view(filtered_string_view&& other) noexcept : string(std::exchange(other.string, nullptr)) , length(std::exchange(other.length, 0)) , pred(std::exchange(other.pred, default_predicate)) {} auto filtered_string_view::operator=(const filtered_string_view& other) noexcept -> filtered_string_view& { if (&other != this) { // self-copied object should remain unchanged. this->string = other.string; this->length = other.length; this->pred = other.pred; } return *this; } auto filtered_string_view::operator=(filtered_string_view&& other) noexcept -> filtered_string_view& { if (&other != this) { // self-copied object should remain unchanged. this->string = std::exchange(other.string, nullptr); this->length = std::exchange(other.length, 0); this->pred = std::exchange(other.pred, default_predicate); } return *this; } auto filtered_string_view::operator[](const std::size_t& n) const noexcept -> const char& { return *std::next(std::begin(*this), n); } auto filtered_string_view::operator[](const int& n) const noexcept -> const char& { return (*this)[static_cast(n)]; } filtered_string_view::operator std::string() const { auto result = std::string{}; std::copy(std::begin(*this), std::end(*this), std::back_inserter(result)); return result; } auto filtered_string_view::at(const int index) const -> const char& { const auto throw_index = [&]() { throw std::domain_error("filtered_string_view::at(" + std::to_string(index) + "): invalid index"); }; if (index < 0) { throw_index(); } auto it = std::begin(*this); for (auto i = 0; i < index; ++i) { ++it; if (it == std::end(*this)) { throw_index(); } } return *it; } auto filtered_string_view::size() const noexcept -> std::size_t { return std::distance(std::begin(*this), std::end(*this)); } auto filtered_string_view::empty() const noexcept -> bool { return std::size(*this) == 0; } auto filtered_string_view::data() const noexcept -> const char* { return this->string; } auto filtered_string_view::predicate() const noexcept -> const filter& { return this->pred; } auto operator==(const filtered_string_view& a, const filtered_string_view& b) -> bool { return std::string{a} == std::string{b}; } auto operator<=>(const filtered_string_view& a, const filtered_string_view& b) -> std::strong_ordering { return std::string{a} <=> std::string{b}; } auto operator<<(std::ostream& os, const filtered_string_view& fsv) -> std::ostream& { os << std::string{fsv}; return os; } auto filtered_string_view::default_predicate(const char&) noexcept -> bool { return true; } auto compose(const filtered_string_view& fsv, const std::vector& filts) -> filtered_string_view { return filtered_string_view{std::data(fsv), [&](const auto& c) { return std::all_of(std::begin(filts), std::end(filts), [&](const auto& func) { return std::invoke(func, c); }); }}; } auto split(const filtered_string_view& fsv, const filtered_string_view& tok) -> std::vector { std::vector result{}; const auto origin = std::string{fsv}; const auto target = std::string{tok}; const auto skip = std::size(target); for (auto a = 0ul, b = origin.find(target, a); a != std::string::npos; a = b + skip, b = origin.find(target, a)) { if (b == std::string::npos) { result.push_back(fsv::substr(fsv, static_cast(a))); break; } if (a == b) { result.push_back(""); continue; } result.push_back(fsv::substr(fsv, static_cast(a), static_cast(b - a))); } return result; } auto substr(const filtered_string_view& fsv, const int pos, const int count) -> filtered_string_view { const auto predicate = fsv.predicate(); const auto rcount = count <= 0 ? static_cast(std::size(fsv)) - pos : count; if (rcount == 0 or std::begin(fsv) == std::end(fsv)) { return filtered_string_view{}; } const auto start = std::next(std::begin(fsv), static_cast(pos)); if (start == std::end(fsv)) { return filtered_string_view{}; } const auto end = std::next(start, static_cast(rcount - 1)); return filtered_string_view{std::data(fsv), [=](const auto& c) { if (not std::invoke(predicate, c)) { return false; } return &c >= &*start and &c <= &*end; }}; } // namespace fsv } // namespace fsv