Skip to content

Commit e29c8e7

Browse files
committed
Add contrib charconv rule.
1 parent 62cee99 commit e29c8e7

File tree

3 files changed

+138
-0
lines changed

3 files changed

+138
-0
lines changed
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright (c) 2025 Dr. Colin Hirsch and Daniel Frey
2+
// Distributed under the Boost Software License, Version 1.0.
3+
// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4+
5+
#ifndef TAO_PEGTL_CONTRIB_CHARCONV_HPP
6+
#define TAO_PEGTL_CONTRIB_CHARCONV_HPP
7+
8+
#include <charconv>
9+
#include <system_error>
10+
#include <type_traits>
11+
12+
#include "../apply_mode.hpp"
13+
#include "../config.hpp"
14+
#include "../eol_exclude_tag.hpp"
15+
#include "../rewind_mode.hpp"
16+
#include "../type_list.hpp"
17+
18+
#include "../debug/analyze_traits.hpp"
19+
20+
#include "../internal/enable_control.hpp"
21+
22+
namespace TAO_PEGTL_NAMESPACE
23+
{
24+
namespace internal
25+
{
26+
template< int Base >
27+
struct charconv
28+
{
29+
using rule_t = charconv;
30+
using subs_t = empty_list;
31+
32+
template< apply_mode A,
33+
rewind_mode M,
34+
template< typename... >
35+
class Action,
36+
template< typename... >
37+
class Control,
38+
typename ParseInput,
39+
typename Integral >
40+
[[nodiscard]] static bool match( ParseInput& in, Integral& out )
41+
{
42+
static_assert( std::is_integral_v< Integral > );
43+
44+
// TODO: Better limit for base other than 10.
45+
if( const std::size_t size = in.size( 3 + 3 * sizeof( Integral ) ); size > 0 ) {
46+
const auto result = std::from_chars( in.current(), in.current( size ), out, Base );
47+
switch( result.ec ) {
48+
case std::errc::invalid_argument:
49+
return false;
50+
case std::errc::result_out_of_range:
51+
return false; // throw?
52+
default:
53+
in.template consume< eol_exclude_tag >( result.ptr - in.current() );
54+
return true;
55+
}
56+
}
57+
return false;
58+
}
59+
};
60+
61+
template< int Base >
62+
inline constexpr bool enable_control< charconv< Base > > = false;
63+
64+
} // namespace internal
65+
66+
struct charconv
67+
: internal::charconv< 10 >
68+
{};
69+
70+
template< typename Name, int Base >
71+
struct analyze_traits< Name, internal::charconv< Base > >
72+
: analyze_any_traits<>
73+
{};
74+
75+
} // namespace TAO_PEGTL_NAMESPACE
76+
77+
#endif

src/test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ set(test_sources
3535
ascii_three.cpp
3636
ascii_two.cpp
3737
contrib_alphabet.cpp
38+
contrib_charconv.cpp
3839
contrib_check_count.cpp
3940
contrib_check_depth.cpp
4041
contrib_dispatch.cpp

src/test/contrib_charconv.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright (c) 2025 Dr. Colin Hirsch and Daniel Frey
2+
// Distributed under the Boost Software License, Version 1.0.
3+
// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4+
5+
#include "test.hpp"
6+
#include "verify_meta.hpp"
7+
8+
#include <tao/pegtl/contrib/charconv.hpp>
9+
10+
namespace TAO_PEGTL_NAMESPACE
11+
{
12+
template< typename Integral >
13+
void charconv_success( const std::string& input, const Integral output, const std::size_t remaining = 0 )
14+
{
15+
view_input in( input );
16+
static_assert( std::is_integral_v< Integral > );
17+
Integral state = output + 1;
18+
TAO_PEGTL_TEST_ASSERT( state == output + 1 );
19+
const bool result = parse< charconv >( in, state );
20+
TAO_PEGTL_TEST_ASSERT( result );
21+
TAO_PEGTL_TEST_ASSERT( state == output );
22+
TAO_PEGTL_TEST_ASSERT( in.size() == remaining );
23+
}
24+
25+
template< typename Integral >
26+
void charconv_failure( const std::string& input, const Integral value )
27+
{
28+
view_input in( input );
29+
static_assert( std::is_integral_v< Integral > );
30+
Integral state = value + 1;
31+
TAO_PEGTL_TEST_ASSERT( state == value + 1 );
32+
const bool result = parse< charconv >( in, state );
33+
TAO_PEGTL_TEST_ASSERT( !result );
34+
TAO_PEGTL_TEST_ASSERT( state == value + 1 );
35+
TAO_PEGTL_TEST_ASSERT( in.size() == input.size() );
36+
}
37+
38+
void unit_test()
39+
{
40+
verify_analyze< charconv >( __LINE__, __FILE__, true, false );
41+
42+
charconv_success( "0", int( 0 ) );
43+
charconv_success( "0", unsigned( 0 ) );
44+
45+
charconv_success( "0a", int( 0 ), 1 );
46+
charconv_success( "0b", unsigned( 0 ), 1 );
47+
48+
charconv_success( "0x0", int( 0 ), 2 );
49+
charconv_success( "0x0", unsigned( 0 ), 2 );
50+
51+
charconv_success( "-1", int( -1 ) );
52+
charconv_failure( "-1", unsigned( 42 ) );
53+
54+
charconv_failure( "999999999999", int( 0 ) );
55+
charconv_failure( "999999999999", unsigned( 0 ) );
56+
}
57+
58+
} // namespace TAO_PEGTL_NAMESPACE
59+
60+
#include "main.hpp"

0 commit comments

Comments
 (0)