Skip to content

Commit 15a1e18

Browse files
committed
Don't use an additional buffer in the arithmetic conversions
In the case of the floating point conversions, this effectively avoids a copy of the buffer contents. In the case of the integer conversions, it doesn't eliminate the copy, but still removes the extra buffer. This fixes issue #65.
1 parent 7a53b7f commit 15a1e18

File tree

1 file changed

+69
-34
lines changed

1 file changed

+69
-34
lines changed

include/boost/static_string/static_string.hpp

Lines changed: 69 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -549,11 +549,14 @@ inline
549549
static_string<N>
550550
to_static_string_int_impl(Integer value) noexcept
551551
{
552-
char buffer[N];
553-
const auto digits_end = std::end(buffer);
554-
const auto digits_begin = integer_to_string<std::char_traits<char>, Integer>(
552+
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>(
555555
digits_end, value, std::is_signed<Integer>{});
556-
return static_string<N>(digits_begin, std::distance(digits_begin, digits_end));
556+
result.set_size(digits_end - digits_begin);
557+
std::char_traits<char>::move(result.data(), digits_begin, result.size());
558+
result.term();
559+
return result;
557560
}
558561

559562
#ifdef BOOST_STATIC_STRING_HAS_WCHAR
@@ -562,11 +565,14 @@ inline
562565
static_wstring<N>
563566
to_static_wstring_int_impl(Integer value) noexcept
564567
{
565-
wchar_t buffer[N];
566-
const auto digits_end = std::end(buffer);
567-
const auto digits_begin = integer_to_wstring<std::char_traits<wchar_t>, Integer>(
568+
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>(
568571
digits_end, value, std::is_signed<Integer>{});
569-
return static_wstring<N>(digits_begin, std::distance(digits_begin, digits_end));
572+
result.set_size(digits_end - digits_begin);
573+
std::char_traits<wchar_t>::move(result.data(), digits_begin, result.size());
574+
result.term();
575+
return result;
570576
}
571577
#endif
572578

@@ -595,11 +601,11 @@ to_static_string_float_impl(double value) noexcept
595601
// will require more than 2^63 chars to represent a float value.
596602
const long long narrow =
597603
static_cast<long long>(N);
598-
// extra one needed for null terminator
599-
char buffer[N + 1];
604+
static_string<N> result;
600605
// we know that a formatting error will not occur, so
601606
// we assume that the result is always positive
602-
if (std::size_t(std::snprintf(buffer, N + 1, "%f", value)) > N)
607+
std::size_t length = std::snprintf(result.data(), N + 1, "%f", value);
608+
if (length > N)
603609
{
604610
// the + 4 is for the decimal, 'e',
605611
// its sign, and the sign of the integral portion
@@ -609,10 +615,10 @@ to_static_string_float_impl(double value) noexcept
609615
const int precision = narrow > reserved_count ?
610616
N - reserved_count : 0;
611617
// switch to scientific notation
612-
std::snprintf(buffer, N + 1, "%.*e", precision, value);
618+
length = std::snprintf(result.data(), N + 1, "%.*e", precision, value);
613619
}
614-
// this will not throw
615-
return static_string<N>(buffer);
620+
result.set_size(length);
621+
return result;
616622
}
617623

618624
template<std::size_t N>
@@ -624,13 +630,13 @@ to_static_string_float_impl(long double value) noexcept
624630
// will require more than 2^63 chars to represent a float value.
625631
const long long narrow =
626632
static_cast<long long>(N);
627-
// extra one needed for null terminator
628-
char buffer[N + 1];
633+
static_string<N> result;
629634
// snprintf returns the number of characters
630635
// that would have been written
631636
// we know that a formatting error will not occur, so
632637
// we assume that the result is always positive
633-
if (std::size_t(std::snprintf(buffer, N + 1, "%Lf", value)) > N)
638+
std::size_t length = std::snprintf(result.data(), N + 1, "%Lf", value);
639+
if (length > N)
634640
{
635641
// the + 4 is for the decimal, 'e',
636642
// its sign, and the sign of the integral portion
@@ -640,10 +646,10 @@ to_static_string_float_impl(long double value) noexcept
640646
const int precision = narrow > reserved_count ?
641647
N - reserved_count : 0;
642648
// switch to scientific notation
643-
std::snprintf(buffer, N + 1, "%.*Le", precision, value);
649+
length = std::snprintf(result.data(), N + 1, "%.*Le", precision, value);
644650
}
645-
// this will not throw
646-
return static_string<N>(buffer);
651+
result.set_size(length);
652+
return result;
647653
}
648654

