Upload
roman-orlov
View
3.032
Download
6
Embed Size (px)
Citation preview
1/25
Догнать и перегнать boost::lexical_castБыстрое преобразование целого числа в строку
Орлов Роман
18 февраля 2017 г.
Орлов Роман Догнать и перегнать boost::lexical_cast
2/25
Готовые решения
Стандартная библиотека• семейство printf (sprintf, snprintf)• потоки ввода/вывода (std::basic_stringstream)• std::to_string• std::to_chars [C++17]
Boost• Lexical Cast• Format• Iostreams• Spirit Karma
А также fmtlib, FastFormat, Qt и другие…
Орлов Роман Догнать и перегнать boost::lexical_cast
3/25
Готовые решенияБез динамического выделения памяти
Стандартная библиотека• семейство printf (sprintf, snprintf)• потоки ввода/вывода (std::basic_stringstream)• std::to_string• std::to_chars [C++17]
Boost• Lexical Cast• Format• Iostreams• Spirit Karma
Орлов Роман Догнать и перегнать boost::lexical_cast
3/25
Готовые решенияБез динамического выделения памяти
Стандартная библиотека• семейство printf (sprintf, snprintf)• потоки ввода/вывода (std::basic_stringstream)• std::to_string• std::to_chars [C++17]
Boost• Lexical Cast• Format• Iostreams• Spirit Karma
Орлов Роман Догнать и перегнать boost::lexical_cast
3/25
Готовые решенияБез динамического выделения памяти
Стандартная библиотека• семейство printf (sprintf, snprintf)• потоки ввода/вывода (std::basic_stringstream)• std::to_string• std::to_chars [C++17]
Boost• Lexical Cast• Format• Iostreams• Spirit Karma
Орлов Роман Догнать и перегнать boost::lexical_cast
3/25
Готовые решенияБез динамического выделения памяти
Стандартная библиотека• семейство printf (sprintf, snprintf)• потоки ввода/вывода (std::basic_stringstream)• std::to_string• std::to_chars [C++17]
Boost• Lexical Cast• Format• Iostreams• Spirit Karma
Орлов Роман Догнать и перегнать boost::lexical_cast
3/25
Готовые решенияБез динамического выделения памяти
Стандартная библиотека• семейство printf (sprintf, snprintf)• потоки ввода/вывода (std::basic_stringstream)• std::to_string• std::to_chars [C++17]
Boost• Lexical Cast• Format• Iostreams ???• Spirit Karma
Орлов Роман Догнать и перегнать boost::lexical_cast
4/25
Производительность boost::lexical_cast
Для всех xi = 100, i = 1, . . . , 10000
Clang 3.6.0 GCC 6.1.10
50
100
150
179
140
89
38
1728
14
t,мс
lexical_cast std::stringstream+ctor std::stringstream printf
Орлов Роман Догнать и перегнать boost::lexical_cast
5/25
Под капотом boost::lexical_castИтерационное решение
inline CharT* main_convert_loop() BOOST_NOEXCEPT {while (main_convert_iteration());return m_finish;
}
inline bool main_convert_iteration() BOOST_NOEXCEPT {--m_finish;int_type const digit = static_cast<int_type>(m_value % 10U);Traits::assign(*m_finish, Traits::to_char_type(m_zero + digit));m_value /= 10;return !!m_value; // suppressing warnings
}
• Неизвестно количество итераций на момент компиляции.• Вычисление веса каждого разряда, начиная с младшего.Для числа 90000000000000000000 необходимо 20 раз вычислять весаразрядов.
Орлов Роман Догнать и перегнать boost::lexical_cast
5/25
Под капотом boost::lexical_castИтерационное решение
inline CharT* main_convert_loop() BOOST_NOEXCEPT {while (main_convert_iteration());return m_finish;
}
inline bool main_convert_iteration() BOOST_NOEXCEPT {--m_finish;int_type const digit = static_cast<int_type>(m_value % 10U);Traits::assign(*m_finish, Traits::to_char_type(m_zero + digit));m_value /= 10;return !!m_value; // suppressing warnings
}
• Неизвестно количество итераций на момент компиляции.
• Вычисление веса каждого разряда, начиная с младшего.Для числа 90000000000000000000 необходимо 20 раз вычислять весаразрядов.
Орлов Роман Догнать и перегнать boost::lexical_cast
5/25
Под капотом boost::lexical_castИтерационное решение
inline CharT* main_convert_loop() BOOST_NOEXCEPT {while (main_convert_iteration());return m_finish;
}
inline bool main_convert_iteration() BOOST_NOEXCEPT {--m_finish;int_type const digit = static_cast<int_type>(m_value % 10U);Traits::assign(*m_finish, Traits::to_char_type(m_zero + digit));m_value /= 10;return !!m_value; // suppressing warnings
}
• Неизвестно количество итераций на момент компиляции.• Вычисление веса каждого разряда, начиная с младшего.Для числа 90000000000000000000 необходимо 20 раз вычислять весаразрядов.
Орлов Роман Догнать и перегнать boost::lexical_cast
6/25
Под капотом boost::lexical_castПроблема временного буфера
template <std::size_t N, class ArrayT>bool shr_std_array(ArrayT& output) BOOST_NOEXCEPT {using namespace std;const std::size_t size = static_cast<std::size_t>(finish - start);if (size > N - 1) { // ‘-1‘ because we need to store \0 at the endreturn false;
}memcpy(&output[0], start, size * sizeof(CharT));output[size] = Traits::to_char_type(0);return true;
}
• Использование временного буфера с последующим копированием.• Сложность O(2N), где N – количество разрядов в числе.
Орлов Роман Догнать и перегнать boost::lexical_cast
7/25
Под капотом karma::generateРекурсивное решение без временного буфера
template <typename OutputIterator, typename T>static bool call(OutputIterator& sink, T n, T& num, int exp) {
int ch = radix_type::call(remainder_type::call(n));n = divide_type::call(n, num, ++exp);BOOST_PP_REPEAT(BOOST_KARMA_NUMERICS_LOOP_UNROLL,
BOOST_KARMA_NUMERICS_INNER_LOOP_PREFIX, _);if (!traits::test_zero(n))
call(sink, n, num, exp);BOOST_PP_REPEAT(BOOST_KARMA_NUMERICS_LOOP_UNROLL,
BOOST_KARMA_NUMERICS_INNER_LOOP_SUFFIX, _);*sink = char(ch);++sink;return true;
}
#define BOOST_KARMA_NUMERICS_INNER_LOOP_PREFIX(z, x, data) \if (!traits::test_zero(n)) { \
int ch = radix_type::call(remainder_type::call(n)); \n = divide_type::call(n, num, ++exp);
#define BOOST_KARMA_NUMERICS_INNER_LOOP_SUFFIX(z, x, data) \*sink = char(ch); \++sink; \
}
Орлов Роман Догнать и перегнать boost::lexical_cast
7/25
Под капотом karma::generateРекурсивное решение без временного буфера
template <typename OutputIterator, typename T>static bool call(OutputIterator& sink, T n, T& num, int exp) {
int ch = radix_type::call(remainder_type::call(n));n = divide_type::call(n, num, ++exp);BOOST_PP_REPEAT(BOOST_KARMA_NUMERICS_LOOP_UNROLL,
BOOST_KARMA_NUMERICS_INNER_LOOP_PREFIX, _);if (!traits::test_zero(n))
call(sink, n, num, exp);BOOST_PP_REPEAT(BOOST_KARMA_NUMERICS_LOOP_UNROLL,
BOOST_KARMA_NUMERICS_INNER_LOOP_SUFFIX, _);*sink = char(ch);++sink;return true;
}
#define BOOST_KARMA_NUMERICS_INNER_LOOP_PREFIX(z, x, data) \if (!traits::test_zero(n)) { \
int ch = radix_type::call(remainder_type::call(n)); \n = divide_type::call(n, num, ++exp);
#define BOOST_KARMA_NUMERICS_INNER_LOOP_SUFFIX(z, x, data) \*sink = char(ch); \++sink; \
}
Орлов Роман Догнать и перегнать boost::lexical_cast
8/25
Требования к алгоритму
• Без динамического выделения памяти
• Известно число итераций на момент компиляции
• Получение результата без промежуточной буферизации
• Поддержка итераторов
Орлов Роман Догнать и перегнать boost::lexical_cast
9/25
[int2str] На верхнем уровне
template<typename T, typename Iter>inline Iter convert(T x, Iter iter){static_assert(std::is_integral<T>::value,
”T must be integral type”);return impl::converter<typename std::decay<T>::type>::run(x, iter);
}
T – целочисленный тип,Iter – forward-итератор, для которого применимо *iter = char()
template<typename T, typename Iter>inline Iter convert_c_str(T x, Iter iter){iter = convert(x, iter);*iter++ = 0;return iter;
}
Орлов Роман Догнать и перегнать boost::lexical_cast
10/25
[int2str] Основной алгоритмПоиск первого делителя
template<number_t N>struct detail{
template<typename Iter>inline static Iter convert(number_t x, Iter iter){
if (N > x)return detail<N / 10u>::convert(x, iter);
return detail<N>::convert_step(x, iter);}
template<typename Iter>inline static Iter convert_step(number_t x, Iter iter);
};
N – делитель для получения веса старшего разряда,N = 10000000000000000000, 1000000000000000000, . . . , 100, 10, 1
Орлов Роман Догнать и перегнать boost::lexical_cast
11/25
[int2str] Основной алгоритмГенерация строки
template<number_t N>template<typename Iter>Iter detail<N>::convert_step(number_t x, Iter iter){
if (N > x){
*iter++ = ’0’;return detail<N / 10u>::convert_step(x, iter);
}auto const w = x / N; // <-- DIVISION BY CONSTANT*iter++ = static_cast<char>(’0’ + w);return detail<N / 10u>::convert_step(x - w * N, iter);
}
• Веса разрядов вычисляются от старших к младшим.• Чем больше в числе нулевых разрядов, тем быстрее работаеталгоритм.
Орлов Роман Догнать и перегнать boost::lexical_cast
12/25
[int2str] Основной алгоритмКонец генерации строки
template<>struct detail<1u>{
template<typename Iter>inline static Iter convert(number_t x, Iter iter){
return convert_step(x, iter);}
template<typename Iter>inline static Iter convert_step(number_t x, Iter iter){
*iter++ = static_cast<char>(’0’ + x);return iter;
}};
Орлов Роман Догнать и перегнать boost::lexical_cast
13/25
[int2str] Плохое решениеВыбор делителя N
template<typename T, typename Iter>Iter convert(T x, Iter iter){return detail< ? >()>::convert(x, iter); // What N should be here?
}
Пусть N=10000000000000000000, делителю наибольшего числа.
При T=unsigned char и x=42 получимdetail<10000000000000000000>::convert(x, iter)
Для поиска первого делителя числа x, т.е.detail<10>::convert(x, iter)
будет выполнено 18 сравнений N>x.
Орлов Роман Догнать и перегнать boost::lexical_cast
13/25
[int2str] Плохое решениеВыбор делителя N
template<typename T, typename Iter>Iter convert(T x, Iter iter){return detail< ? >()>::convert(x, iter); // What N should be here?
}
Пусть N=10000000000000000000, делителю наибольшего числа.
При T=unsigned char и x=42 получимdetail<10000000000000000000>::convert(x, iter)
Для поиска первого делителя числа x, т.е.detail<10>::convert(x, iter)
будет выполнено 18 сравнений N>x.
Орлов Роман Догнать и перегнать boost::lexical_cast
13/25
[int2str] Плохое решениеВыбор делителя N
template<typename T, typename Iter>Iter convert(T x, Iter iter){return detail< ? >()>::convert(x, iter); // What N should be here?
}
Пусть N=10000000000000000000, делителю наибольшего числа.
При T=unsigned char и x=42 получимdetail<10000000000000000000>::convert(x, iter)
Для поиска первого делителя числа x, т.е.detail<10>::convert(x, iter)
будет выполнено 18 сравнений N>x.
Орлов Роман Догнать и перегнать boost::lexical_cast
14/25
[int2str] Максимальный делитель по типуПредопределенные константы
template<size_t N>constexpr number_t get_max_divider();
template<>constexpr number_t get_max_divider<1u>(){
return 100u;}
template<>constexpr number_t get_max_divider<2u>(){
return 10000u;}
…
template<typename T>constexpr number_t get_max_divider(){
return get_max_divider<sizeof(T)>();}
Орлов Роман Догнать и перегнать boost::lexical_cast
14/25
[int2str] Максимальный делитель по типуПредопределенные константы
template<size_t N>constexpr number_t get_max_divider();
template<>constexpr number_t get_max_divider<1u>(){
return 100u;}
template<>constexpr number_t get_max_divider<2u>(){
return 10000u;}
…template<typename T>constexpr number_t get_max_divider(){
return get_max_divider<sizeof(T)>();}
Орлов Роман Догнать и перегнать boost::lexical_cast
15/25
[int2str] Максимальный делитель по типуВычисление на этапе компиляции
template<typename T>constexpr number_t get_max_divider(number_t n = 1){
return (std::numeric_limits<T>::max() / n <= 9 ? n: get_max_divider<T>(n * 10));
}
template<typename T, typename Iter>Iter convert(T x, Iter iter){
return detail<get_max_divider<T>()>::convert(x, iter);}
При T=uint64_t и x=42 получимdetail<10000000000000000000>::convert(x, iter)
Для поиска первого делителя x снова выполним 18 сравнений N>x.
Орлов Роман Догнать и перегнать boost::lexical_cast
15/25
[int2str] Максимальный делитель по типуВычисление на этапе компиляции
template<typename T>constexpr number_t get_max_divider(number_t n = 1){
return (std::numeric_limits<T>::max() / n <= 9 ? n: get_max_divider<T>(n * 10));
}
template<typename T, typename Iter>Iter convert(T x, Iter iter){
return detail<get_max_divider<T>()>::convert(x, iter);}
При T=uint64_t и x=42 получимdetail<10000000000000000000>::convert(x, iter)
Для поиска первого делителя x снова выполним 18 сравнений N>x.
Орлов Роман Догнать и перегнать boost::lexical_cast
15/25
[int2str] Максимальный делитель по типуВычисление на этапе компиляции
template<typename T>constexpr number_t get_max_divider(number_t n = 1){
return (std::numeric_limits<T>::max() / n <= 9 ? n: get_max_divider<T>(n * 10));
}
template<typename T, typename Iter>Iter convert(T x, Iter iter){
return detail<get_max_divider<T>()>::convert(x, iter);}
При T=uint64_t и x=42 получимdetail<10000000000000000000>::convert(x, iter)
Для поиска первого делителя x снова выполним 18 сравнений N>x.
Орлов Роман Догнать и перегнать boost::lexical_cast
16/25
[int2str] Итерация по типам
Введем метафункцию next_type(T) = U, T ∈ I, U ∈ I,I – множество беззнаковых целых типов, sizeof(T) ≤ sizeof(U).Если T ∼ U, то T – тип максимального размера.template<typename T>struct next_type {
typedef unsigned long long type;};
template<>struct next_type<unsigned char> { // sizeof(char) < sizeof(short)
typedef unsigned short type;};
template<>struct next_type<unsigned short> { // sizeof(short) < sizeof(int)
typedef unsigned int type;};
Для остальных типов специализации не нужныnext_type<unsigned int> → unsigned long longnext_type<unsigned long long> → unsigned long long
Орлов Роман Догнать и перегнать boost::lexical_cast
16/25
[int2str] Итерация по типам
Введем метафункцию next_type(T) = U, T ∈ I, U ∈ I,I – множество беззнаковых целых типов, sizeof(T) ≤ sizeof(U).Если T ∼ U, то T – тип максимального размера.template<typename T>struct next_type {
typedef unsigned long long type;};
template<>struct next_type<unsigned char> { // sizeof(char) < sizeof(short)
typedef unsigned short type;};
template<>struct next_type<unsigned short> { // sizeof(short) < sizeof(int)
typedef unsigned int type;};
Для остальных типов специализации не нужныnext_type<unsigned int> → unsigned long longnext_type<unsigned long long> → unsigned long long
Орлов Роман Догнать и перегнать boost::lexical_cast
16/25
[int2str] Итерация по типам
Введем метафункцию next_type(T) = U, T ∈ I, U ∈ I,I – множество беззнаковых целых типов, sizeof(T) ≤ sizeof(U).Если T ∼ U, то T – тип максимального размера.template<typename T>struct next_type {
typedef unsigned long long type;};
template<>struct next_type<unsigned char> { // sizeof(char) < sizeof(short)
typedef unsigned short type;};
template<>struct next_type<unsigned short> { // sizeof(short) < sizeof(int)
typedef unsigned int type;};
Для остальных типов специализации не нужныnext_type<unsigned int> → unsigned long longnext_type<unsigned long long> → unsigned long long
Орлов Роман Догнать и перегнать boost::lexical_cast
17/25
[int2str] Выбор наиболее близкого делителя
template<typename FromT=unsigned char,typename T,typename Iter>
inline Iter convert_from(T x, Iter iter){
if (x <= std::numeric_limits<FromT>::max())return detail<get_max_divider<FromT>()>::convert(x, iter);
return convert_from<typename next_type<FromT>::type>(x, iter);}
Если T=uint64_t и x=42, то при вызовеconvert_from<unsigned char>(x, iter)
будет использована специализацияdetail<100>::convert(x, iter)
вместо первоначальнойdetail<10000000000000000000>::convert(x, iter)
Орлов Роман Догнать и перегнать boost::lexical_cast
18/25
[int2str] Реализация конвертера
template<typename T, typename Enable=void>struct converter{
template<typename Iter>inline static Iter run(T x, Iter iter) {
return convert_from(x, iter);}
};
template<typename T>struct converter< T,
typename std::enable_if<std::is_signed<T>::value>::type>{
template<typename Iter>inline static Iter run(T x, Iter iter) {
using U = typename std::make_unsigned<T>::type;if (x < 0) {
*iter++ = ’-’;return convert_from(static_cast<U>(-x), iter);
}return convert_from(static_cast<U>(x), iter);
}};
Орлов Роман Догнать и перегнать boost::lexical_cast
18/25
[int2str] Реализация конвертера
template<typename T, typename Enable=void>struct converter{
template<typename Iter>inline static Iter run(T x, Iter iter) {
return convert_from(x, iter);}
};
template<typename T>struct converter< T,
typename std::enable_if<std::is_signed<T>::value>::type>{
template<typename Iter>inline static Iter run(T x, Iter iter) {
using U = typename std::make_unsigned<T>::type;if (x < 0) {
*iter++ = ’-’;return convert_from(static_cast<U>(-x), iter);
}return convert_from(static_cast<U>(x), iter);
}};
Орлов Роман Догнать и перегнать boost::lexical_cast
19/25
Результаты тестированияКомпиляторы и библиотеки
GCC 6• GCC 6.2.1 20160916
Clang• Clang 3.8.0 (tags/RELEASE_380/final)
MS Visual Studio 2015• CL 19.00.24215.1
Boost• Boost 1.62.0, September 28th, 2016 15:17 GMT
Орлов Роман Догнать и перегнать boost::lexical_cast
20/25
Результаты тестированияСинтетический случай
Для всех xi = i, i = INT_MIN, . . . , INT_MAX
clang -O3 gcc -O3 clang -O2 gcc -O2 msvc /O2 /GL0
200
400
600
2 2 2 2 2
100 101 99 100 112
264
378
260
379
635
255
435
366
436
286
t ,с
null int2str::convert boost::lexical_cast karma::generate
Орлов Роман Догнать и перегнать boost::lexical_cast
21/25
Результаты тестированияОбщий случай
Для всех xi = random(INT_MIN, INT_MAX), i = 1, . . . , 10000000
clang -O3 gcc -O3 clang -O2 gcc -O2 msvc /O2 /GL0
2
4
6
8
10
1.53 1.59 1.55 1.59
9.13
2.1 2.18 2.09 2.36
9.65
2.28 2.54 2.29 2.53
10.69
2.212.75 2.48 2.73
9.86
t,с
null int2str::convert boost::lexical_cast karma::generate
Орлов Роман Догнать и перегнать boost::lexical_cast
22/25
Особенности компиляцииint2str::convert VS boost::lexical_cast ON clang -O3
int2str::convert(9001,…)mov ax,dimovzx ecx,axcmp edi,0xffja 0x400a38
0x400a38 cmp ecx,0x270fja XXXXcmp ecx,0x3e7ja 0x400af2
0x400af2 jmp 0x400b000x400b00 cmp rdi,0x3e7
ja 0x400b1b0x400b1b mov rax,rdi
shr rax,0x3movabs rcx,0x20c49ba5e353f7cfmul rcxshr rdx,0x4lea eax,[rdx+0x30]mov BYTE PTR [rsi],alimul rcx,rdx,0xfffffffffffffc18add rcx,rdicmp rcx,0x63ja XXXXmov BYTE PTR [rsi+0x1],0x30cmp rcx,0x9ja XXXXmov BYTE PTR [rsi+0x2],0x30add rcx,0x30mov BYTE PTR [rsi+0x3],cljmp 0x400c51
0x400c51 add rsi,0x4mov rax,rsi
boost::lexical_cast<…>(9001)0x401390 mov rdx,QWORD PTR [rbx+0x8]
lea rsi,[rdx-0x1]mov QWORD PTR [rbx+0x8],rsimov esi,ecximul rsi,raxshr rsi,0x23add esi,esilea esi,[rsi+rsi*4]sub ecx,esiadd ecx,DWORD PTR [rbx+0x14]mov BYTE PTR [rdx-0x1],clmovsxd rdx,DWORD PTR [rbx]imul rcx,rdx,0x66666667mov rsi,rcxshr rsi,0x3fsar rcx,0x22add ecx,esimov DWORD PTR [rbx],ecxlea edx,[rdx+0x9]cmp edx,0x12ja 0x401390
x4
Орлов Роман Догнать и перегнать boost::lexical_cast
22/25
Особенности компиляцииint2str::convert VS boost::lexical_cast ON clang -O3
int2str::convert(9001,…)mov ax,dimovzx ecx,axcmp edi,0xffja 0x400a38
0x400a38 cmp ecx,0x270fja XXXXcmp ecx,0x3e7ja 0x400af2
0x400af2 jmp 0x400b000x400b00 cmp rdi,0x3e7
ja 0x400b1b0x400b1b mov rax,rdi
shr rax,0x3movabs rcx,0x20c49ba5e353f7cfmul rcxshr rdx,0x4lea eax,[rdx+0x30]mov BYTE PTR [rsi],alimul rcx,rdx,0xfffffffffffffc18add rcx,rdicmp rcx,0x63ja XXXXmov BYTE PTR [rsi+0x1],0x30cmp rcx,0x9ja XXXXmov BYTE PTR [rsi+0x2],0x30add rcx,0x30mov BYTE PTR [rsi+0x3],cljmp 0x400c51
0x400c51 add rsi,0x4mov rax,rsi
boost::lexical_cast<…>(9001)0x401390 mov rdx,QWORD PTR [rbx+0x8]
lea rsi,[rdx-0x1]mov QWORD PTR [rbx+0x8],rsimov esi,ecximul rsi,raxshr rsi,0x23add esi,esilea esi,[rsi+rsi*4]sub ecx,esiadd ecx,DWORD PTR [rbx+0x14]mov BYTE PTR [rdx-0x1],clmovsxd rdx,DWORD PTR [rbx]imul rcx,rdx,0x66666667mov rsi,rcxshr rsi,0x3fsar rcx,0x22add ecx,esimov DWORD PTR [rbx],ecxlea edx,[rdx+0x9]cmp edx,0x12ja 0x401390
x4
Орлов Роман Догнать и перегнать boost::lexical_cast
22/25
Особенности компиляцииint2str::convert VS boost::lexical_cast ON clang -O3
int2str::convert(9001,…)mov ax,dimovzx ecx,axcmp edi,0xffja 0x400a38
0x400a38 cmp ecx,0x270fja XXXXcmp ecx,0x3e7ja 0x400af2
0x400af2 jmp 0x400b000x400b00 cmp rdi,0x3e7
ja 0x400b1b0x400b1b mov rax,rdi
shr rax,0x3movabs rcx,0x20c49ba5e353f7cfmul rcxshr rdx,0x4lea eax,[rdx+0x30]mov BYTE PTR [rsi],alimul rcx,rdx,0xfffffffffffffc18add rcx,rdicmp rcx,0x63ja XXXXmov BYTE PTR [rsi+0x1],0x30cmp rcx,0x9ja XXXXmov BYTE PTR [rsi+0x2],0x30add rcx,0x30mov BYTE PTR [rsi+0x3],cljmp 0x400c51
0x400c51 add rsi,0x4mov rax,rsi
boost::lexical_cast<…>(9001)0x401390 mov rdx,QWORD PTR [rbx+0x8]
lea rsi,[rdx-0x1]mov QWORD PTR [rbx+0x8],rsimov esi,ecximul rsi,raxshr rsi,0x23add esi,esilea esi,[rsi+rsi*4]sub ecx,esiadd ecx,DWORD PTR [rbx+0x14]mov BYTE PTR [rdx-0x1],clmovsxd rdx,DWORD PTR [rbx]imul rcx,rdx,0x66666667mov rsi,rcxshr rsi,0x3fsar rcx,0x22add ecx,esimov DWORD PTR [rbx],ecxlea edx,[rdx+0x9]cmp edx,0x12ja 0x401390
x4
Орлов Роман Догнать и перегнать boost::lexical_cast
23/25
Особенности компиляцииclang -O3 VS gcc -O3
int2str::convert(9001,…)mov ax,dimovzx ecx,axcmp edi,0xffja 0x400a38
0x400a38 cmp ecx,0x270fja XXXXcmp ecx,0x3e7ja 0x400af2
0x400af2 jmp 0x400b000x400b00 cmp rdi,0x3e7
ja 0x400b1b0x400b1b mov rax,rdi
shr rax,0x3movabs rcx,0x20c49ba5e353f7cfmul rcxshr rdx,0x4lea eax,[rdx+0x30]mov BYTE PTR [rsi],alimul rcx,rdx,0xfffffffffffffc18add rcx,rdicmp rcx,0x63ja XXXXmov BYTE PTR [rsi+0x1],0x30cmp rcx,0x9ja XXXXmov BYTE PTR [rsi+0x2],0x30add rcx,0x30mov BYTE PTR [rsi+0x3],cljmp 0x400c51
0x400c51 add rsi,0x4mov rax,rsi
int2str::convert(9001,…)cmp cx,0xffmovsx rax,cxjle XXXXcmp cx,0x270fjle 0x400964
0x400964 cmp cx,0x3e7jle XXXXxor edx,edxmov ecx,0x3e8div rcxadd eax,0x30cmp rdx,0x63mov BYTE PTR [rsp],alja XXXXcmp rdx,0x9mov BYTE PTR [rsp+0x1],0x30ja XXXXlea eax,[rdx+0x30]mov BYTE PTR [rsp+0x2],0x30mov rsi,rspmov BYTE PTR [rsp+0x3],allea rax,[rsp+0x4]jmp XXXX
Орлов Роман Догнать и перегнать boost::lexical_cast
24/25
Итоги
#include <int2str/int2str.hpp>#include <string>#include <iostream>
int main(){
std::string msg = ”C++ Russia ”;int2str::convert(2017, std::back_inserter(msg));std::cout << msg << std::endl;return 0;
}
Нет динамического выделения памяти.На момент компиляции известно число итераций.Результат формируется без промежуточной буферизации.Работа через итераторы.Быстрее boost::lexical_cast.
Орлов Роман Догнать и перегнать boost::lexical_cast
25/25
Спасибо за внимание!
https://github.com/compmaniak/int2str
Орлов Роман Догнать и перегнать boost::lexical_cast