@@ -334,7 +334,16 @@ namespace bencode {
334334 std::end (t);
335335 };
336336
337- template <typename Integer>
337+ template <typename T>
338+ concept sequence = iterable<T> && !std::convertible_to<T, std::string_view>;
339+
340+ template <typename T>
341+ concept mapping = sequence<T> && requires {
342+ typename T::key_type;
343+ typename T::mapped_type;
344+ };
345+
346+ template <std::integral Integer>
338347 inline void check_overflow (Integer value, Integer digit) {
339348 using limits = std::numeric_limits<Integer>;
340349 // Wrap `max` in parentheses to work around <windows.h> #defining `max`.
@@ -343,7 +352,7 @@ namespace bencode {
343352 throw std::overflow_error (" integer overflow" );
344353 }
345354
346- template <typename Integer>
355+ template <std::integral Integer>
347356 inline void check_underflow (Integer value, Integer digit) {
348357 using limits = std::numeric_limits<Integer>;
349358 // As above, work around <windows.h> #defining `min`.
@@ -352,7 +361,7 @@ namespace bencode {
352361 throw std::underflow_error (" integer underflow" );
353362 }
354363
355- template <typename Integer>
364+ template <std::integral Integer>
356365 inline void
357366 check_over_underflow (Integer value, Integer digit, Integer sgn) {
358367 if (sgn == 1 )
@@ -361,7 +370,7 @@ namespace bencode {
361370 check_underflow (value, digit);
362371 }
363372
364- template <typename Integer, typename Iter>
373+ template <std::integral Integer, std::input_iterator Iter>
365374 inline Integer
366375 decode_digits (Iter &begin, Iter end, [[maybe_unused]] Integer sgn = 1 ) {
367376 assert (sgn == 1 || (std::is_signed_v<Integer> &&
@@ -411,7 +420,7 @@ namespace bencode {
411420 return value;
412421 }
413422
414- template <typename Integer, typename Iter>
423+ template <std::integral Integer, std::input_iterator Iter>
415424 Integer decode_int (Iter &begin, Iter end) {
416425 assert (*begin == u8 ' i' );
417426 ++begin;
@@ -433,58 +442,43 @@ namespace bencode {
433442 return value;
434443 }
435444
436- template <typename String>
437- class str_reader {
438- public:
439- template <typename Iter, typename Size>
440- inline String operator ()(Iter &begin, Iter end, Size len) {
441- return call (
442- begin, end, len,
443- typename std::iterator_traits<Iter>::iterator_category ()
444- );
445- }
446- private:
447- template <typename Iter, typename Size>
448- String call (Iter &begin, Iter end, Size len, std::forward_iterator_tag) {
449- if (std::distance (begin, end) < static_cast <std::ptrdiff_t >(len)) {
450- begin = end;
451- throw end_of_input_error ();
452- }
453-
454- auto orig = begin;
455- std::advance (begin, len);
456- return String (orig, begin);
445+ template <typename String, std::forward_iterator Iter>
446+ String decode_chars (Iter &begin, Iter end, std::size_t len) {
447+ if (std::distance (begin, end) < static_cast <std::ptrdiff_t >(len)) {
448+ begin = end;
449+ throw end_of_input_error ();
457450 }
458451
459- template <typename Iter, typename Size>
460- String call (Iter &begin, Iter end, Size len, std::input_iterator_tag) {
461- String value (len, 0 );
462- for (Size i = 0 ; i < len; i++) {
463- if (begin == end)
464- throw end_of_input_error ();
465- value[i] = *begin++;
466- }
467- return value;
468- }
469- };
452+ auto orig = begin;
453+ std::advance (begin, len);
454+ return String (orig, begin);
455+ }
470456
471- template <>
472- class str_reader <std::string_view> {
473- public:
474- template <typename Iter, typename Size>
475- std::string_view operator ()(Iter &begin, Iter end, Size len) {
476- if (std::distance (begin, end) < static_cast <std::ptrdiff_t >(len)) {
477- begin = end;
457+ template <typename String, std::input_iterator Iter>
458+ inline String decode_chars (Iter &begin, Iter end, std::size_t len) {
459+ String value (len, 0 );
460+ for (std::size_t i = 0 ; i < len; i++) {
461+ if (begin == end)
478462 throw end_of_input_error ();
479- }
463+ value[i] = *begin++;
464+ }
465+ return value;
466+ }
480467
481- std::string_view value (&*begin, len);
482- std::advance (begin, len);
483- return value;
468+ template <typename String, std::contiguous_iterator Iter>
469+ requires is_view<String>
470+ String decode_chars (Iter &begin, Iter end, std::size_t len) {
471+ if (std::distance (begin, end) < static_cast <std::ptrdiff_t >(len)) {
472+ begin = end;
473+ throw end_of_input_error ();
484474 }
485- };
486475
487- template <typename String, typename Iter>
476+ std::string_view value (&*begin, len);
477+ std::advance (begin, len);
478+ return value;
479+ }
480+
481+ template <typename String, std::input_iterator Iter>
488482 String decode_str (Iter &begin, Iter end) {
489483 assert (std::isdigit (*begin));
490484 std::size_t len = decode_digits<std::size_t >(begin, end);
@@ -494,10 +488,10 @@ namespace bencode {
494488 throw syntax_error (" expected ':' token" );
495489 ++begin;
496490
497- return str_reader <String>{} (begin, end, len);
491+ return decode_chars <String>(begin, end, len);
498492 }
499493
500- template <typename Data, typename Iter>
494+ template <typename Data, std::input_iterator Iter>
501495 Data do_decode (Iter &begin, Iter end, bool all) {
502496 using Traits = variant_traits_for<Data>;
503497 using Integer = typename Data::integer;
@@ -600,7 +594,7 @@ namespace bencode {
600594
601595 }
602596
603- template <typename Data, typename Iter>
597+ template <typename Data, std::input_iterator Iter>
604598 inline Data basic_decode (Iter begin, Iter end) {
605599 return detail::do_decode<Data>(begin, end, true );
606600 }
@@ -626,7 +620,7 @@ namespace bencode {
626620 return detail::do_decode<Data>(s, e, true );
627621 }
628622
629- template <typename Data, typename Iter>
623+ template <typename Data, std::input_iterator Iter>
630624 inline Data basic_decode_some (Iter &begin, Iter end) {
631625 return detail::do_decode<Data>(begin, end, false );
632626 }
@@ -755,34 +749,22 @@ namespace bencode {
755749 std::copy (value.begin (), value.end (), iter);
756750 }
757751
758- template <detail::output_iterator_ref Iter, typename T >
759- void encode (Iter &&iter, const std::vector<T> &value) {
752+ template <detail::output_iterator_ref Iter, detail::sequence Seq >
753+ void encode (Iter &&iter, const Seq &value) {
760754 detail::list_encoder e (iter);
761755 for (auto &&i : value)
762756 e.add (i);
763757 }
764758
765- template <detail::output_iterator_ref Iter, typename T >
766- void encode (Iter &&iter, const std::map<string, T> &value) {
759+ template <detail::output_iterator_ref Iter, detail::mapping Map >
760+ void encode (Iter &&iter, const Map &value) {
767761 detail::dict_encoder e (iter);
768762 for (auto &&i : value)
769763 e.add (i.first , i.second );
770764 }
771765
772- template <detail::output_iterator_ref Iter, typename T>
773- void encode (Iter &&iter, const std::map<string_view, T> &value) {
774- detail::dict_encoder e (iter);
775- for (auto &&i : value)
776- e.add (i.first , i.second );
777- }
778-
779- template <detail::output_iterator_ref Iter, typename K, typename V>
780- void encode (Iter &&iter, const map_proxy<K, V> &value) {
781- encode (iter, *value);
782- }
783-
784766 namespace detail {
785- template <std::input_or_output_iterator Iter>
767+ template <detail::output_iterator_ref Iter>
786768 class encode_visitor {
787769 public:
788770 inline encode_visitor (Iter &iter) : iter(iter) {}
0 commit comments