649655
#ifdef BOOST_STATIC_STRING_HAS_WCHAR
@@ -656,17 +662,16 @@ to_static_wstring_float_impl(double value) noexcept
656662
// will require more than 2^63 chars to represent a float value.
657663
const long long narrow =
658664
static_cast<long long>(N);
659-
// extra one needed for null terminator
660-
wchar_t buffer[N + 1];
665+
static_wstring<N> result;
661666
// swprintf returns a negative number if it can't
662667
// fit all the characters in the buffer.
663668
// mingw has a non-standard swprintf, so
664669
// this just covers all the bases. short
665670
// circuit evaluation will ensure that the
666671
// second operand is not evaluated on conforming
667672
// implementations.
668-
const long long num_written =
669-
std::swprintf(buffer, N + 1, L"%f", value);
673+
long long num_written =
674+
std::swprintf(result.data(), N + 1, L"%f", value);
670675
if (num_written < 0 ||
671676
num_written > narrow)
672677
{
@@ -678,10 +683,10 @@ to_static_wstring_float_impl(double value) noexcept
678683
const int precision = narrow > reserved_count ?
679684
N - reserved_count : 0;
680685
// switch to scientific notation
681-
std::swprintf(buffer, N + 1, L"%.*e", precision, value);
686+
num_written = std::swprintf(result.data(), N + 1, L"%.*e", precision, value);
682687
}
683-
// this will not throw
684-
return static_wstring<N>(buffer);
688+
result.set_size(static_cast<std::size_t>(num_written));
689+
return result;
685690
}
686691

687692
template<std::size_t N>
@@ -693,17 +698,16 @@ to_static_wstring_float_impl(long double value) noexcept
693698
// will require more than 2^63 chars to represent a float value.
694699
const long long narrow =
695700
static_cast<long long>(N);
696-
// extra one needed for null terminator
697-
wchar_t buffer[N + 1];
701+
static_wstring<N> result;
698702
// swprintf returns a negative number if it can't
699703
// fit all the characters in the buffer.
700704
// mingw has a non-standard swprintf, so
701705
// this just covers all the bases. short
702706
// circuit evaluation will ensure that the
703707
// second operand is not evaluated on conforming
704708
// implementations.
705-
const long long num_written =
706-
std::swprintf(buffer, N + 1, L"%Lf", value);
709+
long long num_written =
710+
std::swprintf(result.data(), N + 1, L"%Lf", value);
707711
if (num_written < 0 ||
708712
num_written > narrow)
709713
{
@@ -715,10 +719,10 @@ to_static_wstring_float_impl(long double value) noexcept
715719
const int precision = narrow > reserved_count ?
716720
N - reserved_count : 0;
717721
// switch to scientific notation
718-
std::swprintf(buffer, N + 1, L"%.*Le", precision, value);
722+
num_written = std::swprintf(result.data(), N + 1, L"%.*Le", precision, value);
719723
}
720-
// this will not throw
721-
return static_wstring<N>(buffer);
724+
result.set_size(static_cast<std::size_t>(num_written));
725+
return result;
722726
}
723727
#endif
724728

@@ -925,6 +929,37 @@ class basic_static_string
925929
private:
926930
template<std::size_t, class, class>
927931
friend class basic_static_string;
932+
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
928963
public:
929964
//--------------------------------------------------------------------------
930965
//

0 commit comments

Comments
 (0)