From 32225717e44c3a43aa5407ec6ce1b3d57a7b02c0 Mon Sep 17 00:00:00 2001 From: namark <namark@disroot.org> Date: Mon, 19 Jul 2021 19:43:18 +0400 Subject: [PATCH] index_range for what it's worth --- source/simple/support/misc.hpp | 54 ++++++++++++++++++++++++++++++++++ unit_tests/misc.cpp | 36 +++++++++++++++++++++++ 2 files changed, 90 insertions(+) diff --git a/source/simple/support/misc.hpp b/source/simple/support/misc.hpp index 85d6cfe..1ac05d9 100644 --- a/source/simple/support/misc.hpp +++ b/source/simple/support/misc.hpp @@ -9,6 +9,7 @@ #include <cinttypes> #include "range.hpp" +#include "algorithm/utils.hpp" namespace simple::support { @@ -129,11 +130,64 @@ namespace simple::support } template <typename It> + [[deprecated("use simple::support::string_view from simple/support/algorithm/range_wrappers.hpp")]] std::string_view make_string_view(It begin, It end) { return {begin, static_cast<std::string_view::size_type>(end - begin)}; } + // NOTE: maybe put in algorithm range wrappers instead? + template <typename Container, + typename = std::enable_if_t<is_range_v<Container>>> + class index_range + { + public: + + using container_type = Container; + using size_type = typename container_type::size_type; + explicit index_range + ( + Container & container, + range<size_type> index = range<size_type>::limit() + ) : + container(&container), + index(index) + {} + + explicit index_range + ( + Container & container, + range<typename Container::const_iterator> iterator_range + ) : + container(&container), + index(iterator_range - container.begin()) + {} + + auto begin() const + { return iter_at(index.lower()); } + auto end() const + { return iter_at(index.upper()); } + + private: + Container* container; + range<size_type> index; + + auto iter_at(size_type index) const + { + using std::begin; + using std::end; + using std::clamp; + + auto begin_ = begin(*container); + auto end_ = end(*container); + + // TODO: use container.size() if available + return begin_ + clamp(index, size_type{}, + static_cast<size_type>(end_ - begin_)); // good cast, since container can not have negative size + } + + }; + } // namespace simple::support #endif /* end of include guard */ diff --git a/unit_tests/misc.cpp b/unit_tests/misc.cpp index 429cac9..e295460 100644 --- a/unit_tests/misc.cpp +++ b/unit_tests/misc.cpp @@ -101,11 +101,47 @@ void SimplifiedToNumber() to_<unsigned char>(std::to_string(std::numeric_limits<unsigned char>::max()) + '0')); } +void RangeReference() +{ + using std::begin; + using std::end; + + const std::string prefix = "Permaprefix"; + + std::string stuff{prefix}; + + range temporef{begin(stuff), end(stuff)}; + + assert( std::equal(begin(temporef), end(temporef), + begin(prefix), end(prefix)) ); + + index_range permaref(stuff, {begin(stuff), end(stuff)}); + + assert( std::equal(begin(permaref), end(permaref), + begin(prefix), end(prefix)) ); + + stuff += " now this a really really long long paragraph of text, that should by all means cause reallocation and stuff, so the iterators in temporef range will be invalidated, while permaref that uses indices will remain valid and usable... though it doesn't really matter if it actually relocates since there is no way to check any of this, you'll just have to believe me and trust me and never ever let me go..."; + + // can't do this anymore + // assert( std::equal(begin(temporef), end(temporef), + // begin(prefix), end(prefix)) ); + // asan might not catch this, because of small string optimization, and since you are allowed to reinterpret anything as char* it might not even be UB dependent on the implementation, but then the assertion will fail at least + // otherwise the assertion might not fail, if the old/freed memory happens to remain untouched by either the system or the allocator + // so asan and assert together can kind of catch this I guess + // TODO: __gnu_debug::string (but not std::string under _GLIBCXX_DEBUG, it's an obscure exception) does catch this reliably, so that's a thing to consider for unit testing purposes in general + + // all ok here + assert( std::equal(begin(permaref), end(permaref), + begin(prefix), end(prefix)) ); + +} + int main() { StringToNumber(); StringToNumericRange(); NumericRangeToString(); SimplifiedToNumber(); + RangeReference(); return 0; } -- GitLab