Догнать и перегнать boost::lexical_cast

42
1/25 Догнать и перегнать boost::lexical_cast Быстрое преобразование целого числа в строку Орлов Роман 18 февраля 2017 г. Орлов Роман Догнать и перегнать boost::lexical_cast

Upload: roman-orlov

Post on 03-Mar-2017

3.030 views

Category:

Software


6 download

TRANSCRIPT

Page 1: Догнать и перегнать boost::lexical_cast

1/25

Догнать и перегнать boost::lexical_castБыстрое преобразование целого числа в строку

Орлов Роман

18 февраля 2017 г.

Орлов Роман Догнать и перегнать boost::lexical_cast

Page 2: Догнать и перегнать 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

Page 3: Догнать и перегнать 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

Page 4: Догнать и перегнать 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

Page 5: Догнать и перегнать 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

Page 6: Догнать и перегнать 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

Page 7: Догнать и перегнать 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

Page 8: Догнать и перегнать 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

Page 9: Догнать и перегнать 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

Page 10: Догнать и перегнать 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

Page 11: Догнать и перегнать 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

Page 12: Догнать и перегнать 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

Page 13: Догнать и перегнать 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

Page 14: Догнать и перегнать 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

Page 15: Догнать и перегнать boost::lexical_cast

8/25

Требования к алгоритму

• Без динамического выделения памяти

• Известно число итераций на момент компиляции

• Получение результата без промежуточной буферизации

• Поддержка итераторов

Орлов Роман Догнать и перегнать boost::lexical_cast

Page 16: Догнать и перегнать 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

Page 17: Догнать и перегнать 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

Page 18: Догнать и перегнать 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

Page 19: Догнать и перегнать 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

Page 20: Догнать и перегнать 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

Page 21: Догнать и перегнать 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

Page 22: Догнать и перегнать 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

Page 23: Догнать и перегнать 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

Page 24: Догнать и перегнать 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

Page 25: Догнать и перегнать 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

Page 26: Догнать и перегнать 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

Page 27: Догнать и перегнать 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

Page 28: Догнать и перегнать 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

Page 29: Догнать и перегнать 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

Page 30: Догнать и перегнать 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

Page 31: Догнать и перегнать 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

Page 32: Догнать и перегнать 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

Page 33: Догнать и перегнать 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

Page 34: Догнать и перегнать 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

Page 35: Догнать и перегнать 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

Page 36: Догнать и перегнать 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

Page 37: Догнать и перегнать 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

Page 38: Догнать и перегнать 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

Page 39: Догнать и перегнать 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

Page 40: Догнать и перегнать 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

Page 41: Догнать и перегнать 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

Page 42: Догнать и перегнать boost::lexical_cast

25/25

Спасибо за внимание!

https://github.com/compmaniak/int2str

Орлов Роман Догнать и перегнать boost::lexical_cast