RESTinio
Loading...
Searching...
No Matches
easy_parser.hpp
Go to the documentation of this file.
1/*
2 * RESTinio
3 */
4
13#pragma once
14
17
20
23
25#include <restinio/expected.hpp>
26
27#include <algorithm>
28#include <array>
29#include <cstring>
30#include <iostream>
31#include <limits>
32#include <map>
33#include <optional>
34#include <vector>
35
36namespace restinio
37{
38
39namespace easy_parser
40{
41
43
44//
45// error_reason_t
46//
84
85//
86// parse_error_t
87//
94{
96 std::size_t m_position;
99
100public:
103 std::size_t position,
106 , m_reason{ reason }
107 {}
108
110 [[nodiscard]]
111 std::size_t
113
115 [[nodiscard]]
118};
119
120//
121// nothing_t
122//
129struct nothing_t {};
130
131//
132// result_value_wrapper
133//
179template< typename T >
181{
182 using result_type = T;
184
185 static void
187 {
188 to = std::move(what);
189 }
190
191 [[nodiscard]]
192 static result_type &&
194 {
195 return std::move(v);
196 }
197};
198
199//
200// result_wrapper_for
201//
244template< typename T >
249
250template< typename T >
252
253template< typename T, typename... Args >
254struct result_value_wrapper< std::vector< T, Args... > >
255{
256 using result_type = std::vector< T, Args... >;
257 using value_type = typename result_type::value_type;
259
260 static void
262 {
263 to = std::move(what);
264 }
265
266 static void
268 {
269 to.push_back( std::move(what) );
270 }
271
272 [[nodiscard]]
273 static result_type &&
275 {
276 return std::move(v);
277 }
278};
279
280namespace impl
281{
282
283//
284// std_array_wrapper
285//
298template< typename T, std::size_t S >
300{
301 std::array< T, S > m_array;
302 std::size_t m_index{ 0u };
303};
304
305} /* namespace impl */
306
307template< typename T, std::size_t S >
308struct result_value_wrapper< std::array< T, S > >
309{
310 using result_type = std::array< T, S >;
311 using value_type = typename result_type::value_type;
313
314 static void
316 {
317 to.m_array = std::move(what);
318 to.m_index = 0u;
319 }
320
321 static void
323 {
324 if( to.m_index >= S )
325 throw exception_t(
326 "index in the result std::array is out of range, "
327 "index=" + std::to_string(to.m_index) +
328 ", size={}" + std::to_string(S) );
329
330 to.m_array[ to.m_index ] = std::move(what);
331 ++to.m_index;
332 }
333
334 [[nodiscard]]
335 static result_type &&
337 {
338 return std::move(v.m_array);
339 }
340};
341
348template< typename T, std::size_t S >
349struct result_wrapper_for< impl::std_array_wrapper<T, S> >
350{
352};
353
354template< typename Char, typename... Args >
355struct result_value_wrapper< std::basic_string< Char, Args... > >
356{
357 using result_type = std::basic_string< Char, Args... >;
360
361 static void
363 {
364 to = std::move(what);
365 }
366
367 static void
369 {
370 to.push_back( what );
371 }
372
386 static void
388 {
389 to.append( what );
390 }
391
392 [[nodiscard]]
393 static result_type &&
395 {
396 return std::move(v);
397 }
398};
399
400template< typename K, typename V, typename... Args >
401struct result_value_wrapper< std::map< K, V, Args... > >
402{
403 using result_type = std::map< K, V, Args... >;
404 // NOTE: we can't use container_type::value_type here
405 // because value_type for std::map is std::pair<const K, V>,
406 // not just std::pair<K, V>,
407 using value_type = std::pair<K, V>;
409
410 static void
412 {
413 to = std::move(what);
414 }
415
416 static void
418 {
419 to.emplace( std::move(what) );
420 }
421
422 [[nodiscard]]
423 static result_type &&
425 {
426 return std::move(v);
427 }
428};
429
430template<>
432{
436
437 static void
439
440 static void
442
443 [[nodiscard]]
444 static result_type &&
446 {
447 return std::move(v);
448 }
449};
450
456constexpr std::size_t N = std::numeric_limits<std::size_t>::max();
457
458//
459// digits_to_consume_t
460//
468{
469public:
470 using underlying_int_t = std::int_fast8_t;
471
473
481
482public:
487 constexpr
492
497 constexpr
504
506 [[nodiscard]]
507 constexpr auto
508 min() const noexcept { return m_min; }
509
511 [[nodiscard]]
512 constexpr auto
513 max() const noexcept { return m_max; }
514
516 [[nodiscard]]
517 constexpr static auto
519 {
520 return std::numeric_limits<underlying_int_t>::max();
521 }
522
526 [[nodiscard]]
527 constexpr static auto
532};
533
548[[nodiscard]]
549inline constexpr digits_to_consume_t
554
569[[nodiscard]]
570inline constexpr digits_to_consume_t
574{
575 return { min, max };
576}
577
578namespace impl
579{
580
581//
582// character_t
583//
594{
595 bool m_eof;
596 char m_ch;
597};
598
599[[nodiscard]]
600inline bool
601operator==( const character_t & a, const character_t & b ) noexcept
602{
603 return (a.m_eof == b.m_eof && a.m_ch == b.m_ch);
604}
605
606[[nodiscard]]
607inline bool
608operator!=( const character_t & a, const character_t & b ) noexcept
609{
610 return (a.m_eof != b.m_eof || a.m_ch != b.m_ch);
611}
612
618constexpr char SP = ' ';
624constexpr char HTAB = '\x09';
625
626//
627// is_space
628//
634[[nodiscard]]
635inline constexpr bool
636is_space( const char ch ) noexcept
637{
638 return ch == SP || ch == HTAB;
639}
640
641//
642// is_space_predicate_t
643//
651{
652 [[nodiscard]]
653 bool
654 operator()( const char actual ) const noexcept
655 {
656 return is_space(actual);
657 }
658};
659
660//
661// is_digit
662//
668[[nodiscard]]
669inline constexpr bool
670is_digit( const char ch ) noexcept
671{
672 return (ch >= '0' && ch <= '9');
673}
674
675//
676// is_digit_predicate_t
677//
684{
685 [[nodiscard]]
686 bool
687 operator()( const char actual ) const noexcept
688 {
689 return is_digit( actual );
690 }
691};
692
693//
694// is_hexdigit
695//
701[[nodiscard]]
702inline constexpr bool
703is_hexdigit( const char ch ) noexcept
704{
705 return (ch >= '0' && ch <= '9') ||
706 (ch >= 'A' && ch <= 'F') ||
707 (ch >= 'a' && ch <= 'f');
708}
709
710//
711// is_hexdigit_predicate_t
712//
720{
721 [[nodiscard]]
722 bool
723 operator()( const char actual ) const noexcept
724 {
725 return is_hexdigit( actual );
726 }
727};
728
729//
730// source_t
731//
741{
745
750 string_view_t::size_type m_index{};
751
752public:
754 using position_t = string_view_t::size_type;
755
758
760
764 [[nodiscard]]
765 character_t
767 {
768 if( m_index < m_data.size() )
769 {
770 return {false, m_data[ m_index++ ]};
771 }
772 else
773 return {true, 0};
774 }
775
777 void
779 {
780 if( m_index )
781 --m_index;
782 }
783
785 [[nodiscard]]
788 {
789 return m_index;
790 }
791
794 void
796 {
797 if( pos <= m_data.size() )
798 m_index = pos;
799 }
800
802 [[nodiscard]]
803 bool
805 {
806 return m_index >= m_data.size();
807 }
808
810
815 [[nodiscard]]
819 string_view_t::size_type from,
823 string_view_t::size_type length = string_view_t::npos ) const noexcept
824 {
825 return m_data.substr( from, length );
826 }
827
852 {
855 bool m_consumed{ false };
856
857 public :
861
866
872
875 {
876 return m_started_at;
877 }
878
880
885 void
887 {
888 m_consumed = true;
889 }
890 };
891};
892
893//
894// entity_type_t
895//
902{
904 producer,
909 consumer,
911 clause,
914
918};
919
920//
921// producer_tag
922//
944template< typename Result_Type >
950
951template< typename T, typename = meta::void_t<> >
952struct is_producer : public std::false_type {};
953
954template< typename T >
955struct is_producer< T, meta::void_t< decltype(T::entity_type) > >
956{
957 static constexpr bool value = entity_type_t::producer == T::entity_type;
958};
959
970template< typename T >
972
973//
974// transformer_tag
975//
998template< typename Result_Type >
1004
1005template< typename T, typename = meta::void_t<> >
1006struct is_transformer : public std::false_type {};
1007
1008template< typename T >
1009struct is_transformer< T, meta::void_t< decltype(T::entity_type) > >
1010{
1011 static constexpr bool value = entity_type_t::transformer == T::entity_type;
1012};
1013
1024template< typename T >
1026
1027//
1028// transformer_invoker
1029//
1047template< typename Result_Type >
1049{
1050 template< typename Transformer, typename Input_Type >
1051 [[nodiscard]]
1052 static Result_Type
1054 source_t &,
1057 {
1058 return transformer.transform( std::move(*input) );
1059 }
1060};
1061
1068template< typename Result_Type >
1070{
1071 template< typename Transformer, typename Input_Type >
1072 [[nodiscard]]
1075 // source_t is necessary to get the position in the case of an error.
1076 source_t & source,
1079 {
1080 auto result = transformer.transform( std::move(*input) );
1081 if( result )
1082 return *result;
1083 else
1084 return make_unexpected( parse_error_t{
1085 source.current_position(),
1086 result.error()
1087 } );
1088 }
1089};
1090
1091//
1092// is_appropriate_transformer_result_type
1093//
1110template< typename Result_Type >
1112{
1113 static constexpr bool value = true;
1114};
1115
1116template< typename Result_Type >
1119{
1120 static constexpr bool value = true;
1121};
1122
1123template< typename Result_Type >
1126{
1127 static constexpr bool value = false;
1128};
1129
1130//
1131// transformed_value_producer_traits_checker
1132//
1144template< typename Producer, typename Transformer >
1146{
1147 static_assert( is_producer_v<Producer>,
1148 "Producer should be a producer type" );
1149 static_assert( is_transformer_v<Transformer>,
1150 "Transformer should be a transformer type" );
1151
1152 using producer_result_t = std::decay_t< decltype(
1153 std::declval<Producer &>().try_parse( std::declval<source_t &>() )
1154 ) >;
1155
1156 using transformation_result_t = std::decay_t< decltype(
1157 std::declval<Transformer &>().transform(
1158 std::move(*(std::declval<producer_result_t>())) )
1159 ) >;
1160
1161 using expected_result_t = typename Transformer::result_type;
1162
1165};
1166
1167//
1168// transformed_value_producer_t
1169//
1179template< typename Producer, typename Transformer >
1181 : public producer_tag< typename Transformer::result_type >
1182{
1185
1186 static_assert(
1188 "transformation result should be either T or "
1189 "expected_t<T, error_reson_t>, not expected_t<T, parse_error_t>" );
1190
1193
1194public :
1195 using result_type = typename Transformer::result_type;
1196
1203
1204 [[nodiscard]]
1207 {
1208 auto producer_result = m_producer.try_parse( source );
1209 if( producer_result )
1210 {
1211 using transformation_result_t =
1213
1215 source,
1217 std::move(producer_result) );
1218 }
1219 else
1220 return make_unexpected( producer_result.error() );
1221 }
1222};
1223
1229template< typename P, typename T >
1230[[nodiscard]]
1231std::enable_if_t<
1235 P producer,
1236 T transformer )
1237{
1239
1240 return transformator_type{ std::move(producer), std::move(transformer) };
1241}
1242
1243//
1244// transformer_proxy_tag
1245//
1271
1272template< typename T, typename = meta::void_t<> >
1273struct is_transformer_proxy : public std::false_type {};
1274
1275template< typename T >
1276struct is_transformer_proxy< T, meta::void_t< decltype(T::entity_type) > >
1277{
1278 static constexpr bool value = entity_type_t::transformer_proxy == T::entity_type;
1279};
1280
1290template< typename T >
1292
1299template<
1300 typename P,
1301 typename T,
1302 typename S = std::enable_if_t<
1304 void > >
1305[[nodiscard]]
1306auto
1308 P producer,
1310{
1311 auto real_transformer = transformer_proxy.template make_transformer<
1312 typename P::result_type >();
1313
1314 using transformator_type = std::decay_t< decltype(real_transformer) >;
1315
1317
1318 return producer_type{ std::move(producer), std::move(real_transformer) };
1319}
1320
1321//
1322// consumer_tag
1323//
1347
1348template< typename T, typename = meta::void_t<> >
1349struct is_consumer : public std::false_type {};
1350
1351template< typename T >
1352struct is_consumer< T, meta::void_t< decltype(T::entity_type) > >
1353{
1354 static constexpr bool value = entity_type_t::consumer == T::entity_type;
1355};
1356
1367template< typename T >
1369
1370//
1371// clause_tag
1372//
1394{
1396};
1397
1398template< typename T, typename = meta::void_t<> >
1399struct is_clause : public std::false_type {};
1400
1401template< typename T >
1402struct is_clause< T, meta::void_t<
1403 decltype(std::decay_t<T>::entity_type) > >
1404{
1405 using real_type = std::decay_t<T>;
1406
1407 static constexpr bool value = entity_type_t::clause == real_type::entity_type;
1408};
1409
1420template< typename T >
1422
1423//
1424// tuple_of_entities_t
1425//
1456template< typename... Entities >
1458 meta::transform_t< std::decay, meta::type_list<Entities...> >,
1459 std::tuple >;
1460
1461//
1462// consume_value_clause_t
1463//
1473template< typename P, typename C >
1475{
1476 static_assert( is_producer_v<P>, "P should be a producer type" );
1477 static_assert( is_consumer_v<C>, "C should be a consumer type" );
1478
1481
1482public :
1484 : m_producer{ std::move(producer) }
1485 , m_consumer{ std::move(consumer) }
1486 {}
1487
1488 template< typename Target_Type >
1489 [[nodiscard]]
1490 std::optional< parse_error_t >
1492 {
1493 auto parse_result = m_producer.try_parse( from );
1494 if( parse_result )
1495 {
1496 m_consumer.consume( target, std::move(*parse_result) );
1497 return std::nullopt;
1498 }
1499 else
1500 return parse_result.error();
1501 }
1502};
1503
1509template< typename P, typename C >
1510[[nodiscard]]
1511std::enable_if_t<
1515{
1516 return { std::move(producer), std::move(consumer) };
1517}
1518
1519//
1520// top_level_clause_t
1521//
1532template< typename Producer >
1534{
1535 static_assert( is_producer_v<Producer>,
1536 "Producer should be a producer type" );
1537
1539
1540public :
1544
1545 [[nodiscard]]
1546 auto
1548 {
1549 return m_producer.try_parse( from );
1550 }
1551};
1552
1553//
1554// ensure_no_remaining_content
1555//
1565[[nodiscard]]
1566inline std::optional< parse_error_t >
1568 source_t & from )
1569{
1570 while( !from.eof() )
1571 {
1572 if( !is_space( from.getch().m_ch ) )
1573 {
1574 from.putback(); // Otherwise current_position() will be wrong.
1575 return parse_error_t{
1576 from.current_position(),
1578 };
1579 }
1580 }
1581
1582 return std::nullopt;
1583}
1584
1585//
1586// remove_trailing_spaces
1587//
1593[[nodiscard]]
1594inline string_view_t
1596{
1597 auto s = from.size();
1598 for(; s && is_space( from[ (s-1u) ] ); --s) {}
1599
1600 return from.substr( 0u, s );
1601}
1602
1603//
1604// alternatives_clause_t
1605//
1634template<
1635 typename Subitems_Tuple >
1637{
1639
1640public :
1645
1646 template< typename Target_Type >
1647 [[nodiscard]]
1648 std::optional< parse_error_t >
1650 {
1651 const auto starting_pos = from.current_position();
1652
1653 std::optional< parse_error_t > actual_parse_error;
1655 m_subitems,
1656 [&from, &target, &actual_parse_error]( auto && one_producer ) {
1659
1661 if( !actual_parse_error )
1662 {
1663 target = std::move(tmp_value);
1664 consumer.commit();
1665
1666 return true;
1667 }
1668 else {
1669 // Since v.0.6.7 we should check for
1670 // force_only_this_alternative_failed error.
1671 // In the case of that error enumeration of alternatives
1672 // should be stopped.
1674 actual_parse_error->reason();
1675 }
1676 } );
1677
1678 if( !success || actual_parse_error )
1679 return parse_error_t{
1682 };
1683 else
1684 return std::nullopt;
1685 }
1686};
1687
1688//
1689// maybe_clause_t
1690//
1715template<
1716 typename Subitems_Tuple >
1718{
1720
1721public :
1724 : m_subitems{ std::move(subitems) }
1725 {}
1726
1727 template< typename Target_Type >
1728 [[nodiscard]]
1729 std::optional< parse_error_t >
1731 {
1734
1736 m_subitems,
1737 [&from, &tmp_value]( auto && one_producer ) {
1738 return !one_producer.try_process( from, tmp_value );
1739 } );
1740
1741 if( success )
1742 {
1743 target = std::move(tmp_value);
1744 consumer.commit();
1745 }
1746
1747 // maybe_clause always returns success even if nothing consumed.
1748 return std::nullopt;
1749 }
1750};
1751
1752//
1753// not_clause_t
1754//
1778template<
1779 typename Subitems_Tuple >
1781{
1783
1784public :
1787 : m_subitems{ std::move(subitems) }
1788 {}
1789
1790 template< typename Target_Type >
1791 [[nodiscard]]
1792 std::optional< parse_error_t >
1794 {
1795 // NOTE: will always return the current position back.
1797
1799
1801 m_subitems,
1802 [&from, &dummy_value]( auto && one_producer ) {
1803 return !one_producer.try_process( from, dummy_value );
1804 } );
1805
1806 // This is contra-intuitive but: we return pattern_not_found in
1807 // the case when pattern is actually found in the input.
1808 if( !success )
1809 return parse_error_t{
1810 consumer.started_at(),
1811 //FIXME: maybe a more appropriate error_reason can
1812 //be used here?
1814 };
1815 else
1816 return std::nullopt;
1817 }
1818};
1819
1820//
1821// and_clause_t
1822//
1846template<
1847 typename Subitems_Tuple >
1849{
1851
1852public :
1855 : m_subitems{ std::move(subitems) }
1856 {}
1857
1858 template< typename Target_Type >
1859 [[nodiscard]]
1860 std::optional< parse_error_t >
1862 {
1863 // NOTE: will always return the current position back.
1865
1867
1869 m_subitems,
1870 [&from, &dummy_value]( auto && one_producer ) {
1871 return !one_producer.try_process( from, dummy_value );
1872 } );
1873
1874 if( !success )
1875 return parse_error_t{
1876 consumer.started_at(),
1878 };
1879 else
1880 return std::nullopt;
1881 }
1882};
1883
1884//
1885// sequence_clause_t
1886//
1907template<
1908 typename Subitems_Tuple >
1910{
1912
1913public :
1918
1919 template< typename Target_Type >
1920 [[nodiscard]]
1921 std::optional< parse_error_t >
1923 {
1926
1927 // We should store actual parse error from subitems to return it.
1928 std::optional< parse_error_t > result;
1929
1931 m_subitems,
1932 [&from, &tmp_value, &result]( auto && one_producer ) {
1933 result = one_producer.try_process( from, tmp_value );
1934 return !result;
1935 } );
1936
1937 if( success )
1938 {
1939 target = std::move(tmp_value);
1940 consumer.commit();
1941 }
1942
1943 return result;
1944 }
1945};
1946
1947//
1948// forced_alternative_clause_t
1949//
1960template<
1961 typename Subitems_Tuple >
1962class forced_alternative_clause_t : public sequence_clause_t< Subitems_Tuple >
1963{
1965
1966public :
1967 using base_type_t::base_type_t;
1968
1969 template< typename Target_Type >
1970 [[nodiscard]]
1971 std::optional< parse_error_t >
1973 {
1974 const auto starting_pos = from.current_position();
1975
1977 {
1978 // The forced clause is not parsed correctly.
1979 // So the special error code should be returned in that case.
1980 return parse_error_t{
1983 };
1984 }
1985 else
1986 return std::nullopt;
1987 }
1988};
1989
1990//
1991// produce_t
1992//
2007template<
2008 typename Target_Type,
2009 typename Subitems_Tuple >
2010class produce_t : public producer_tag< Target_Type >
2011{
2013
2015
2016public :
2019 : m_subitems{ std::move(subitems) }
2020 {}
2021
2022 [[nodiscard]]
2025 {
2027 std::optional< parse_error_t > error;
2028
2030 m_subitems,
2031 [&from, &tmp_value, &error]( auto && one_clause ) {
2032 error = one_clause.try_process( from, tmp_value );
2033 return !error;
2034 } );
2035
2036 if( success )
2038 else
2039 return make_unexpected( *error );
2040 }
2041};
2042
2043//
2044// repeat_clause_t
2045//
2059template<
2060 typename Subitems_Tuple >
2062{
2063 std::size_t m_min_occurences;
2064 std::size_t m_max_occurences;
2065
2067
2068public :
2070 std::size_t min_occurences,
2071 std::size_t max_occurences,
2075 , m_subitems{ std::move(subitems) }
2076 {}
2077
2078 template< typename Target_Type >
2079 [[nodiscard]]
2080 std::optional< parse_error_t >
2082 {
2084
2085 std::size_t count{};
2086 bool failure_detected{ false };
2087 for(; !failure_detected && count != m_max_occurences; )
2088 {
2090
2092 m_subitems,
2093 [&from, &dest]( auto && one_clause ) {
2094 return !one_clause.try_process( from, dest );
2095 } );
2096
2097 if( !failure_detected )
2098 {
2099 // Another item successfully parsed and should be stored.
2101 ++count;
2102 }
2103 }
2104
2105 if( count >= m_min_occurences )
2106 {
2107 whole_consumer.commit();
2108 return std::nullopt;
2109 }
2110
2111 return parse_error_t{
2112 from.current_position(),
2114 };
2115 }
2116};
2117
2118//
2119// symbol_producer_template_t
2120//
2130template< typename Predicate >
2132 : public producer_tag< char >
2133 , protected Predicate
2134{
2135public:
2136 template< typename... Args >
2138 : Predicate{ std::forward<Args>(args)... }
2139 {}
2140
2141 [[nodiscard]]
2143 try_parse( source_t & from ) const noexcept
2144 {
2145 const auto ch = from.getch();
2146 if( !ch.m_eof )
2147 {
2148 // A call to predicate.
2149 if( (*this)(ch.m_ch) )
2150 return ch.m_ch;
2151 else
2152 {
2153 from.putback();
2154 return make_unexpected( parse_error_t{
2155 from.current_position(),
2157 } );
2158 }
2159 }
2160 else
2161 return make_unexpected( parse_error_t{
2162 from.current_position(),
2164 } );
2165 }
2166};
2167
2168//
2169// any_symbol_predicate_t
2170//
2180{
2181 [[nodiscard]]
2182 constexpr bool
2183 operator()( const char ) const noexcept
2184 {
2185 return true;
2186 }
2187};
2188
2189//
2190// particular_symbol_predicate_t
2191//
2199{
2201
2202 [[nodiscard]]
2203 bool
2204 operator()( const char actual ) const noexcept
2205 {
2206 return m_expected == actual;
2207 }
2208};
2209
2210//
2211// not_particular_symbol_predicate_t
2212//
2220{
2222
2223 [[nodiscard]]
2224 bool
2225 operator()( const char actual ) const noexcept
2226 {
2227 return m_sentinel != actual;
2228 }
2229};
2230
2231//
2232// caseless_particular_symbol_predicate_t
2233//
2241{
2243
2247
2248 [[nodiscard]]
2249 bool
2250 operator()( const char actual ) const noexcept
2251 {
2253 }
2254};
2255
2256//
2257// symbol_from_range_predicate_t
2258//
2268{
2271
2272 [[nodiscard]]
2273 bool
2274 operator()( const char actual ) const noexcept
2275 {
2276 return ( actual >= m_left && actual <= m_right );
2277 }
2278};
2279
2280//
2281// symbol_producer_t
2282//
2302
2303//
2304// any_symbol_if_not_producer_t
2305//
2325
2326//
2327// caseless_symbol_producer_t
2328//
2351
2352//
2353// symbol_from_range_producer_t
2354//
2374
2375//
2376// digit_producer_t
2377//
2387 : public symbol_producer_template_t< is_digit_predicate_t >
2388{
2389public:
2391};
2392
2393//
2394// hexdigit_producer_t
2395//
2405 : public symbol_producer_template_t< is_hexdigit_predicate_t >
2406{
2407public:
2409};
2410
2411//
2412// try_parse_digits_with_digits_limit
2413//
2435template< typename T, typename Value_Accumulator >
2436[[nodiscard]]
2439 source_t & from,
2441 Value_Accumulator acc ) noexcept
2442{
2444
2446
2447 for( auto ch = from.getch(); !ch.m_eof; ch = from.getch() )
2448 {
2449 if( is_digit(ch.m_ch) )
2450 {
2451 acc.next_digit( static_cast<T>(ch.m_ch - '0') );
2452
2453 if( acc.overflow_detected() )
2454 return make_unexpected( parse_error_t{
2455 consumer.started_at(),
2457 } );
2458
2460 if( symbols_processed == digits_limit.max() )
2461 break;
2462 }
2463 else
2464 {
2465 from.putback();
2466 break;
2467 }
2468 }
2469
2470 if( symbols_processed < digits_limit.min() )
2471 // Not all required digits are extracted.
2472 return make_unexpected( parse_error_t{
2473 from.current_position(),
2475 } );
2476 else
2477 {
2478 consumer.commit();
2479 return acc.value();
2480 }
2481}
2482
2483//
2484// try_parse_hexdigits_with_digits_limit
2485//
2499template< typename T, typename Value_Accumulator >
2500[[nodiscard]]
2503 source_t & from,
2505 Value_Accumulator acc ) noexcept
2506{
2507 const auto ch_to_digit = []( char ch ) -> std::pair<bool, T> {
2508 if( ch >= '0' && ch <= '9' )
2509 return std::make_pair( true, static_cast<T>(ch - '0') );
2510 else if( ch >= 'A' && ch <= 'F' )
2511 return std::make_pair( true, static_cast<T>(10 + (ch - 'A')) );
2512 else if( ch >= 'a' && ch <= 'f' )
2513 return std::make_pair( true, static_cast<T>(10 + (ch - 'a')) );
2514 else
2515 return std::make_pair( false, static_cast<T>(0) );
2516 };
2517
2519
2521
2522 for( auto ch = from.getch(); !ch.m_eof; ch = from.getch() )
2523 {
2524 const auto d = ch_to_digit( ch.m_ch );
2525 if( d.first )
2526 {
2527 acc.next_digit( d.second );
2528
2529 if( acc.overflow_detected() )
2530 return make_unexpected( parse_error_t{
2531 consumer.started_at(),
2533 } );
2534
2536 if( symbols_processed == digits_limit.max() )
2537 break;
2538 }
2539 else
2540 {
2541 from.putback();
2542 break;
2543 }
2544 }
2545
2546 if( symbols_processed < digits_limit.min() )
2547 // Not all required digits are extracted.
2548 return make_unexpected( parse_error_t{
2549 from.current_position(),
2551 } );
2552 else
2553 {
2554 consumer.commit();
2555 return acc.value();
2556 }
2557}
2558
2559//
2560// non_negative_decimal_number_producer_t
2561//
2570template< typename T >
2584
2585//
2586// non_negative_decimal_number_producer_with_digits_limit_t
2587//
2598template< typename T >
2620
2621//
2622// hexadecimal_number_producer_t
2623//
2632template< typename T >
2634{
2635 static_assert( std::is_unsigned<T>::value,
2636 "T is expected to be unsigned type" );
2637
2638public:
2639 [[nodiscard]]
2648};
2649
2650//
2651// hexadecimal_number_producer_with_digits_limit_t
2652//
2663template< typename T >
2685
2686//
2687// decimal_number_producer_t
2688//
2697template< typename T >
2699{
2700 static_assert( std::is_signed<T>::value,
2701 "decimal_number_producer_t can be used only for signed types" );
2702
2703public:
2705
2706 [[nodiscard]]
2708 try_parse( source_t & from ) const noexcept
2709 {
2710 return try_parse_impl( from,
2711 []() noexcept {
2713 } );
2714 }
2715
2716protected:
2717 template< typename Digits_Limit_Maker >
2718 [[nodiscard]]
2721 source_t & from,
2722 Digits_Limit_Maker && digits_limit_maker ) const noexcept
2723 {
2725
2726 auto sign_ch = from.getch();
2727 if( !sign_ch.m_eof )
2728 {
2730 from,
2731 sign_ch.m_ch,
2732 std::forward<Digits_Limit_Maker>(digits_limit_maker) );
2733
2734 if( r )
2735 consumer.commit();
2736
2737 return r;
2738 }
2739 else
2740 return make_unexpected( parse_error_t{
2741 from.current_position(),
2743 } );
2744 }
2745
2746private:
2747 template< typename Digits_Limit_Maker >
2748 [[nodiscard]]
2751 source_t & from,
2752 char first_symbol,
2754 {
2757
2758 if( '-' == first_symbol )
2759 {
2761 from,
2763 overflow_controlled_integer_accumulator_t<
2764 T,
2765 10,
2766 check_negative_extremum >{} );
2767 if( r )
2768 return static_cast< T >( -(*r) ); // This static_cast is required
2769 // for clang compiler that warns that if type of *r is `short`,
2770 // then -(*r) will have type `int`.
2771 else
2772 return r;
2773 }
2774 else if( '+' == first_symbol )
2775 {
2777 from,
2780 }
2781 else if( is_digit(first_symbol) )
2782 {
2783 from.putback();
2785 from,
2788 }
2789
2790 return make_unexpected( parse_error_t{
2791 from.current_position(),
2793 } );
2794 }
2795};
2796
2797//
2798// decimal_number_producer_with_digits_limit_t
2799//
2810template< typename T >
2812 : public decimal_number_producer_t< T >
2813{
2815
2816public:
2821
2822 [[nodiscard]]
2823 auto
2824 try_parse( source_t & from ) const noexcept
2825 {
2826 return this->try_parse_impl(
2827 from,
2828 [this]() noexcept { return m_digits_limit; } );
2829 }
2830};
2831
2832//
2833// any_value_skipper_t
2834//
2844{
2845 template< typename Target_Type, typename Value >
2846 void
2848};
2849
2850//
2851// as_result_consumer_t
2852//
2871{
2872 template< typename Target_Type, typename Value >
2873 void
2875 {
2877 dest, std::forward<Value>(src) );
2878 }
2879};
2880
2881//
2882// just_result_consumer_t
2883//
2891template< typename Result_Type >
2893{
2895
2896 // NOTE: this helper method is necessary for MSVC++ compiler.
2897 // It's because MSVC++ can't compile expression:
2898 //
2899 // as_result(dest, Result_Type{m_result})
2900 //
2901 // in consume() method for trivial types like size_t.
2908
2909public :
2910 template< typename Result_Arg >
2912 noexcept(noexcept(Result_Type{std::forward<Result_Arg>(result)}))
2913 : m_result{ std::forward<Result_Arg>(result) }
2914 {}
2915
2916 template< typename Target_Type, typename Value >
2917 void
2919 {
2921 dest,
2922 // NOTE: use a copy of m_result.
2924 }
2925};
2926
2927//
2928// custom_consumer_t
2929//
2939template< typename C >
2941{
2943
2944public :
2946
2947 template< typename Target_Type, typename Value >
2948 void
2950 noexcept(noexcept(m_consumer(dest, std::forward<Value>(src))))
2951 {
2952 m_consumer( dest, std::forward<Value>(src) );
2953 }
2954};
2955
2956//
2957// field_setter_consumer_t
2958//
2968template< typename F, typename C >
2970{
2971 using pointer_t = F C::*;
2972
2974
2975public :
2977
2978 // NOTE: it seems that this method won't be compiled if
2979 // result_value_wrapper::result_type differs from
2980 // result_value_wrapper::wrapped_type.
2981 //
2982 // This is not a problem for the current version.
2983 // But this moment would require more attention in the future.
2984 void
2985 consume( C & to, F && value ) const
2986 noexcept(noexcept(to.*m_ptr = std::move(value)))
2987 {
2988 to.*m_ptr = std::move(value);
2989 }
2990};
2991
2998template< typename P, typename F, typename C >
2999[[nodiscard]]
3000std::enable_if_t<
3004{
3005 return {
3006 std::move(producer),
3008 };
3009}
3010
3011//
3012// tuple_item_consumer_t
3013//
3020template< std::size_t Index >
3022{
3023 // NOTE: it seems that this method won't be compiled if
3024 // result_value_wrapper::result_type differs from
3025 // result_value_wrapper::wrapped_type.
3026 //
3027 // This is not a problem for the current version.
3028 // But this moment would require more attention in the future.
3029 template< typename Target_Type, typename Value >
3030 void
3031 consume( Target_Type && to, Value && value )
3032 {
3033 std::get<Index>(std::forward<Target_Type>(to)) =
3034 std::forward<Value>(value);
3035 }
3036};
3037
3038//
3039// to_lower_transformer_t
3040//
3041template< typename Input_Type >
3043
3050template<>
3051struct to_lower_transformer_t< std::string >
3052 : public transformer_tag< std::string >
3053{
3054 using input_type = std::string;
3055
3056 [[nodiscard]]
3058 transform( input_type && input ) const noexcept
3059 {
3060 result_type result{ std::move(input) };
3061 std::transform( result.begin(), result.end(), result.begin(),
3062 []( unsigned char ch ) -> char {
3063 return restinio::impl::to_lower_case(ch);
3064 } );
3065
3066 return result;
3067 }
3068};
3069
3076template<>
3078 : public transformer_tag< char >
3079{
3081
3082 [[nodiscard]]
3084 transform( input_type && input ) const noexcept
3085 {
3087 }
3088};
3089
3096template< std::size_t S >
3097struct to_lower_transformer_t< std::array< char, S > >
3098 : public transformer_tag< std::array< char, S > >
3099{
3100 using input_type = std::array< char, S >;
3102
3103 [[nodiscard]]
3104 typename base_type::result_type
3105 transform( input_type && input ) const noexcept
3106 {
3108 std::transform( input.begin(), input.end(), result.begin(),
3109 []( unsigned char ch ) -> char {
3110 return restinio::impl::to_lower_case(ch);
3111 } );
3112
3113 return result;
3114 }
3115};
3116
3117//
3118// to_lower_transformer_proxy_t
3119//
3126{
3127 template< typename Input_Type >
3128 [[nodiscard]]
3129 auto
3134};
3135
3136//
3137// just_value_transformer_t
3138//
3145template< typename T >
3147{
3149
3150public :
3151 just_value_transformer_t( T v ) noexcept(noexcept(T{std::move(v)}))
3152 : m_value{ std::move(v) }
3153 {}
3154
3155 template< typename Input >
3156 [[nodiscard]]
3157 T
3159 {
3160 return m_value;
3161 }
3162};
3163
3164//
3165// convert_transformer_t
3166//
3173template< typename Output_Type, typename Converter >
3174class convert_transformer_t : public transformer_tag< Output_Type >
3175{
3177
3178public :
3179 template< typename Convert_Arg >
3181 noexcept(noexcept(Converter{std::forward<Convert_Arg>(converter)}))
3182 : m_converter{ std::forward<Convert_Arg>(converter) }
3183 {}
3184
3193 template< typename Input >
3194 [[nodiscard]]
3195 auto
3197 noexcept(noexcept(m_converter(std::forward<Input>(input))))
3198 {
3199 using actual_result_t = std::decay_t< decltype(
3200 m_converter(std::forward<Input>(input))
3201 ) >;
3202
3203 static_assert(
3205 "the return value of converter should be either Output_Type or "
3206 "expected_t<Output_Type, error_reason_t>" );
3207
3208 return m_converter(std::forward<Input>(input));
3209 }
3210};
3211
3212//
3213// conversion_result_type_detector
3214//
3225template< typename Result_Type >
3230
3231template< typename Result_Type >
3236
3242template< typename Result_Type >
3245
3246//
3247// convert_transformer_proxy_t
3248//
3262template< typename Converter >
3264{
3265 template< typename Input_Type >
3267 std::decay_t< decltype(
3268 std::declval<Converter &>()(std::declval<Input_Type&&>())
3269 ) >
3270 >;
3271
3273
3274public :
3275 template< typename Convert_Arg >
3277 noexcept(noexcept(Converter{std::forward<Convert_Arg>(converter)}))
3278 : m_converter{ std::forward<Convert_Arg>(converter) }
3279 {}
3280
3281 template< typename Input_Type >
3282 [[nodiscard]]
3283 auto
3291
3292 template< typename Input_Type >
3293 [[nodiscard]]
3294 auto
3296 noexcept(noexcept(Converter{std::move(m_converter)}))
3297 {
3299
3301 std::move(m_converter)
3302 };
3303 }
3304};
3305
3306//
3307// try_parse_exact_fragment
3308//
3309
3310// Requires that begin is not equal to end.
3311template< typename It >
3312[[nodiscard]]
3315{
3316 assert( begin != end );
3317
3319
3320 for( auto ch = from.getch(); !ch.m_eof; ch = from.getch() )
3321 {
3322 if( ch.m_ch != *begin )
3323 return make_unexpected( parse_error_t{
3324 consumer.started_at(),
3326 } );
3327 if( ++begin == end )
3328 break;
3329 }
3330
3331 if( begin != end )
3332 return make_unexpected( parse_error_t{
3333 consumer.started_at(),
3335 } );
3336
3337 consumer.commit();
3338
3339 return true;
3340}
3341
3342//
3343// exact_fixed_size_fragment_producer_t
3344//
3354template< std::size_t Size >
3356 : public producer_tag< bool >
3357{
3358 static_assert( 1u < Size, "Size is expected to greater that 1" );
3359
3360 // NOTE: there is no space for last zero-byte.
3361 std::array< char, Size-1u > m_fragment;
3362
3363public:
3365 {
3366 // NOTE: last zero-byte is discarded.
3367 std::copy( &f[ 0 ], &f[ m_fragment.size() ], m_fragment.data() );
3368 }
3369
3370 [[nodiscard]]
3373 {
3375 m_fragment.begin(), m_fragment.end() );
3376 }
3377};
3378
3379//
3380// exact_fragment_producer_t
3381//
3389 : public producer_tag< bool >
3390{
3391 std::string m_fragment;
3392
3393public:
3394 exact_fragment_producer_t( std::string fragment )
3395 : m_fragment{ std::move(fragment) }
3396 {
3397 if( m_fragment.empty() )
3398 throw exception_t( "'fragment' value for exact_fragment_producer_t "
3399 "can't be empty!" );
3400 }
3401
3402 [[nodiscard]]
3405 {
3407 m_fragment.begin(), m_fragment.end() );
3408 }
3409};
3410
3411//
3412// try_parse_caseless_exact_fragment
3413//
3414
3415// Requires that begin is not equal to end.
3416// It assumes that content in [begin, end) is already in lower case.
3417template< typename It >
3418[[nodiscard]]
3421{
3422 assert( begin != end );
3423
3425
3426 for( auto ch = from.getch(); !ch.m_eof; ch = from.getch() )
3427 {
3428 if( restinio::impl::to_lower_case(ch.m_ch) != *begin )
3429 return make_unexpected( parse_error_t{
3430 consumer.started_at(),
3432 } );
3433 if( ++begin == end )
3434 break;
3435 }
3436
3437 if( begin != end )
3438 return make_unexpected( parse_error_t{
3439 consumer.started_at(),
3441 } );
3442
3443 consumer.commit();
3444
3445 return true;
3446}
3447
3448//
3449// caseless_exact_fixed_size_fragment_producer_t
3450//
3462template< std::size_t Size >
3464 : public producer_tag< bool >
3465{
3466 static_assert( 1u < Size, "Size is expected to greater that 1" );
3467
3468 // NOTE: there is no space for last zero-byte.
3469 std::array< char, Size-1u > m_fragment;
3470
3471public:
3473 {
3474 // Content should be converted to lower-case.
3475 // NOTE: last zero-byte is discarded.
3476 std::transform(
3477 &f[ 0 ], &f[ m_fragment.size() ],
3478 m_fragment.data(),
3479 []( const char src ) {
3480 return restinio::impl::to_lower_case( src );
3481 } );
3482 }
3483
3484 [[nodiscard]]
3487 {
3489 m_fragment.begin(), m_fragment.end() );
3490 }
3491};
3492
3493//
3494// caseless_exact_fragment_producer_t
3495//
3505 : public producer_tag< bool >
3506{
3507 std::string m_fragment;
3508
3509public:
3511 : m_fragment{ std::move(fragment) }
3512 {
3513 if( m_fragment.empty() )
3514 throw exception_t( "'fragment' value for exact_fragment_producer_t "
3515 "can't be empty!" );
3516
3517 // Content should be converted to lower-case.
3518 for( auto & ch : m_fragment )
3520 }
3521
3522 [[nodiscard]]
3525 {
3527 m_fragment.begin(), m_fragment.end() );
3528 }
3529};
3530
3531} /* namespace impl */
3532
3533//
3534// produce
3535//
3550template<
3551 typename Target_Type,
3552 typename... Clauses >
3553[[nodiscard]]
3554auto
3556{
3557 static_assert( 0 != sizeof...(clauses),
3558 "list of clauses can't be empty" );
3559 static_assert( meta::all_of_v< impl::is_clause, Clauses... >,
3560 "all arguments for produce() should be clauses" );
3561
3565
3566 return producer_type_t{
3567 std::make_tuple(std::forward<Clauses>(clauses)...)
3568 };
3569}
3570
3571//
3572// alternatives
3573//
3593template< typename... Clauses >
3594[[nodiscard]]
3595auto
3597{
3598 static_assert( 0 != sizeof...(clauses),
3599 "list of clauses can't be empty" );
3600 static_assert( meta::all_of_v< impl::is_clause, Clauses... >,
3601 "all arguments for alternatives() should be clauses" );
3602
3605
3606 return clause_type_t{
3607 std::make_tuple(std::forward<Clauses>(clauses)...)
3608 };
3609}
3610
3611//
3612// maybe
3613//
3632template< typename... Clauses >
3633[[nodiscard]]
3634auto
3636{
3637 static_assert( 0 != sizeof...(clauses),
3638 "list of clauses can't be empty" );
3639 static_assert( meta::all_of_v< impl::is_clause, Clauses... >,
3640 "all arguments for maybe() should be clauses" );
3641
3644
3645 return clause_type_t{
3646 std::make_tuple(std::forward<Clauses>(clauses)...)
3647 };
3648}
3649
3650//
3651// not_clause
3652//
3674template< typename... Clauses >
3675[[nodiscard]]
3676auto
3678{
3679 static_assert( 0 != sizeof...(clauses),
3680 "list of clauses can't be empty" );
3681 static_assert( meta::all_of_v< impl::is_clause, Clauses... >,
3682 "all arguments for not_clause() should be clauses" );
3683
3686
3687 return clause_type_t{
3688 std::make_tuple(std::forward<Clauses>(clauses)...)
3689 };
3690}
3691
3692//
3693// and_clause
3694//
3716template< typename... Clauses >
3717[[nodiscard]]
3718auto
3720{
3721 static_assert( 0 != sizeof...(clauses),
3722 "list of clauses can't be empty" );
3723 static_assert( meta::all_of_v< impl::is_clause, Clauses... >,
3724 "all arguments for sequence() should be clauses" );
3725
3728
3729 return clause_type_t{
3730 std::make_tuple(std::forward<Clauses>(clauses)...)
3731 };
3732}
3733
3734//
3735// sequence
3736//
3756template< typename... Clauses >
3757[[nodiscard]]
3758auto
3760{
3761 static_assert( 0 != sizeof...(clauses),
3762 "list of clauses can't be empty" );
3763 static_assert( meta::all_of_v< impl::is_clause, Clauses... >,
3764 "all arguments for sequence() should be clauses" );
3765
3768
3769 return clause_type_t{
3770 std::make_tuple(std::forward<Clauses>(clauses)...)
3771 };
3772}
3773
3774//
3775// force_only_this_alternative
3776//
3819template< typename... Clauses >
3820[[nodiscard]]
3821auto
3823{
3824 static_assert( 0 != sizeof...(clauses),
3825 "list of clauses can't be empty" );
3826 static_assert( meta::all_of_v< impl::is_clause, Clauses... >,
3827 "all arguments for force_only_this_alternative() should "
3828 "be clauses" );
3829
3832
3833 return clause_type_t{
3834 std::make_tuple(std::forward<Clauses>(clauses)...)
3835 };
3836}
3837
3838//
3839// repeat
3840//
3873template<
3874 typename... Clauses >
3875[[nodiscard]]
3876auto
3879 std::size_t min_occurences,
3881
3886 std::size_t max_occurences,
3888 Clauses &&... clauses )
3889{
3890 static_assert( 0 != sizeof...(clauses),
3891 "list of clauses can't be empty" );
3892 static_assert( meta::all_of_v< impl::is_clause, Clauses... >,
3893 "all arguments for repeat() should be clauses" );
3894
3897
3898 return producer_type_t{
3901 std::make_tuple(std::forward<Clauses>(clauses)...)
3902 };
3903}
3904
3905//
3906// skip
3907//
3921[[nodiscard]]
3922inline auto
3924
3925//
3926// any_symbol_p
3927//
3936[[nodiscard]]
3937inline auto
3942
3943//
3944// symbol_p
3945//
3954[[nodiscard]]
3955inline auto
3956symbol_p( char expected ) noexcept
3957{
3959}
3960
3961//
3962// any_symbol_if_not_p
3963//
3972[[nodiscard]]
3973inline auto
3978
3979//
3980// caseless_symbol_p
3981//
3992[[nodiscard]]
3993inline auto
3995{
3997}
3998
3999//
4000// symbol_from_range_p
4001//
4010[[nodiscard]]
4011inline auto
4012symbol_from_range_p( char left, char right ) noexcept
4013{
4015}
4016
4017//
4018// symbol
4019//
4031[[nodiscard]]
4032inline auto
4033symbol( char expected ) noexcept
4034{
4035 return symbol_p(expected) >> skip();
4036}
4037
4038//
4039// caseless_symbol
4040//
4054[[nodiscard]]
4055inline auto
4057{
4058 return caseless_symbol_p(expected) >> skip();
4059}
4060
4061//
4062// symbol_from_range
4063//
4075[[nodiscard]]
4076inline auto
4077symbol_from_range( char left, char right ) noexcept
4078{
4079 return symbol_from_range_p(left, right) >> skip();
4080}
4081
4082//
4083// space_p
4084//
4093[[nodiscard]]
4094inline auto
4099
4100//
4101// space
4102//
4114[[nodiscard]]
4115inline auto
4117{
4118 return space_p() >> skip();
4119}
4120
4121//
4122// digit_p
4123//
4132[[nodiscard]]
4133inline auto
4135{
4136 return impl::digit_producer_t{};
4137}
4138
4139//
4140// digit
4141//
4153[[nodiscard]]
4154inline auto
4156{
4157 return digit_p() >> skip();
4158}
4159
4160//
4161// hexdigit_p
4162//
4171[[nodiscard]]
4172inline auto
4174{
4176}
4177
4178//
4179// hexdigit
4180//
4192[[nodiscard]]
4193inline auto
4195{
4196 return hexdigit_p() >> skip();
4197}
4198
4199//
4200// non_negative_decimal_number_p
4201//
4216template< typename T >
4217[[nodiscard]]
4218inline auto
4223
4224//
4225// non_negative_decimal_number_p
4226//
4255template< typename T >
4256[[nodiscard]]
4257inline auto
4264
4265//
4266// hexadecimal_number_p
4267//
4285template< typename T >
4286[[nodiscard]]
4287inline auto
4292
4293//
4294// hexadecimal_number_p
4295//
4327template< typename T >
4328[[nodiscard]]
4329inline auto
4336
4337//
4338// decimal_number_p
4339//
4365template< typename T >
4366[[nodiscard]]
4367inline auto
4369{
4370 static_assert( std::is_signed<T>::value,
4371 "decimal_number_p() can be used only for signed numeric types" );
4372
4374}
4375
4376//
4377// decimal_number_p
4378//
4418template< typename T >
4419[[nodiscard]]
4420inline auto
4422{
4423 static_assert( std::is_signed<T>::value,
4424 "decimal_number_p() can be used only for signed numeric types" );
4425
4428 };
4429}
4430
4431//
4432// as_result
4433//
4449[[nodiscard]]
4450inline auto
4452
4453//
4454// custom_consumer
4455//
4494template< typename F >
4495[[nodiscard]]
4496auto
4498{
4500
4501 return actual_consumer_t{ std::move(consumer) };
4502}
4503
4504namespace impl
4505{
4506
4507//
4508// to_container_consumer_t
4509//
4522{
4523 template< typename Container, typename Item >
4524 void
4526 {
4528 container_adaptor_type::to_container( to, std::move(item) );
4529 }
4530};
4531
4532} /* namespace impl */
4533
4534//
4535// to_container
4536//
4562[[nodiscard]]
4563inline auto
4565{
4567}
4568
4569//
4570// to_lower
4571//
4589[[nodiscard]]
4590inline auto
4592
4593//
4594// just
4595//
4613template< typename T >
4614[[nodiscard]]
4615auto
4616just( T value ) noexcept(noexcept(impl::just_value_transformer_t<T>{value}))
4617{
4618 return impl::just_value_transformer_t<T>{value};
4619}
4620
4621//
4622// just_result
4623//
4642template< typename T >
4643[[nodiscard]]
4644auto
4645just_result( T value )
4646 noexcept(noexcept(impl::just_result_consumer_t<T>{value}))
4647{
4648 return impl::just_result_consumer_t<T>{value};
4649}
4650
4651//
4652// convert
4653//
4715template< typename Converter >
4716[[nodiscard]]
4717auto
4719{
4720 using converter_type = std::decay_t<Converter>;
4721
4724
4725 return transformer_proxy_type{ std::forward<Converter>(converter) };
4726}
4727
4728//
4729// exact_p
4730//
4747[[nodiscard]]
4748inline auto
4750{
4752 std::string{ fragment.data(), fragment.size() }
4753 };
4754}
4755
4790template< std::size_t Size >
4791[[nodiscard]]
4792auto
4793exact_p( const char (&fragment)[Size] )
4794{
4796}
4797
4798//
4799// exact
4800//
4812[[nodiscard]]
4813inline auto
4815{
4817 std::string{ fragment.data(), fragment.size() }
4818 } >> skip();
4819}
4820
4849template< std::size_t Size >
4850[[nodiscard]]
4851auto
4852exact( const char (&fragment)[Size] )
4853{
4855}
4856
4857//
4858// caseless_exact_p
4859//
4876[[nodiscard]]
4877inline auto
4879{
4881 std::string{ fragment.data(), fragment.size() }
4882 };
4883}
4884
4919template< std::size_t Size >
4920[[nodiscard]]
4921auto
4922caseless_exact_p( const char (&fragment)[Size] )
4923{
4925}
4926
4927//
4928// caseless_exact
4929//
4941[[nodiscard]]
4942inline auto
4944{
4946 std::string{ fragment.data(), fragment.size() }
4947 } >> skip();
4948}
4949
4978template< std::size_t Size >
4979[[nodiscard]]
4980auto
4981caseless_exact( const char (&fragment)[Size] )
4982{
4984}
4985
4986//
4987// try_parse
4988//
5020template< typename Producer >
5021[[nodiscard]]
5025 Producer producer )
5026{
5027 static_assert( impl::is_producer_v<Producer>,
5028 "Producer should be a value producer type" );
5029
5032
5033 auto result = impl::top_level_clause_t< Producer >{ std::move(producer) }
5034 .try_process( source );
5035
5036 if( result )
5037 {
5038 // We should ensure that all content has been consumed.
5039 const auto all_content_check =
5041 if( all_content_check )
5042 return make_unexpected( *all_content_check );
5043 }
5044
5045 return result;
5046}
5047
5048//
5049// make_error_description
5050//
5082[[nodiscard]]
5083inline std::string
5085 const parse_error_t & error,
5087{
5088 const auto append_quote = [&]( std::string & dest ) {
5089 constexpr std::size_t max_quote_size = 16u;
5090 if( error.position() > 0u )
5091 {
5092 // How many chars we can get from right of error position?
5093 const auto prefix_size = error.position() > max_quote_size ?
5094 max_quote_size : error.position();
5095
5096 dest.append( 1u, '"' );
5097 dest.append(
5098 &from[ error.position() ] - prefix_size,
5099 prefix_size );
5100 dest.append( "\" >>> " );
5101 }
5102
5103 const char problematic_symbol = error.position() < from.size() ?
5104 from[ error.position() ] : '?';
5105 dest.append( 1u, '\'' );
5106 if( problematic_symbol >= '\x00' && problematic_symbol < ' ' )
5107 {
5108 constexpr char hex_digits[] = "0123456789abcdef";
5109
5110 dest.append( "\\x" );
5111 dest.append( 1u, hex_digits[
5112 static_cast<unsigned char>(problematic_symbol) >> 4 ] );
5113 dest.append( 1u, hex_digits[
5114 static_cast<unsigned char>(problematic_symbol) & 0xfu ] );
5115 }
5116 else
5117 dest.append( 1u, problematic_symbol );
5118
5119 dest.append( 1u, '\'' );
5120
5121 if( error.position() + 1u < from.size() )
5122 {
5123 // How many chars we can get from the right of error position?
5124 const auto suffix_size =
5125 error.position() + 1u + max_quote_size < from.size() ?
5126 max_quote_size : from.size() - error.position() - 1u;
5127
5128 dest.append( " <<< \"" );
5129 dest.append( &from[ error.position() + 1u ], suffix_size );
5130 dest.append( 1u, '"' );
5131 }
5132 };
5133
5134 std::string result;
5135
5136 const auto basic_reaction = [&](const char * msg) {
5137 result += msg;
5138 result += " at ";
5139 result += std::to_string( error.position() );
5140 result += ": ";
5142 };
5143
5144 switch( error.reason() )
5145 {
5147 basic_reaction( "unexpected character" );
5148 break;
5149
5151 result += "unexpected EOF at ";
5152 result += std::to_string( error.position() );
5153 break;
5154
5156 basic_reaction( "appropriate alternative can't found" );
5157 break;
5158
5160 basic_reaction( "expected pattern is not found" );
5161 break;
5162
5164 basic_reaction( "unconsumed input found" );
5165 break;
5166
5168 basic_reaction( "some illegal value found" );
5169 break;
5170
5172 basic_reaction( "forced selection alternative failed" );
5173 break;
5174 }
5175
5176 return result;
5177}
5178
5179} /* namespace easy_parser */
5180
5181} /* namespace restinio */
5182
Limits for number of digits to be extracted during parsing of decimal numbers.
static constexpr auto unlimited_max() noexcept
Get the value that means that maximum is not limited.
constexpr digits_to_consume_t(underlying_int_t total) noexcept
constexpr auto max() const noexcept
Get the maximum value.
constexpr digits_to_consume_t(underlying_int_t min, underlying_int_t max) noexcept
underlying_int_t m_max
Maximal number of digits to consume.
constexpr auto min() const noexcept
Get the minimal value.
static constexpr auto from_one_to_max() noexcept
underlying_int_t m_min
Minimal number of digits to consume.
A template for implementation of clause that selects one of alternative clauses.
std::optional< parse_error_t > try_process(source_t &from, Target_Type &target)
A template for implementation of clause that checks the presence of some entity in the input stream.
std::optional< parse_error_t > try_process(source_t &from, Target_Type &)
and_clause_t(Subitems_Tuple &&subitems)
A producer for the case when any character except the specific sentinel character is expected in the ...
A producer that expects a fragment in the input and produces boolean value if that fragment is found.
expected_t< bool, parse_error_t > try_parse(source_t &from)
A producer that expects a fragment in the input and produces boolean value if that fragment is found.
expected_t< bool, parse_error_t > try_parse(source_t &from)
A producer for the case when a particual character is expected in the input stream.
A template for a clause that binds a value producer with value consumer.
std::optional< parse_error_t > try_process(source_t &from, Target_Type &target)
A proxy for the creation of convert_transformer instances for a specific value producers.
conversion_result_type_detector_t< std::decay_t< decltype( std::declval< Converter & >()(std::declval< Input_Type && >())) > > output
convert_transformer_proxy_t(Convert_Arg &&converter) noexcept(noexcept(Converter{std::forward< Convert_Arg >(converter)}))
auto make_transformer() const &noexcept(noexcept(Converter{m_converter}))
auto make_transformer() &&noexcept(noexcept(Converter{std::move(m_converter)}))
A transformator that uses a user supplied function/functor for conversion a value from one type to an...
auto transform(Input &&input) const noexcept(noexcept(m_converter(std::forward< Input >(input))))
Performs the transformation by calling the converter.
convert_transformer_t(Convert_Arg &&converter) noexcept(noexcept(Converter{std::forward< Convert_Arg >(converter)}))
A template for consumers that are released by lambda/functional objects.
void consume(Target_Type &dest, Value &&src) const noexcept(noexcept(m_consumer(dest, std::forward< Value >(src))))
A producer for the case when a signed decimal number is expected in the input stream.
static try_parse_result_type try_parse_with_this_first_symbol(source_t &from, char first_symbol, Digits_Limit_Maker &&digits_limit_maker) noexcept
try_parse_result_type try_parse(source_t &from) const noexcept
try_parse_result_type try_parse_impl(source_t &from, Digits_Limit_Maker &&digits_limit_maker) const noexcept
A producer for the case when a signed decimal number is expected in the input stream.
A producer for the case when a decimal digit is expected in the input stream.
A producer that expects a fragment in the input and produces boolean value if that fragment is found.
expected_t< bool, parse_error_t > try_parse(source_t &from)
A producer that expects a fragment in the input and produces boolean value if that fragment is found.
expected_t< bool, parse_error_t > try_parse(source_t &from)
A template for consumers that store a value to the specified field of a target object.
void consume(C &to, F &&value) const noexcept(noexcept(to.*m_ptr=std::move(value)))
An alternative that should be parsed correctly or the parsing of the whole alternatives clause should...
std::optional< parse_error_t > try_process(source_t &from, Target_Type &target)
A producer for the case when a number in hexadecimal form is expected in the input stream.
expected_t< T, parse_error_t > try_parse(source_t &from) const noexcept
A producer for the case when a number in hexadecimal form is expected in the input stream.
expected_t< T, parse_error_t > try_parse(source_t &from) const noexcept
A producer for the case when a hexadecimal digit is expected in the input stream.
A consumer for the case when a specific value should be used as the result instead of the value produ...
Result_Type make_copy_of_result() const noexcept(noexcept(Result_Type{m_result}))
just_result_consumer_t(Result_Arg &&result) noexcept(noexcept(Result_Type{std::forward< Result_Arg >(result)}))
void consume(Target_Type &dest, Value &&) const
A transformer that skips incoming value and returns a value specified by a user.
T transform(Input &&) const noexcept(noexcept(T{m_value}))
just_value_transformer_t(T v) noexcept(noexcept(T{std::move(v)}))
A template for implementation of clause that checks and handles presence of optional entity in the in...
std::optional< parse_error_t > try_process(source_t &from, Target_Type &target)
A producer for the case when a non-negative decimal number is expected in the input stream.
expected_t< T, parse_error_t > try_parse(source_t &from) const noexcept
A producer for the case when a non-negative decimal number is expected in the input stream.
expected_t< T, parse_error_t > try_parse(source_t &from) const noexcept
A template for implementation of clause that checks absence of some entity in the input stream.
not_clause_t(Subitems_Tuple &&subitems)
std::optional< parse_error_t > try_process(source_t &from, Target_Type &)
A template for producing a value of specific type of a sequence of entities from the input stream.
produce_t(Subitems_Tuple &&subitems)
expected_t< Target_Type, parse_error_t > try_parse(source_t &from)
A template for handling repetition of clauses.
std::optional< parse_error_t > try_process(source_t &from, Target_Type &dest)
repeat_clause_t(std::size_t min_occurences, std::size_t max_occurences, Subitems_Tuple &&subitems)
A template for implementation of clause that checks and handles presence of sequence of entities in t...
std::optional< parse_error_t > try_process(source_t &from, Target_Type &target)
A helper class to automatically return acquired content back to the input stream.
content_consumer_t(const content_consumer_t &)=delete
void commit() noexcept
Consume all acquired content.
The class that implements "input stream".
source_t(string_view_t data) noexcept
Initializing constructor.
string_view_t fragment(string_view_t::size_type from, string_view_t::size_type length=string_view_t::npos) const noexcept
Return a fragment from the input stream.
position_t current_position() const noexcept
Get the current position in the stream.
string_view_t::size_type m_index
The current position in the input stream.
void putback() noexcept
Return one character back to the input stream.
character_t getch() noexcept
Get the next character from the input stream.
bool eof() const noexcept
Is EOF has been reached?
const string_view_t m_data
The content to be used as "input stream".
void backto(position_t pos) noexcept
Return the current position in the input stream at the specified position.
string_view_t::size_type position_t
Type to be used as the index inside the input stream.
A producer for the case when a symbol should belong to specified range.
A producer for the case when a particual character is expected in the input stream.
A template for producer of charachers that satisfy some predicate.
expected_t< char, parse_error_t > try_parse(source_t &from) const noexcept
A special class to be used as the top level clause in parser.
A template of producer that gets a value from another producer, transforms it and produces transforme...
transformed_value_producer_t(Producer &&producer, Transformer &&transformer)
expected_t< result_type, parse_error_t > try_parse(source_t &source)
Information about parsing error.
error_reason_t m_reason
The reason of the error.
std::size_t position() const noexcept
Get the position in the input stream where error was detected.
error_reason_t reason() const noexcept
Get the reason of the error.
std::size_t m_position
Position in the input stream.
parse_error_t(std::size_t position, error_reason_t reason) noexcept
Initializing constructor.
Exception class for all exceptions thrown by RESTinio.
Definition exception.hpp:26
Helper class for accumulating integer value during parsing it from string (with check for overflow).
Detection of compiler version and absence of various features.
Various tools for C++ metaprogramming.
expected_t< bool, parse_error_t > try_parse_exact_fragment(source_t &from, It begin, It end)
constexpr bool is_producer_v
A meta-value to check whether T is a producer type.
constexpr char HTAB
A constant for Horizontal Tab value.
typename conversion_result_type_detector< Result_Type >::type conversion_result_type_detector_t
string_view_t remove_trailing_spaces(string_view_t from) noexcept
Helper function for removal of trailing spaces from a string-view.
expected_t< T, parse_error_t > try_parse_digits_with_digits_limit(source_t &from, digits_to_consume_t digits_limit, Value_Accumulator acc) noexcept
Helper function for parsing integers with respect to the number of digits to be consumed.
constexpr bool is_hexdigit(const char ch) noexcept
Is a character a hexadecimal digit?
constexpr bool is_consumer_v
A meta-value to check whether T is a consumer type.
std::optional< parse_error_t > ensure_no_remaining_content(source_t &from)
A special function to check that there is no more actual data in the input stream except whitespaces.
constexpr char SP
A constant for SPACE value.
expected_t< T, parse_error_t > try_parse_hexdigits_with_digits_limit(source_t &from, digits_to_consume_t digits_limit, Value_Accumulator acc) noexcept
Helper function for parsing integers in hexadecimal form.
std::enable_if_t< is_producer_v< P > &is_transformer_v< T >, transformed_value_producer_t< P, T > > operator>>(P producer, T transformer)
A special operator to connect a value producer with value transformer.
entity_type_t
A marker for distinguish different kind of entities in parser.
@ consumer
Entity is a consumer of values. It requires a value on the input and doesn't produces anything.
@ transformer
Entity is a transformer of a value from one type to another.
@ clause
Entity is a clause. It doesn't produces anything.
@ producer
Entity is a producer of values.
@ transformer_proxy
Entity is a transformer-proxy. It can't be used directly, only for binding a producer and transformer...
constexpr bool is_space(const char ch) noexcept
If a character a space character?
constexpr bool is_transformer_proxy_v
A meta-value to check whether T is a transformer-proxy type.
constexpr bool is_clause_v
A meta-value to check whether T is a consumer type.
expected_t< bool, parse_error_t > try_parse_caseless_exact_fragment(source_t &from, It begin, It end)
constexpr bool is_digit(const char ch) noexcept
Is a character a decimal digit?
constexpr bool is_transformer_v
A meta-value to check whether T is a transformer type.
meta::rename_t< meta::transform_t< std::decay, meta::type_list< Entities... > >, std::tuple > tuple_of_entities_t
A helper meta-function to create an actual type of tuple with clauses/producers.
bool operator!=(const character_t &a, const character_t &b) noexcept
bool operator==(const character_t &a, const character_t &b) noexcept
auto space() noexcept
A factory function to create a clause that expects a space, extracts it and then skips it.
auto digit_p() noexcept
A factory function to create a digit_producer.
auto to_container()
A factory function to create a to_container_consumer.
auto caseless_symbol_p(char expected) noexcept
A factory function to create a caseless_symbol_producer.
auto any_symbol_p() noexcept
A factory function to create an any_symbol_producer.
auto force_only_this_alternative(Clauses &&... clauses)
An alternative that should be parsed correctly or the parsing of the whole alternatives clause should...
auto symbol(char expected) noexcept
A factory function to create a clause that expects the speficied symbol, extracts it and then skips i...
auto space_p() noexcept
A factory function to create a space_producer.
auto decimal_number_p() noexcept
A factory function to create a decimal_number_producer.
auto and_clause(Clauses &&... clauses)
A factory function to create an and_clause.
auto digit() noexcept
A factory function to create a clause that expects a decimal digit, extracts it and then skips it.
auto exact(string_view_t fragment)
A factory function that creates an instance of exact_fragment clause.
expected_t< typename Producer::result_type, parse_error_t > try_parse(string_view_t from, Producer producer)
Perform the parsing of the specified content by using specified value producer.
std::string make_error_description(const parse_error_t &error, string_view_t from)
Make textual description of error returned by try_parse function.
auto any_symbol_if_not_p(char sentinel) noexcept
A factory function to create a any_symbol_if_not_producer.
auto as_result() noexcept
A factory function to create a as_result_consumer.
constexpr digits_to_consume_t expected_digits(digits_to_consume_t::underlying_int_t total) noexcept
Create a limit for number of digits to be extracted.
auto maybe(Clauses &&... clauses)
A factory function to create an optional clause.
auto just(T value) noexcept(noexcept(impl::just_value_transformer_t< T >{value}))
A special transformer that replaces the produced value by a value specified by a user.
auto just_result(T value) noexcept(noexcept(impl::just_result_consumer_t< T >{value}))
A special consumer that replaces the produced value by a value specified by a user and sets that user...
auto skip() noexcept
A factory function to create a skip_consumer.
error_reason_t
Reason of parsing error.
@ unexpected_eof
Unexpected end of input is encontered when some character expected.
@ force_only_this_alternative_failed
A failure of parsing an alternative marked as "force only this alternative".
@ no_appropriate_alternative
None of alternatives was found in the input.
@ unexpected_character
Unexpected character is found in the input.
@ unconsumed_input
There are some unconsumed non-whitespace characters in the input after the completion of parsing.
@ pattern_not_found
Required pattern is not found in the input.
@ illegal_value_found
Illegal value was found in the input.
auto symbol_p(char expected) noexcept
A factory function to create a symbol_producer.
auto to_lower() noexcept
A factory function to create a to_lower_transformer.
auto caseless_symbol(char expected) noexcept
A factory function to create a clause that expects the speficied symbol, extracts it and then skips i...
auto alternatives(Clauses &&... clauses)
A factory function to create an alternatives clause.
auto convert(Converter &&converter)
A factory function to create convert_transformer.
auto produce(Clauses &&... clauses)
A factory function to create a producer that creates an instance of the target type by using specifie...
auto not_clause(Clauses &&... clauses)
A factory function to create a not_clause.
auto caseless_exact(string_view_t fragment)
A factory function that creates an instance of caseless_exact_fragment clause.
auto caseless_exact_p(string_view_t fragment)
A factory function that creates an instance of caseless_exact_fragment_producer.
auto symbol_from_range_p(char left, char right) noexcept
A factory function to create a symbol_from_range_producer.
constexpr std::size_t N
A special marker that means infinite repetitions.
auto hexdigit_p() noexcept
A factory function to create a hexdigit_producer.
auto exact_p(string_view_t fragment)
A factory function that creates an instance of exact_fragment_producer.
auto repeat(std::size_t min_occurences, std::size_t max_occurences, Clauses &&... clauses)
A factory function to create repetitor of subclauses.
auto non_negative_decimal_number_p() noexcept
A factory function to create a non_negative_decimal_number_producer.
auto symbol_from_range(char left, char right) noexcept
A factory function to create a clause that expects a symbol from specified range, extracts it and the...
auto hexadecimal_number_p() noexcept
A factory function to create a hexadecimal_number_producer.
auto sequence(Clauses &&... clauses)
A factory function to create a sequence of subclauses.
typename result_wrapper_for< T >::type result_wrapper_for_t
auto custom_consumer(F consumer)
A factory function to create a custom_consumer.
auto hexdigit() noexcept
A factory function to create a clause that expects a hexadecimal digit, extracts it and then skips it...
char to_lower_case(char ch)
constexpr bool all_of_v
Applies the predicate to all types from the list and return true only if all types satisty that predi...
typename impl::transform< Transform_F, From, type_list<> >::type transform_t
Applies a specified meta-function to every item from a specified type-list and return a new type-list...
typename impl::rename< From, To >::type rename_t
Allows to pass all template arguments from one type to another.
bool all_of(Tuple &&tuple, Predicate &&predicate)
bool any_of(Tuple &&tuple, Predicate &&predicate)
run_on_this_thread_settings_t< Traits > on_this_thread()
A special marker for the case when http_server must be run on the context of the current thread.
std::string_view string_view_t
nonstd::expected< T, E > expected_t
Definition expected.hpp:18
Helper for parsing integer values.
A predicate that allows extraction of any symbol.
constexpr bool operator()(const char) const noexcept
A special consumer that simply throws any value away.
void consume(Target_Type &, Value &&) const noexcept
A consumer for the case when the current value should be returned as the result for the producer at o...
void consume(Target_Type &dest, Value &&src) const
A predicate for cases where the case-insensitive match of expected and actual symbols is required.
One character extracted from the input stream.
A special base class to be used with clauses.
static constexpr entity_type_t entity_type
A special base class to be used with consumers.
static constexpr entity_type_t entity_type
A helper template for the detection of type to be produced as conversion procedure.
A metafunction that checks is Result_Type can be used as the result of transformation method.
A predicate for cases where char to be expected to be a decimal digit.
bool operator()(const char actual) const noexcept
A predicate for cases where char to be expected to be a hexadecimal digit.
bool operator()(const char actual) const noexcept
A preducate for symbol_producer_template that checks that a symbol is a space.
bool operator()(const char actual) const noexcept
A predicate for cases where mismatch with a particular symbol is required.
A predicate for cases where exact match of expected and actual symbols is required.
bool operator()(const char actual) const noexcept
A special base class to be used with producers.
static constexpr entity_type_t entity_type
A special wrapper for std::array type to be used inside a producer during the parsing.
A predicate for cases where a symbol should belong to specified range.
bool operator()(const char actual) const noexcept
A template for a consumer that stories values into a container.
A proxy for the creation of an appropriate to_lower_transformer.
result_type transform(input_type &&input) const noexcept
base_type::result_type transform(input_type &&input) const noexcept
result_type transform(input_type &&input) const noexcept
A helper template for checking a possibility to connect a producer with a transformer.
std::decay_t< decltype( std::declval< Producer & >().try_parse(std::declval< source_t & >())) > producer_result_t
std::decay_t< decltype( std::declval< Transformer & >().transform( std::move(*(std::declval< producer_result_t >())))) > transformation_result_t
static expected_t< Result_Type, parse_error_t > invoke(source_t &source, Transformer &transformer, expected_t< Input_Type, parse_error_t > &&input)
A helper template for calling transformation function.
static Result_Type invoke(source_t &, Transformer &transformer, expected_t< Input_Type, parse_error_t > &&input)
A special base class to be used with transformer-proxies.
A special base class to be used with transformers.
static constexpr entity_type_t entity_type
A consumer that stores a result value at the specified index in the result tuple.
void consume(Target_Type &&to, Value &&value)
A special type to be used in the case where there is no need to store produced value.
static void as_result(wrapped_type &, result_type &&) noexcept
static result_type && unwrap_value(wrapped_type &v)
static void to_container(wrapped_type &, value_type &&) noexcept
static void as_result(wrapped_type &to, result_type &&what)
static void to_container(wrapped_type &to, value_type &&what)
static void to_container(wrapped_type &to, wrapped_type &&what)
Special overload for the case when std::string should be added to another std::string.
static void to_container(wrapped_type &to, value_type &&what)
static void as_result(wrapped_type &to, result_type &&what)
static void as_result(wrapped_type &to, result_type &&what)
static void to_container(wrapped_type &to, value_type &&what)
A template with specializations for different kind of result values and for type nothing.
static result_type && unwrap_value(wrapped_type &v)
static void as_result(wrapped_type &to, result_type &&what)
A metafunction for detection of actual result_value_wrapper type for T.
The basic building block: a type for representation of a type list.
Various meta-functions for operating the content of a tuple.