Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion include/boost/url/grammar/impl/token_rule.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ parse(
BOOST_URL_RETURN_EC(
error::need_more);
}
it = (find_if_not)(it, end, cs_);
auto const& cs = this->get();
it = grammar::find_if_not(it, end, cs);
if(it != it0)
return core::string_view(it0, it - it0);
BOOST_URL_RETURN_EC(
Expand Down
60 changes: 57 additions & 3 deletions include/boost/url/grammar/token_rule.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#include <boost/url/grammar/charset.hpp>
#include <boost/url/error_types.hpp>
#include <boost/core/detail/string_view.hpp>
#include <boost/core/empty_value.hpp>
#include <type_traits>

namespace boost {
namespace urls {
Expand All @@ -22,6 +24,7 @@ namespace grammar {
namespace implementation_defined {
template<class CharSet>
struct token_rule_t
: private empty_value<CharSet>
{
using value_type = core::string_view;

Expand All @@ -39,12 +42,21 @@ struct token_rule_t
constexpr
token_rule_t(
CharSet const& cs) noexcept
: cs_(cs)
: empty_value<CharSet>(
empty_init, cs)
{
}

private:
CharSet const cs_;
template<class CS = CharSet>
constexpr
token_rule_t(
typename std::enable_if<
std::is_default_constructible<CS>::value,
int>::type = 0) noexcept
: empty_value<CharSet>(
empty_init)
{
}
};
}

Expand Down Expand Up @@ -86,6 +98,48 @@ token_rule(
return {cs};
}

/** Match a non-empty string of characters from a default-constructible set

This overload is only available when CharSet is
default constructible.

If there is no more input, the error code
@ref error::need_more is returned.

@par Value Type
@code
using value_type = core::string_view;
@endcode

@par Example
Rules are used with the function @ref parse.
@code
system::result< core::string_view > rv = parse( "abcdef", token_rule<alpha_chars_t>() );
@endcode

@par BNF
@code
token = 1*( ch )
@endcode

@tparam CharSet The character set type to use
@return The token rule

@see
@ref alpha_chars,
@ref parse.
*/
template<BOOST_URL_CONSTRAINT(CharSet) CharSet>
constexpr
auto
token_rule() noexcept ->
typename std::enable_if<
std::is_default_constructible<CharSet>::value,
implementation_defined::token_rule_t<CharSet>>::type
{
return implementation_defined::token_rule_t<CharSet>();
}

} // grammar
} // urls
} // boost
Expand Down
25 changes: 25 additions & 0 deletions test/unit/grammar/token_rule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,31 @@ struct token_rule_test
ok(r, "a", "a");
bad(r, "", error::need_more);
bad(r, "1", error::mismatch);

// Test default construction with stateless CharSet
{
constexpr auto r2 = token_rule<implementation_defined::alpha_chars_t>();
ok(r2, "abc", "abc");
ok(r2, "ABC", "ABC");
bad(r2, "", error::need_more);
bad(r2, "123", error::mismatch);
}

// Test EBO - token_rule_t with empty CharSet should be minimal size
{
// alpha_chars_t is empty (no data members)
static_assert(
sizeof(implementation_defined::token_rule_t<implementation_defined::alpha_chars_t>) == 1,
"EBO should reduce size to 1 byte for empty CharSet");
}

// Test that default-constructed rules work correctly at runtime
{
auto r3 = token_rule<implementation_defined::alpha_chars_t>();
auto rv = parse("abcdef", r3);
BOOST_TEST(rv.has_value());
BOOST_TEST_EQ(rv.value(), "abcdef");
}
}
};

Expand Down
Loading