Skip to content

Commit

Permalink
Make stdin_view truly private
Browse files Browse the repository at this point in the history
  • Loading branch information
eliaskosunen committed Nov 27, 2023
1 parent 4eb6f84 commit 17a7c8b
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 61 deletions.
113 changes: 79 additions & 34 deletions include/scn/detail/result.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,33 @@ namespace scn {
SCN_BEGIN_NAMESPACE

namespace detail {
template <typename Range, bool Dangling = false>
struct dangling_iterator {
using type = ranges::iterator_t<Range>;
};
template <typename Range>
struct dangling_iterator<Range, true> {
using type = ranges::dangling;
};
template <typename Range, bool Dangling, bool StdinMarker>
constexpr auto dangling_iterator()
{
if constexpr (StdinMarker) {
return type_identity<stdin_range_marker>{};
}
else if constexpr (Dangling) {
return type_identity<ranges::dangling>{};
}
else {
return type_identity<ranges::iterator_t<Range>>{};
}
}

template <typename Range, bool Dangling = false>
struct dangling_sentinel {
using type = ranges::sentinel_t<Range>;
};
template <typename Range>
struct dangling_sentinel<Range, true> {
using type = ranges::dangling;
};
template <typename Range, bool Dangling, bool StdinMarker>
constexpr auto dangling_sentinel()
{
if constexpr (StdinMarker) {
return type_identity<stdin_range_marker>{};
}
else if constexpr (Dangling) {
return type_identity<ranges::dangling>{};
}
else {
return type_identity<ranges::sentinel_t<Range>>{};
}
}
} // namespace detail

/**
Expand All @@ -65,12 +75,21 @@ namespace scn {
class scan_result {
static constexpr bool is_dangling =
std::is_same_v<detail::remove_cvref_t<Range>, ranges::dangling>;
static_assert(ranges::borrowed_range<Range> || is_dangling);
static constexpr bool is_stdin_marker =
std::is_same_v<detail::remove_cvref_t<Range>, stdin_range_marker>;
static_assert(ranges::borrowed_range<Range> || is_dangling ||
is_stdin_marker);

public:
using range_type = Range;
using iterator = detail::dangling_iterator<Range, is_dangling>;
using sentinel = detail::dangling_sentinel<Range, is_dangling>;
using iterator = typename decltype(detail::dangling_iterator<
Range,
is_dangling,
is_stdin_marker>())::type;
using sentinel = typename decltype(detail::dangling_sentinel<
Range,
is_dangling,
is_stdin_marker>())::type;
using tuple_type = std::tuple<Args...>;

constexpr scan_result() = default;
Expand All @@ -89,26 +108,46 @@ namespace scn {

/// Converting constructor from a range and a tuple
template <typename OtherR,
typename = std::enable_if_t<
std::is_constructible_v<range_type, OtherR>>>
std::enable_if_t<
std::is_constructible_v<range_type, OtherR>>* = nullptr>
scan_result(OtherR&& r, std::tuple<Args...>&& values)
: m_range(SCN_FWD(r)), m_values(SCN_MOVE(values))
{
}

template <typename OtherR,
typename = std::enable_if_t<
std::is_constructible_v<range_type, OtherR>>>
template <
typename OtherR,
std::enable_if_t<
std::is_constructible_v<range_type, OtherR> &&
std::is_convertible_v<const OtherR&, range_type>>* = nullptr>
/*implicit*/ scan_result(const scan_result<OtherR, Args...>& o)
: m_range(o.range()), m_values(o.values())
{
}
template <
typename OtherR,
std::enable_if_t<
std::is_constructible_v<range_type, OtherR> &&
!std::is_convertible_v<const OtherR&, range_type>>* = nullptr>
explicit scan_result(const scan_result<OtherR, Args...>& o)
: m_range(o.m_range), m_values(o.m_values)
: m_range(o.range()), m_values(o.values())
{
}

template <typename OtherR,
typename = std::enable_if_t<
std::is_constructible_v<range_type, OtherR>>>
std::enable_if_t<
std::is_constructible_v<range_type, OtherR> &&
std::is_convertible_v<OtherR&&, range_type>>* = nullptr>
/*implicit*/ scan_result(scan_result<OtherR, Args...>&& o)
: m_range(o.range()), m_values(SCN_MOVE(o.values()))
{
}
template <typename OtherR,
std::enable_if_t<
std::is_constructible_v<range_type, OtherR> &&
!std::is_convertible_v<OtherR&&, range_type>>* = nullptr>
explicit scan_result(scan_result<OtherR, Args...>&& o)
: m_range(SCN_MOVE(o.m_range)), m_values(SCN_MOVE(o.m_values))
: m_range(o.range()), m_values(SCN_MOVE(o.values()))
{
}

Expand All @@ -117,8 +156,8 @@ namespace scn {
std::is_constructible_v<range_type, OtherR>>>
scan_result& operator=(const scan_result<OtherR, Args...>& o)
{
m_range = o.m_range;
m_values = o.m_values;
m_range = o.range();
m_values = o.values();
return *this;
}

Expand All @@ -127,8 +166,8 @@ namespace scn {
std::is_constructible_v<range_type, OtherR>>>
scan_result& operator=(scan_result<OtherR, Args...>&& o)
{
m_range = SCN_MOVE(o.m_range);
m_values = SCN_MOVE(o.m_values);
m_range = o.range();
m_values = SCN_MOVE(o.values());
return *this;
}

Expand All @@ -145,6 +184,9 @@ namespace scn {
if constexpr (is_dangling) {
return ranges::dangling{};
}
else if constexpr (is_stdin_marker) {
return stdin_range_marker{};
}
else {
return m_range.begin();
}
Expand All @@ -156,6 +198,9 @@ namespace scn {
if constexpr (is_dangling) {
return ranges::dangling{};
}
else if constexpr (is_stdin_marker) {
return stdin_range_marker{};
}
else {
return m_range.end();
}
Expand Down Expand Up @@ -212,8 +257,8 @@ namespace scn {
}

private:
range_type m_range{};
tuple_type m_values{};
SCN_NO_UNIQUE_ADDRESS range_type m_range{};
SCN_NO_UNIQUE_ADDRESS tuple_type m_values{};
};

template <typename R, typename... Args>
Expand Down
12 changes: 6 additions & 6 deletions include/scn/detail/scan.h
Original file line number Diff line number Diff line change
Expand Up @@ -288,14 +288,14 @@ namespace scn {
*/
template <typename... Args>
SCN_NODISCARD auto input(format_string<Args...> format)
-> scan_result_type<detail::stdin_subrange, Args...>
-> scan_result_type<stdin_range_marker, Args...>
{
auto args = make_scan_args<detail::stdin_subrange, Args...>();
auto ret = vinput(format, args);
if (SCN_UNLIKELY(!ret)) {
return unexpected(ret.error());
auto err = vinput(format, args);
if (SCN_UNLIKELY(!err)) {
return unexpected(err);
}
return scan_result{*ret, SCN_MOVE(args.args())};
return scan_result{stdin_range_marker{}, SCN_MOVE(args.args())};
}

/**
Expand All @@ -305,7 +305,7 @@ namespace scn {
*/
template <typename... Args>
SCN_NODISCARD auto prompt(const char* msg, format_string<Args...> format)
-> scan_result_type<detail::stdin_subrange, Args...>
-> scan_result_type<stdin_range_marker, Args...>
{
std::printf("%s", msg);
return input<Args...>(format);
Expand Down
6 changes: 6 additions & 0 deletions include/scn/detail/stdin_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,9 @@ namespace std::ranges {
template <>
inline constexpr bool enable_borrowed_range<scn::detail::stdin_subrange> =
true;

template <>
inline constexpr bool enable_borrowed_range<scn::stdin_range_marker> = true;
} // namespace std::ranges

#else
Expand All @@ -375,6 +378,9 @@ inline constexpr bool enable_view<scn::detail::stdin_subrange> = true;
template <>
inline constexpr bool enable_borrowed_range<scn::detail::stdin_subrange> = true;

template <>
inline constexpr bool enable_borrowed_range<scn::stdin_range_marker> = true;

NANO_END_NAMESPACE

#endif
12 changes: 5 additions & 7 deletions include/scn/detail/vscan.h
Original file line number Diff line number Diff line change
Expand Up @@ -260,17 +260,15 @@ namespace scn {
return detail::vscan_value_generic(SCN_FWD(range), arg);
}

auto vinput(std::string_view format,
scan_args_for<detail::stdin_subrange, char> args)
-> vscan_result<detail::stdin_subrange>;
scan_error vinput(std::string_view format,
scan_args_for<detail::stdin_subrange, char> args);

#if !SCN_DISABLE_LOCALE
template <typename Locale,
typename = std::void_t<decltype(Locale::classic())>>
auto vinput(const Locale& loc,
std::string_view format,
scan_args_for<detail::stdin_subrange, char> args)
-> vscan_result<detail::stdin_subrange>;
scan_error vinput(const Locale& loc,
std::string_view format,
scan_args_for<detail::stdin_subrange, char> args);
#endif

namespace detail {
Expand Down
25 changes: 11 additions & 14 deletions src/scn/vscan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -402,43 +402,40 @@ namespace scn {
}
} // namespace detail

auto vinput(std::string_view format,
scan_args_for<detail::stdin_subrange, char> args)
-> vscan_result<detail::stdin_subrange>
scan_error vinput(std::string_view format,
scan_args_for<detail::stdin_subrange, char> args)
{
auto source = detail::stdin_manager_instance().make_view();
source.lock();
auto it = vscan_internal(detail::stdin_subrange{source}, format, args);
if (SCN_UNLIKELY(!it)) {
return unexpected(it.error());
return it.error();
}
source.manager().sync_now(*it);
return ranges::subrange{source.begin(), source.end()};
return {};
}

#if !SCN_DISABLE_LOCALE
template <typename Locale, typename>
auto vinput(const Locale& loc,
std::string_view format,
scan_args_for<detail::stdin_subrange, char> args)
-> vscan_result<detail::stdin_subrange>
scan_error vinput(const Locale& loc,
std::string_view format,
scan_args_for<detail::stdin_subrange, char> args)
{
auto source = detail::stdin_manager_instance().make_view();
source.lock();
auto it = vscan_internal(detail::stdin_subrange{source}, format, args,
detail::locale_ref{loc});
if (SCN_UNLIKELY(!it)) {
return unexpected(it.error());
return it.error();
}
source.manager().sync_now(*it);
return detail::stdin_subrange{source.begin(), source.end()};
return {};
}

template auto vinput<std::locale, void>(
template scan_error vinput<std::locale, void>(
const std::locale&,
std::string_view,
scan_args_for<detail::stdin_subrange, char>)
-> vscan_result<detail::stdin_subrange>;
scan_args_for<detail::stdin_subrange, char>);
#endif

namespace detail {
Expand Down

0 comments on commit 17a7c8b

Please sign in to comment.