2525#include < jsoncons/config/jsoncons_config.hpp>
2626#include < jsoncons/conversion_result.hpp>
2727#include < jsoncons/utility/more_type_traits.hpp>
28+ #include < jsoncons/utility/read_number.hpp>
2829
2930namespace jsoncons {
3031
@@ -576,6 +577,17 @@ struct to_bigint_result
576577 }
577578};
578579
580+ template <typename Allocator>
581+ class basic_bigint ;
582+
583+ template <typename CharT, typename Allocator>
584+ utility::to_number_result<CharT> to_bigint (const CharT* data, std::size_t length,
585+ basic_bigint<Allocator>& value, const Allocator& alloc);
586+
587+ template <typename CharT>
588+ utility::to_number_result<CharT> to_bigint (const CharT* data, std::size_t length,
589+ basic_bigint<std::allocator<uint64_t >>& value);
590+
579591/*
580592This implementation is based on Chapter 2 and Appendix A of
581593Ammeraal, L. (1996) Algorithms and Data Structures in C++,
@@ -630,7 +642,22 @@ class basic_bigint
630642 basic_bigint (const CharT* s, const Allocator& alloc = Allocator())
631643 : storage_(alloc)
632644 {
633- *this = parse (s, std::char_traits<CharT>::length (s), alloc);
645+ auto r = jsoncons::to_bigint (s, std::char_traits<CharT>::length (s), *this , alloc);
646+ if (r.ec != std::errc{})
647+ {
648+ JSONCONS_THROW (std::system_error ((int )r.ec , std::system_category ()));
649+ }
650+ }
651+
652+ template <typename CharT>
653+ basic_bigint (const CharT* s, size_type length, const Allocator& alloc = Allocator())
654+ : storage_(alloc)
655+ {
656+ auto r = jsoncons::to_bigint (s, length, *this , alloc);
657+ if (r.ec != std::errc{})
658+ {
659+ JSONCONS_THROW (std::system_error ((int )r.ec , std::system_category ()));
660+ }
634661 }
635662
636663 basic_bigint (const basic_bigint& other)
@@ -661,9 +688,13 @@ class basic_bigint
661688 }
662689
663690 template <typename StringViewLike,typename =typename std::enable_if<ext_traits::is_string_or_string_view<StringViewLike>::value>::type>
664- basic_bigint (const StringViewLike& sv )
691+ basic_bigint (const StringViewLike& s )
665692 {
666- *this = parse (sv.data (), sv.size ());
693+ auto r = jsoncons::to_bigint (s.data (), s.size (), *this );
694+ if (r.ec != std::errc{})
695+ {
696+ JSONCONS_THROW (std::system_error ((int )r.ec , std::system_category ()));
697+ }
667698 }
668699
669700 ~basic_bigint () noexcept
@@ -697,48 +728,47 @@ class basic_bigint
697728 }
698729
699730 template <typename CharT>
700- static basic_bigint<Allocator > parse (const std::basic_string<CharT>& s)
731+ static utility::to_number_result<CharT > parse (const std::basic_string<CharT>& s, basic_bigint<Allocator>& value )
701732 {
702- return parse (s.data (), s.size ());
733+ return parse<CharT> (s.data (), s.size (), value );
703734 }
704735
705736 template <typename CharT>
706- static basic_bigint<Allocator > parse (const CharT* s)
737+ static utility::to_number_result<CharT > parse (const CharT* s, basic_bigint<Allocator>& value )
707738 {
708- return parse (s, std::char_traits<CharT>::length (s));
709- }
710-
711- template <typename CharT>
712- static basic_bigint<Allocator> parse (const CharT* s, std::error_code& ec)
713- {
714- return parse (s, std::char_traits<CharT>::length (s), ec);
739+ auto r = parse (s, std::char_traits<CharT>::length (s), value);
740+ if (r.ec != std::errc{})
741+ {
742+ JSONCONS_THROW (std::system_error ((int )r.ec , std::system_category ()));
743+ }
715744 }
716745
717746 template <typename CharT>
718- static basic_bigint<Allocator> parse (const CharT* data, size_type length, const Allocator& alloc = Allocator())
747+ static utility::to_number_result<CharT> parse (const CharT* data, size_type length,
748+ basic_bigint<Allocator>& value, const Allocator& alloc = Allocator())
719749 {
720750 if (JSONCONS_UNLIKELY (length == 0 ))
721751 {
722- JSONCONS_THROW ( std::runtime_error ( std::string ( " Invalid argument " )) );
752+ return utility::to_number_result<CharT>(data, std::errc::invalid_argument );
723753 }
724754
725755 if (*data == ' -' )
726756 {
727- return parse (data+1 , length-1 , true , alloc);
757+ return parse (data+1 , length-1 , true , value, alloc);
728758 }
729759 else
730760 {
731- return parse (data, length, false , alloc);
761+ return parse (data, length, false , value, alloc);
732762 }
733763 }
734764
735765 template <typename CharT>
736- static basic_bigint<Allocator > parse (const CharT* data, size_type length,
737- bool neg, const Allocator& alloc = Allocator())
766+ static utility::to_number_result<CharT > parse (const CharT* data, size_type length,
767+ bool neg, basic_bigint<Allocator>& value, const Allocator& alloc = Allocator())
738768 {
739769 if (JSONCONS_UNLIKELY (length == 0 ))
740770 {
741- JSONCONS_THROW ( std::runtime_error ( std::string ( " Invalid argument " )) );
771+ return utility::to_number_result<CharT>(data, std::errc::invalid_argument );
742772 }
743773
744774 const CharT* last = data + length;
@@ -750,7 +780,8 @@ class basic_bigint
750780 }
751781 if (p == last)
752782 {
753- return basic_bigint{0 , alloc};
783+ value = std::move (basic_bigint{0 , alloc});
784+ return utility::to_number_result<CharT>(last, std::errc{});
754785 }
755786 size_type num_digits = last - data;
756787 size_type num_words;
@@ -775,7 +806,7 @@ class basic_bigint
775806 v = (v * 10u ) + (word_type)(c - ' 0' );
776807 break ;
777808 default :
778- JSONCONS_THROW ( std::runtime_error ( std::string ( " Invalid digit " ) + " \' " + ( char )c + " \' " ) );
809+ return utility::to_number_result<CharT>(data+i, std::errc::invalid_argument );
779810 }
780811 }
781812
@@ -790,46 +821,8 @@ class basic_bigint
790821 v.set_negative (true );
791822 }
792823
793- return v;
794- }
795-
796- template <typename CharT>
797- static basic_bigint<Allocator> parse (const CharT* data, size_type length, std::error_code& ec)
798- {
799- ec.clear ();
800- bool neg;
801- if (*data == ' -' )
802- {
803- neg = true ;
804- data++;
805- --length;
806- }
807- else
808- {
809- neg = false ;
810- }
811-
812- basic_bigint<Allocator> v = 0 ;
813- for (size_type i = 0 ; i < length; i++)
814- {
815- CharT c = data[i];
816- switch (c)
817- {
818- case ' 0' :case ' 1' :case ' 2' :case ' 3' :case ' 4' :case ' 5' :case ' 6' :case ' 7' :case ' 8' : case ' 9' :
819- v = (v * 10u ) + (word_type)(c - ' 0' );
820- break ;
821- default :
822- ec = std::make_error_code (std::errc::invalid_argument);
823- return basic_bigint<Allocator>{};
824- }
825- }
826-
827- if (neg)
828- {
829- v.set_negative (true );
830- }
831-
832- return v;
824+ value = std::move (v);
825+ return utility::to_number_result<CharT>(last, std::errc{});
833826 }
834827
835828 template <typename CharT>
@@ -1966,13 +1959,13 @@ class basic_bigint
19661959 }
19671960
19681961 template <typename CharT>
1969- friend to_bigint_result<CharT> to_bigint (const CharT* s, basic_bigint& val, int radix = 10 )
1962+ friend to_bigint_result<CharT> to_bigint (const CharT* s, basic_bigint& val, int radix)
19701963 {
19711964 return to_bigint (s, std::char_traits<CharT>::length (s), val, radix);
19721965 }
19731966
19741967 template <typename CharT>
1975- friend to_bigint_result<CharT> to_bigint (const CharT* s, size_type length, basic_bigint& val, int radix = 10 )
1968+ friend to_bigint_result<CharT> to_bigint (const CharT* s, size_type length, basic_bigint& val, int radix)
19761969 {
19771970 if (!(radix >= 2 && radix <= 16 ))
19781971 {
@@ -2075,7 +2068,116 @@ basic_bigint<Allocator> bsqrt(const basic_bigint<Allocator>& a)
20752068 return x < q ? x : q;
20762069}
20772070
2078- using bigint = basic_bigint<std::allocator<uint8_t >>;
2071+ template <typename CharT, typename Allocator>
2072+ utility::to_number_result<CharT> to_bigint (const CharT* data, std::size_t length,
2073+ basic_bigint<Allocator>& value, const Allocator& alloc)
2074+ {
2075+ if (JSONCONS_UNLIKELY (length == 0 ))
2076+ {
2077+ return utility::to_number_result<CharT>(data, std::errc::invalid_argument);
2078+ }
2079+
2080+ if (*data == ' -' )
2081+ {
2082+ return to_bigint (data+1 , length-1 , true , value, alloc);
2083+ }
2084+ else
2085+ {
2086+ return to_bigint (data, length, false , value, alloc);
2087+ }
2088+ }
2089+
2090+ template <typename CharT>
2091+ utility::to_number_result<CharT> to_bigint (const CharT* s, basic_bigint<std::allocator<uint64_t >>& value)
2092+ {
2093+ return to_bigint (s, std::char_traits<CharT>::length (s), value);
2094+ }
2095+
2096+ template <typename CharT>
2097+ utility::to_number_result<CharT> to_bigint (const CharT* data, std::size_t length,
2098+ basic_bigint<std::allocator<uint64_t >>& value)
2099+ {
2100+ if (JSONCONS_UNLIKELY (length == 0 ))
2101+ {
2102+ return utility::to_number_result<CharT>(data, std::errc::invalid_argument);
2103+ }
2104+
2105+ if (*data == ' -' )
2106+ {
2107+ return to_bigint (data+1 , length-1 , true , value, std::allocator<uint64_t >{});
2108+ }
2109+ else
2110+ {
2111+ return to_bigint (data, length, false , value, std::allocator<uint64_t >{});
2112+ }
2113+ }
2114+
2115+ template <typename CharT, typename Allocator>
2116+ utility::to_number_result<CharT> to_bigint (const CharT* data, std::size_t length,
2117+ bool neg, basic_bigint<Allocator>& value, const Allocator& alloc)
2118+ {
2119+ if (JSONCONS_UNLIKELY (length == 0 ))
2120+ {
2121+ return utility::to_number_result<CharT>(data, std::errc::invalid_argument);
2122+ }
2123+
2124+ using word_type = typename basic_bigint<Allocator>::word_type;
2125+
2126+ const CharT* last = data + length;
2127+ const CharT* p = data;
2128+
2129+ while (p < last && *p == ' 0' )
2130+ {
2131+ ++p;
2132+ }
2133+ if (p == last)
2134+ {
2135+ value = std::move (basic_bigint<Allocator>{0 , alloc});
2136+ return utility::to_number_result<CharT>(last, std::errc{});
2137+ }
2138+ std::size_t num_digits = last - data;
2139+ std::size_t num_words;
2140+ if (length < 10 )
2141+ {
2142+ num_words = 1 ;
2143+ }
2144+ else
2145+ {
2146+ std::size_t num_bits = (std::size_t )(((num_digits*detail::bits_per_digit[10 ]) >> 10 ) + 1 );
2147+ num_words = (num_bits+63 ) >> 6 ;
2148+ }
2149+
2150+ basic_bigint<Allocator> v (0 , alloc);
2151+ v.reserve (num_words);
2152+ for (std::size_t i = 0 ; i < length; i++)
2153+ {
2154+ CharT c = data[i];
2155+ switch (c)
2156+ {
2157+ case ' 0' :case ' 1' :case ' 2' :case ' 3' :case ' 4' :case ' 5' :case ' 6' :case ' 7' :case ' 8' : case ' 9' :
2158+ v = (v * 10u ) + (word_type)(c - ' 0' );
2159+ break ;
2160+ default :
2161+ return utility::to_number_result<CharT>(data+i, std::errc::invalid_argument);
2162+ }
2163+ }
2164+
2165+ // auto view = v.get_storage_view();
2166+ // if (num_words != view.size())
2167+ // {
2168+ // std::cout << "Unexpected num_words! num_words: " << num_words << ", " << num_words << ", size: " << view.size() << "\n";
2169+ // }
2170+
2171+ if (neg)
2172+ {
2173+ v.set_negative (true );
2174+ }
2175+
2176+ value = std::move (v);
2177+ return utility::to_number_result<CharT>(last, std::errc{});
2178+ }
2179+
2180+ using bigint = basic_bigint<std::allocator<uint64_t >>;
20792181
20802182} // namespace jsoncons
20812183
0 commit comments