Skip to content

Commit

Permalink
Use buffered_range in read_until_code_unit
Browse files Browse the repository at this point in the history
  • Loading branch information
eliaskosunen committed Nov 7, 2023
1 parent 320c7f0 commit 5e6f60f
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 27 deletions.
2 changes: 1 addition & 1 deletion include/scn/detail/caching_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ namespace scn {
return m_range;
}

span<const char> buffer() const
span<const char_type> buffer() const
{
return this->m_buffer;
}
Expand Down
28 changes: 10 additions & 18 deletions include/scn/detail/format_string_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -291,25 +291,17 @@ namespace scn {
SCN_EXPECT(begin != end);
SCN_EXPECT(*begin >= '0' && *begin <= '9');

unsigned value = 0, prev = 0;
auto p = begin;
unsigned long long value = 0;
do {
prev = value;
value = value * 10 + static_cast<unsigned>(*p - '0');
++p;
} while (p != end && *p >= '0' && *p <= '9');
auto num_digits = p - begin;
begin = p;
if (SCN_LIKELY(num_digits <= std::numeric_limits<int>::digits10)) {
SCN_LIKELY_ATTR
return static_cast<int>(value);
}
const auto max =
static_cast<unsigned>((std::numeric_limits<int>::max)());
return num_digits == std::numeric_limits<int>::digits10 + 1 &&
prev * 10ull + unsigned(p[-1] - '0') <= max
? static_cast<int>(value)
: -1;
value *= 10;
value += static_cast<unsigned long long>(*begin - '0');
if (value > static_cast<unsigned long long>(
std::numeric_limits<int>::max())) {
return -1;
}
++begin;
} while (begin != end && *begin >= '0' && *begin <= '9');
return static_cast<int>(value);
}

template <typename CharT, typename IDHandler>
Expand Down
29 changes: 26 additions & 3 deletions src/scn/impl/algorithms/read.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,14 +131,37 @@ namespace scn {
simple_borrowed_iterator_t<Range> read_until_code_unit(Range&& range,
Predicate pred)
{
return ranges::find_if(range, pred);
if constexpr (ranges::contiguous_range<Range>) {
return ranges::find_if(range, pred);
}
else {
auto it = ranges::begin(range);
auto buf = buffered_range_segment{range, it};
if (buf.potential_size() == 0) {
return ranges::find_if(range, pred);
}

buf.acquire();
if (auto buf_it = ranges::find_if(buf, pred);
buf_it != buf.end()) {
buf.set_amount_read(ranges::distance(buf.begin(), buf_it));
buf.advance_iterator();
return it;
}
else {
buf.set_amount_read(buf.size());
buf.advance_iterator();
}

return ranges::find_if(ranges::subrange{it, range.end()}, pred);
}
}

template <typename Range, typename Predicate>
simple_borrowed_iterator_t<Range> read_while_code_unit(Range&& range,
Predicate pred)
{
return ranges::find_if_not(range, pred);
return read_until_code_unit(SCN_FWD(range), std::not_fn(pred));
}

template <typename Range, typename Predicate>
Expand Down Expand Up @@ -502,7 +525,7 @@ namespace scn {
return pred(cp) || ctype_facet.is(mask, ch);
});
}
#endif // !SCN_DISABLE_LOCALE
#endif // !SCN_DISABLE_LOCALE

template <typename Range, typename Iterator>
simple_borrowed_iterator_t<Range> apply_opt(
Expand Down
81 changes: 76 additions & 5 deletions src/scn/impl/util/buffered_range.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

#include <algorithm>
#include <limits>
#include <utility>

// experimental

Expand All @@ -38,12 +39,14 @@ namespace scn {

buffered_range_segment_impl_base(
const buffered_range_segment_impl_base&) = delete;
buffered_range_segment_impl_base(
buffered_range_segment_impl_base&&) = delete;
buffered_range_segment_impl_base& operator=(
const buffered_range_segment_impl_base&) = delete;

buffered_range_segment_impl_base(
buffered_range_segment_impl_base&&) = default;
buffered_range_segment_impl_base& operator=(
buffered_range_segment_impl_base&&) = delete;
buffered_range_segment_impl_base&&) = default;

~buffered_range_segment_impl_base() = default;

void set_amount_read(range_difference_t n)
Expand All @@ -59,6 +62,38 @@ namespace scn {
range_difference_t m_read{0};
};

template <typename CharT>
class buffered_range_segment_null_impl
: public buffered_range_segment_impl_base {
public:
template <typename... A>
explicit buffered_range_segment_null_impl(A&...)
{
}

const CharT* begin() const
{
return nullptr;
}
const CharT* end() const
{
return nullptr;
}

void advance_iterator() {}

SCN_NODISCARD range_difference_t potential_size() const
{
return 0;
}
void acquire(range_difference_t n =
std::numeric_limits<range_difference_t>::max())
{
// no-op
SCN_UNUSED(n);
}
};

template <typename Range>
class buffered_range_segment_string_impl
: public buffered_range_segment_impl_base {
Expand Down Expand Up @@ -87,6 +122,12 @@ namespace scn {
return m_range->end();
}

void advance_iterator()
{
ranges::advance(*m_first, m_read);
m_read = 0;
}

SCN_NODISCARD range_difference_t potential_size() const
{
return ranges::distance(begin(), end());
Expand Down Expand Up @@ -120,6 +161,28 @@ namespace scn {
{
}

buffered_range_segment_iostream_impl(
buffered_range_segment_iostream_impl&& other)
: m_range(other.m_range),
m_first(other.m_first),
m_streambuf_view(other.m_streambuf_view),
m_buffer_memory(),
m_buffer()
{
}

buffered_range_segment_iostream_impl& operator=(
buffered_range_segment_iostream_impl&& other)
{
m_range = std::exchange(other.m_range, nullptr);
m_first = std::exchange(other.m_first, nullptr);
m_streambuf_view =
std::exchange(other.m_streambuf_view, nullptr);
m_buffer_memory = {};
m_buffer = {};
return *this;
}

~buffered_range_segment_iostream_impl()
{
ranges::advance(*m_first, m_read);
Expand All @@ -134,6 +197,13 @@ namespace scn {
return m_buffer.end();
}

void advance_iterator()
{
ranges::advance(*m_first, m_read);
m_buffer = m_buffer.subspan(m_read);
m_read = 0;
}

SCN_NODISCARD range_difference_t potential_size() const
{
auto* sb = m_streambuf_view->rdbuf();
Expand All @@ -158,7 +228,7 @@ namespace scn {
if (sb_count != first_idx) {
m_buffer = m_first->view().buffer().subspan(first_idx);
auto n_to_read = std::min(ranges::ssize(m_buffer), n);
m_buffer = m_buffer.first(n);
m_buffer = m_buffer.first(n_to_read);
return;
}

Expand All @@ -182,7 +252,8 @@ namespace scn {

template <typename Range, typename Iterator>
struct buffered_range_segment_impl {
using type = void;
using type =
buffered_range_segment_null_impl<detail::char_t<Range>>;
};

template <typename Range>
Expand Down

0 comments on commit 5e6f60f

Please sign in to comment.