3939#include < limits>
4040#include < iosfwd>
4141#include < type_traits>
42+ #include < utility>
4243
4344namespace boost {
4445namespace static_strings {
@@ -549,13 +550,21 @@ inline
549550static_string<N>
550551to_static_string_int_impl (Integer value) noexcept
551552{
553+ using size_type = typename static_string<N>::size_type;
552554 static_string<N> result;
553- char * const digits_end = result.data () + N;
554- char * const digits_begin = integer_to_string<std::char_traits<char >, Integer>(
555- digits_end, value, std::is_signed<Integer>{});
556- result.set_size (digits_end - digits_begin);
557- std::char_traits<char >::move (result.data (), digits_begin, result.size ());
558- result.term ();
555+ result.resize_and_overwrite (
556+ N,
557+ [&](char * buffer, size_type) -> size_type
558+ {
559+ char * const digits_end = buffer + N;
560+ char * const digits_begin = integer_to_string<std::char_traits<char >, Integer>(
561+ digits_end, value, std::is_signed<Integer>{});
562+ const size_type len = digits_end - digits_begin;
563+ std::char_traits<char >::move (buffer, digits_begin, len);
564+ return len;
565+ }
566+ );
567+
559568 return result;
560569}
561570
@@ -565,13 +574,20 @@ inline
565574static_wstring<N>
566575to_static_wstring_int_impl (Integer value) noexcept
567576{
577+ using size_type = typename static_wstring<N>::size_type;
568578 static_wstring<N> result;
569- wchar_t * const digits_end = result.data () + N;
570- wchar_t * const digits_begin = integer_to_wstring<std::char_traits<wchar_t >, Integer>(
571- digits_end, value, std::is_signed<Integer>{});
572- result.set_size (digits_end - digits_begin);
573- std::char_traits<wchar_t >::move (result.data (), digits_begin, result.size ());
574- result.term ();
579+ result.resize_and_overwrite (
580+ N,
581+ [&](wchar_t * buffer, size_type) -> size_type
582+ {
583+ wchar_t * const digits_end = buffer + N;
584+ wchar_t * const digits_begin = integer_to_wstring<std::char_traits<wchar_t >, Integer>(
585+ digits_end, value, std::is_signed<Integer>{});
586+ const size_type len = digits_end - digits_begin;
587+ std::char_traits<wchar_t >::move (buffer, digits_begin, len);
588+ return len;
589+ }
590+ );
575591 return result;
576592}
577593#endif
@@ -597,27 +613,34 @@ inline
597613static_string<N>
598614to_static_string_float_impl (double value) noexcept
599615{
616+ using size_type = typename static_string<N>::size_type;
600617 // we have to assume here that no reasonable implementation
601618 // will require more than 2^63 chars to represent a float value.
602619 const long long narrow =
603620 static_cast <long long >(N);
604621 static_string<N> result;
605- // we know that a formatting error will not occur, so
606- // we assume that the result is always positive
607- std::size_t length = std::snprintf (result.data (), N + 1 , " %f" , value);
608- if (length > N)
609- {
610- // the + 4 is for the decimal, 'e',
611- // its sign, and the sign of the integral portion
612- const int reserved_count =
613- (std::max)(2 , count_digits (
614- std::numeric_limits<double >::max_exponent10)) + 4 ;
615- const int precision = narrow > reserved_count ?
616- N - reserved_count : 0 ;
617- // switch to scientific notation
618- length = std::snprintf (result.data (), N + 1 , " %.*e" , precision, value);
619- }
620- result.set_size (length);
622+ result.resize_and_overwrite (
623+ N,
624+ [&](char * buffer, size_type) -> size_type
625+ {
626+ // we know that a formatting error will not occur, so
627+ // we assume that the result is always positive
628+ std::size_t length = std::snprintf (buffer, N + 1 , " %f" , value);
629+ if (length > N)
630+ {
631+ // the + 4 is for the decimal, 'e',
632+ // its sign, and the sign of the integral portion
633+ const int reserved_count =
634+ (std::max)(2 , count_digits (
635+ std::numeric_limits<double >::max_exponent10)) + 4 ;
636+ const int precision = narrow > reserved_count ?
637+ N - reserved_count : 0 ;
638+ // switch to scientific notation
639+ length = std::snprintf (buffer, N + 1 , " %.*e" , precision, value);
640+ }
641+ return length;
642+ }
643+ );
621644 return result;
622645}
623646
@@ -626,29 +649,36 @@ inline
626649static_string<N>
627650to_static_string_float_impl (long double value) noexcept
628651{
652+ using size_type = typename static_string<N>::size_type;
629653 // we have to assume here that no reasonable implementation
630654 // will require more than 2^63 chars to represent a float value.
631655 const long long narrow =
632656 static_cast <long long >(N);
633657 static_string<N> result;
634- // snprintf returns the number of characters
635- // that would have been written
636- // we know that a formatting error will not occur, so
637- // we assume that the result is always positive
638- std::size_t length = std::snprintf (result.data (), N + 1 , " %Lf" , value);
639- if (length > N)
640- {
641- // the + 4 is for the decimal, 'e',
642- // its sign, and the sign of the integral portion
643- const int reserved_count =
644- (std::max)(2 , count_digits (
645- std::numeric_limits<long double >::max_exponent10)) + 4 ;
646- const int precision = narrow > reserved_count ?
647- N - reserved_count : 0 ;
648- // switch to scientific notation
649- length = std::snprintf (result.data (), N + 1 , " %.*Le" , precision, value);
650- }
651- result.set_size (length);
658+ result.resize_and_overwrite (
659+ N,
660+ [&](char * buffer, size_type)->size_type
661+ {
662+ // snprintf returns the number of characters
663+ // that would have been written
664+ // we know that a formatting error will not occur, so
665+ // we assume that the result is always positive
666+ std::size_t length = std::snprintf (buffer, N + 1 , " %Lf" , value);
667+ if (length > N)
668+ {
669+ // the + 4 is for the decimal, 'e',
670+ // its sign, and the sign of the integral portion
671+ const int reserved_count =
672+ (std::max)(2 , count_digits (
673+ std::numeric_limits<long double >::max_exponent10)) + 4 ;
674+ const int precision = narrow > reserved_count ?
675+ N - reserved_count : 0 ;
676+ // switch to scientific notation
677+ length = std::snprintf (buffer, N + 1 , " %.*Le" , precision, value);
678+ }
679+ return length;
680+ }
681+ );
652682 return result;
653683}
654684
@@ -658,34 +688,41 @@ inline
658688static_wstring<N>
659689to_static_wstring_float_impl (double value) noexcept
660690{
691+ using size_type = typename static_wstring<N>::size_type;
661692 // we have to assume here that no reasonable implementation
662693 // will require more than 2^63 chars to represent a float value.
663694 const long long narrow =
664695 static_cast <long long >(N);
665696 static_wstring<N> result;
666- // swprintf returns a negative number if it can't
667- // fit all the characters in the buffer.
668- // mingw has a non-standard swprintf, so
669- // this just covers all the bases. short
670- // circuit evaluation will ensure that the
671- // second operand is not evaluated on conforming
672- // implementations.
673- long long num_written =
674- std::swprintf (result.data (), N + 1 , L" %f" , value);
675- if (num_written < 0 ||
676- num_written > narrow)
677- {
678- // the + 4 is for the decimal, 'e',
679- // its sign, and the sign of the integral portion
680- const int reserved_count =
681- (std::max)(2 , count_digits (
682- std::numeric_limits<double >::max_exponent10)) + 4 ;
683- const int precision = narrow > reserved_count ?
684- N - reserved_count : 0 ;
685- // switch to scientific notation
686- num_written = std::swprintf (result.data (), N + 1 , L" %.*e" , precision, value);
687- }
688- result.set_size (static_cast <std::size_t >(num_written));
697+ result.resize_and_overwrite (
698+ N,
699+ [&](wchar_t * buffer, size_type) -> size_type
700+ {
701+ // swprintf returns a negative number if it can't
702+ // fit all the characters in the buffer.
703+ // mingw has a non-standard swprintf, so
704+ // this just covers all the bases. short
705+ // circuit evaluation will ensure that the
706+ // second operand is not evaluated on conforming
707+ // implementations.
708+ long long num_written =
709+ std::swprintf (buffer, N + 1 , L" %f" , value);
710+ if (num_written < 0 ||
711+ num_written > narrow)
712+ {
713+ // the + 4 is for the decimal, 'e',
714+ // its sign, and the sign of the integral portion
715+ const int reserved_count =
716+ (std::max)(2 , count_digits (
717+ std::numeric_limits<double >::max_exponent10)) + 4 ;
718+ const int precision = narrow > reserved_count ?
719+ N - reserved_count : 0 ;
720+ // switch to scientific notation
721+ num_written = std::swprintf (buffer, N + 1 , L" %.*e" , precision, value);
722+ }
723+ return num_written;
724+ }
725+ );
689726 return result;
690727}
691728
@@ -694,34 +731,41 @@ inline
694731static_wstring<N>
695732to_static_wstring_float_impl (long double value) noexcept
696733{
734+ using size_type = typename static_wstring<N>::size_type;
697735 // we have to assume here that no reasonable implementation
698736 // will require more than 2^63 chars to represent a float value.
699737 const long long narrow =
700738 static_cast <long long >(N);
701739 static_wstring<N> result;
702- // swprintf returns a negative number if it can't
703- // fit all the characters in the buffer.
704- // mingw has a non-standard swprintf, so
705- // this just covers all the bases. short
706- // circuit evaluation will ensure that the
707- // second operand is not evaluated on conforming
708- // implementations.
709- long long num_written =
710- std::swprintf (result.data (), N + 1 , L" %Lf" , value);
711- if (num_written < 0 ||
712- num_written > narrow)
713- {
714- // the + 4 is for the decimal, 'e',
715- // its sign, and the sign of the integral portion
716- const int reserved_count =
717- (std::max)(2 , count_digits (
718- std::numeric_limits<long double >::max_exponent10)) + 4 ;
719- const int precision = narrow > reserved_count ?
720- N - reserved_count : 0 ;
721- // switch to scientific notation
722- num_written = std::swprintf (result.data (), N + 1 , L" %.*Le" , precision, value);
723- }
724- result.set_size (static_cast <std::size_t >(num_written));
740+ result.resize_and_overwrite (
741+ N,
742+ [&](wchar_t * buffer, size_type) -> size_type
743+ {
744+ // swprintf returns a negative number if it can't
745+ // fit all the characters in the buffer.
746+ // mingw has a non-standard swprintf, so
747+ // this just covers all the bases. short
748+ // circuit evaluation will ensure that the
749+ // second operand is not evaluated on conforming
750+ // implementations.
751+ long long num_written =
752+ std::swprintf (buffer, N + 1 , L" %Lf" , value);
753+ if (num_written < 0 ||
754+ num_written > narrow)
755+ {
756+ // the + 4 is for the decimal, 'e',
757+ // its sign, and the sign of the integral portion
758+ const int reserved_count =
759+ (std::max)(2 , count_digits (
760+ std::numeric_limits<long double >::max_exponent10)) + 4 ;
761+ const int precision = narrow > reserved_count ?
762+ N - reserved_count : 0 ;
763+ // switch to scientific notation
764+ num_written = std::swprintf (buffer, N + 1 , L" %.*Le" , precision, value);
765+ }
766+ return num_written;
767+ }
768+ );
725769 return result;
726770}
727771#endif
@@ -930,36 +974,6 @@ class basic_static_string
930974 template <std::size_t , class , class >
931975 friend class basic_static_string ;
932976
933- template <std::size_t P, typename Integer>
934- friend
935- static_string<P>
936- detail::to_static_string_int_impl (Integer value) noexcept ;
937-
938- template <std::size_t P>
939- friend
940- static_string<P>
941- detail::to_static_string_float_impl (double value) noexcept ;
942-
943- template <std::size_t P>
944- friend
945- static_string<P>
946- detail::to_static_string_float_impl (long double value) noexcept ;
947-
948- #ifdef BOOST_STATIC_STRING_HAS_WCHAR
949- template <std::size_t P, typename Integer>
950- friend static_wstring<P>
951- detail::to_static_wstring_int_impl (Integer value) noexcept ;
952-
953- template <std::size_t P>
954- friend
955- static_wstring<P>
956- detail::to_static_wstring_float_impl (double value) noexcept ;
957-
958- template <std::size_t P>
959- friend
960- static_wstring<P>
961- detail::to_static_wstring_float_impl (long double value) noexcept ;
962- #endif
963977public:
964978 // --------------------------------------------------------------------------
965979 //
@@ -3751,6 +3765,31 @@ class basic_static_string
37513765 size_type n,
37523766 value_type c);
37533767
3768+ /* *
3769+ Resize the string and overwrite its contents.
3770+
3771+ Resizes the string to contain `n` characters, and uses the
3772+ provided function object `op` to overwrite the string contents.
3773+ The function object is called with two arguments: a pointer to
3774+ the string internal buffer, and the size of the string. The
3775+ function object shall return the number of characters written to
3776+ the buffer, which shall be less than or equal to `n`. The string
3777+ size is set to the value returned by the function object.
3778+
3779+ @par Exception Safety
3780+
3781+ Strong guarantee. However, if an exception is thrown by
3782+ `std::move(op)(p, count)`, the behavior is undefined.
3783+
3784+ @throw std::length_error `n > max_size()`
3785+ */
3786+ template <typename Operation>
3787+ BOOST_STATIC_STRING_CPP14_CONSTEXPR
3788+ void
3789+ resize_and_overwrite (
3790+ size_type n,
3791+ Operation op);
3792+
37543793 /* * Swap two strings.
37553794
37563795 Swaps the contents of the string and `s`.
@@ -6701,6 +6740,26 @@ resize(size_type n, value_type c)
67016740 term ();
67026741}
67036742
6743+ template <std::size_t N, typename CharT, typename Traits>
6744+ template <typename Operation>
6745+ BOOST_STATIC_STRING_CPP14_CONSTEXPR
6746+ void
6747+ basic_static_string<N, CharT, Traits>::
6748+ resize_and_overwrite (
6749+ size_type n,
6750+ Operation op)
6751+ {
6752+ if (n > max_size ()) {
6753+ detail::throw_exception<std::length_error>(" n > max_size() in resize_and_overwrite()" );
6754+ }
6755+
6756+ CharT* p = data ();
6757+ const auto new_size = std::move (op)(p, n);
6758+ BOOST_STATIC_STRING_ASSERT (new_size >= 0 && size_type (new_size) <= n);
6759+ this ->set_size (size_type (new_size));
6760+ term ();
6761+ }
6762+
67046763template <std::size_t N, typename CharT, typename Traits>
67056764BOOST_STATIC_STRING_CPP14_CONSTEXPR
67066765void
0 commit comments