Skip to content

Commit

Permalink
buffered_range for stdin_view
Browse files Browse the repository at this point in the history
  • Loading branch information
eliaskosunen committed Nov 27, 2023
1 parent 5f316d3 commit 4eb6f84
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 8 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/arch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
- arch: armv6
distro: bullseye

exclude:
#exclude:
# FIXME: these runs take too long, and time out
#- arch: aarch64
#- arch: ppc64le
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ jobs:
#- cxx: clang++-7
#- cxx: clang++-6.0
# FIXME: Locally unreproducible ICE
#- cxx: clang++-9
- cxx: clang++-9
# FIXME: some weird linker issue: undefined reference to range_default_scanner default constructor
#- cxx: g++-11
# std: 20
Expand Down
19 changes: 17 additions & 2 deletions include/scn/detail/stdin_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ namespace scn {

stdin_view make_view();

std::ptrdiff_t end_index() const
{
return m_end_index;
}

std::string_view in_avail(stdin_iterator first) const;

private:
stdin_manager() = default;

Expand All @@ -68,9 +75,9 @@ namespace scn {

std::mutex m_mutex;
std::string m_putback_buffer{};
std::atomic<std::ptrdiff_t> m_end_index{-1};
std::atomic<bool> m_require_locking{true};
std::ptrdiff_t m_end_index{-1}, m_furthest_read_index{-1};
bool m_never_read{true};
std::atomic<bool> m_require_locking{true};
};

inline auto& stdin_manager_instance()
Expand Down Expand Up @@ -151,6 +158,11 @@ namespace scn {
return !(a == b);
}

std::ptrdiff_t index() const
{
return m_current_index;
}

private:
friend class stdin_manager;
friend class stdin_view;
Expand Down Expand Up @@ -179,6 +191,9 @@ namespace scn {
m_parent->m_putback_buffer.push_back(*m_current_cached);
}
m_parent->m_never_read = false;
if (m_parent->m_furthest_read_index < m_current_index) {
m_parent->m_furthest_read_index = m_current_index;
}
}

void increment_current()
Expand Down
100 changes: 98 additions & 2 deletions src/scn/impl/util/buffered_range.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#pragma once

#include <scn/detail/ranges.h>
#include <scn/detail/stdin_view.h>
#include <scn/util/span.h>

#include <algorithm>
Expand All @@ -30,7 +31,7 @@ namespace scn {
SCN_BEGIN_NAMESPACE

namespace impl {
struct buffered_range_segment_impl_base {
struct buffered_range_segment_impl_base : public ranges::view_base {
public:
using range_difference_t = std::ptrdiff_t;

Expand Down Expand Up @@ -65,6 +66,8 @@ namespace scn {
class buffered_range_segment_null_impl
: public buffered_range_segment_impl_base {
public:
buffered_range_segment_null_impl() = default;

template <typename... A>
explicit buffered_range_segment_null_impl(A&...)
{
Expand Down Expand Up @@ -101,6 +104,8 @@ namespace scn {
using char_type = detail::char_t<range_type>;
using range_iterator_t = ranges::iterator_t<range_type>;

buffered_range_segment_string_impl() = default;

buffered_range_segment_string_impl(range_type& range,
range_iterator_t& first)
: m_range(&range), m_first(&first)
Expand All @@ -109,20 +114,35 @@ namespace scn {

~buffered_range_segment_string_impl()
{
ranges::advance(*m_first, m_read);
if (m_first) {
ranges::advance(*m_first, m_read);
}
}

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

buffered_range_segment_string_impl(
buffered_range_segment_string_impl&&) = default;
buffered_range_segment_string_impl& operator=(
buffered_range_segment_string_impl&&) = default;

auto begin() const
{
SCN_EXPECT(m_first);
return *m_first;
}
auto end() const
{
SCN_EXPECT(m_range);
return m_range->end();
}

void advance_iterator()
{
SCN_EXPECT(m_first);
ranges::advance(*m_first, m_read);
m_read = 0;
}
Expand All @@ -135,6 +155,7 @@ namespace scn {
std::numeric_limits<range_difference_t>::max())
{
// no-op
SCN_EXPECT(m_range && m_range);
SCN_UNUSED(n);
}

Expand All @@ -143,6 +164,77 @@ namespace scn {
range_iterator_t* m_first{};
};

template <typename Range>
class buffered_range_segment_stdin_impl
: public buffered_range_segment_impl_base {
public:
using range_type = Range;
using char_type = char;
using range_iterator_t = ranges::iterator_t<range_type>;

buffered_range_segment_stdin_impl() = default;

buffered_range_segment_stdin_impl(range_type& range,
range_iterator_t& first)
: m_range(&range), m_first(&first)
{
}

~buffered_range_segment_stdin_impl()
{
if (m_first) {
ranges::advance(*m_first, m_read);
}
}

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

buffered_range_segment_stdin_impl(
buffered_range_segment_stdin_impl&&) = default;
buffered_range_segment_stdin_impl& operator=(
buffered_range_segment_stdin_impl&&) = default;

auto begin() const
{
SCN_EXPECT(m_first);
return m_avail_buf.begin();
}
auto end() const
{
SCN_EXPECT(m_first);
return m_avail_buf.end();
}

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

SCN_NODISCARD range_difference_t potential_size() const
{
SCN_EXPECT(m_first);
return m_first->manager()->in_avail(*m_first).size();
}
void acquire(range_difference_t n =
std::numeric_limits<range_difference_t>::max())
{
SCN_EXPECT(m_range && m_first);
m_avail_buf =
m_first->manager()->in_avail(*m_first).substr(0, n);
}

protected:
range_type* m_range{nullptr};
range_iterator_t* m_first{};
std::string_view m_avail_buf{};
};

template <typename Range, typename Iterator>
struct buffered_range_segment_impl {
using type =
Expand All @@ -161,6 +253,10 @@ namespace scn {
struct buffered_range_segment_impl<Range, const CharT*> {
using type = buffered_range_segment_string_impl<Range>;
};
template <typename Range>
struct buffered_range_segment_impl<Range, detail::stdin_iterator> {
using type = buffered_range_segment_stdin_impl<Range>;
};

template <typename Range>
class buffered_range_segment
Expand Down
12 changes: 10 additions & 2 deletions src/scn/stdin_view.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@ namespace scn {
if (m_end_index > 0) {
m_end_index -= begin.m_current_index;
}
if (m_furthest_read_index > 0) {
m_furthest_read_index -= begin.m_current_index;
}
begin.m_current_index = 0;
SCN_ENSURE(m_end_index >= begin.m_current_index ||
m_end_index == -1);
}

auto stdin_manager::extract_char() const -> std::optional<char>
Expand All @@ -47,6 +48,13 @@ namespace scn {
}
return static_cast<char>(ch);
}

std::string_view stdin_manager::in_avail(stdin_iterator first) const
{
SCN_EXPECT(!first.is_at_end());
return std::string_view{m_putback_buffer}.substr(
first.m_current_index);
}
} // namespace detail

SCN_END_NAMESPACE
Expand Down

0 comments on commit 4eb6f84

Please sign in to comment.