SlideShare uma empresa Scribd logo
1 de 42
Baixar para ler offline
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.1
0
50
100
150
17
9
140
89
38
17
28
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
}
Орлов Роман Догнать и перегнать 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
}
• Неизвестно количество итераций на момент компиляции.
Орлов Роман Догнать и перегнать 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 end
return 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;
}
Орлов Роман Догнать и перегнать 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?
}
Орлов Роман Догнать и перегнать 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, делителю наибольшего числа.
Орлов Роман Догнать и перегнать 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;
}
…
Орлов Роман Догнать и перегнать 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));
}
Орлов Роман Догнать и перегнать 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);
}
Орлов Роман Догнать и перегнать 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;
};
Орлов Роман Догнать и перегнать 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;
};
Орлов Роман Догнать и перегнать 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 long
next_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);
}
};
Орлов Роман Догнать и перегнать 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 /GL
0
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 /GL
0
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.21
2.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,di
movzx ecx,ax
cmp edi,0xff
ja 0x400a38
0x400a38 cmp ecx,0x270f
ja XXXX
cmp ecx,0x3e7
ja 0x400af2
0x400af2 jmp 0x400b00
0x400b00 cmp rdi,0x3e7
ja 0x400b1b
0x400b1b mov rax,rdi
shr rax,0x3
movabs rcx,0x20c49ba5e353f7cf
mul rcx
shr rdx,0x4
lea eax,[rdx+0x30]
mov BYTE PTR [rsi],al
imul rcx,rdx,0xfffffffffffffc18
add rcx,rdi
cmp rcx,0x63
ja XXXX
mov BYTE PTR [rsi+0x1],0x30
cmp rcx,0x9
ja XXXX
mov BYTE PTR [rsi+0x2],0x30
add rcx,0x30
mov BYTE PTR [rsi+0x3],cl
jmp 0x400c51
0x400c51 add rsi,0x4
mov rax,rsi
Орлов Роман Догнать и перегнать boost::lexical_cast
22/25
Особенности компиляции
int2str::convert VS boost::lexical_cast ON clang -O3
int2str::convert(9001,…)
mov ax,di
movzx ecx,ax
cmp edi,0xff
ja 0x400a38
0x400a38 cmp ecx,0x270f
ja XXXX
cmp ecx,0x3e7
ja 0x400af2
0x400af2 jmp 0x400b00
0x400b00 cmp rdi,0x3e7
ja 0x400b1b
0x400b1b mov rax,rdi
shr rax,0x3
movabs rcx,0x20c49ba5e353f7cf
mul rcx
shr rdx,0x4
lea eax,[rdx+0x30]
mov BYTE PTR [rsi],al
imul rcx,rdx,0xfffffffffffffc18
add rcx,rdi
cmp rcx,0x63
ja XXXX
mov BYTE PTR [rsi+0x1],0x30
cmp rcx,0x9
ja XXXX
mov BYTE PTR [rsi+0x2],0x30
add rcx,0x30
mov BYTE PTR [rsi+0x3],cl
jmp 0x400c51
0x400c51 add rsi,0x4
mov rax,rsi
boost::lexical_cast<…>(9001)
0x401390 mov rdx,QWORD PTR [rbx+0x8]
lea rsi,[rdx-0x1]
mov QWORD PTR [rbx+0x8],rsi
mov esi,ecx
imul rsi,rax
shr rsi,0x23
add esi,esi
lea esi,[rsi+rsi*4]
sub ecx,esi
add ecx,DWORD PTR [rbx+0x14]
mov BYTE PTR [rdx-0x1],cl
movsxd rdx,DWORD PTR [rbx]
imul rcx,rdx,0x66666667
mov rsi,rcx
shr rsi,0x3f
sar rcx,0x22
add ecx,esi
mov DWORD PTR [rbx],ecx
lea edx,[rdx+0x9]
cmp edx,0x12
ja 0x401390
Орлов Роман Догнать и перегнать boost::lexical_cast
22/25
Особенности компиляции
int2str::convert VS boost::lexical_cast ON clang -O3
int2str::convert(9001,…)
mov ax,di
movzx ecx,ax
cmp edi,0xff
ja 0x400a38
0x400a38 cmp ecx,0x270f
ja XXXX
cmp ecx,0x3e7
ja 0x400af2
0x400af2 jmp 0x400b00
0x400b00 cmp rdi,0x3e7
ja 0x400b1b
0x400b1b mov rax,rdi
shr rax,0x3
movabs rcx,0x20c49ba5e353f7cf
mul rcx
shr rdx,0x4
lea eax,[rdx+0x30]
mov BYTE PTR [rsi],al
imul rcx,rdx,0xfffffffffffffc18
add rcx,rdi
cmp rcx,0x63
ja XXXX
mov BYTE PTR [rsi+0x1],0x30
cmp rcx,0x9
ja XXXX
mov BYTE PTR [rsi+0x2],0x30
add rcx,0x30
mov BYTE PTR [rsi+0x3],cl
jmp 0x400c51
0x400c51 add rsi,0x4
mov rax,rsi
boost::lexical_cast<…>(9001)
0x401390 mov rdx,QWORD PTR [rbx+0x8]
lea rsi,[rdx-0x1]
mov QWORD PTR [rbx+0x8],rsi
mov esi,ecx
imul rsi,rax
shr rsi,0x23
add esi,esi
lea esi,[rsi+rsi*4]
sub ecx,esi
add ecx,DWORD PTR [rbx+0x14]
mov BYTE PTR [rdx-0x1],cl
movsxd rdx,DWORD PTR [rbx]
imul rcx,rdx,0x66666667
mov rsi,rcx
shr rsi,0x3f
sar rcx,0x22
add ecx,esi
mov DWORD PTR [rbx],ecx
lea edx,[rdx+0x9]
cmp edx,0x12
ja 0x401390
x4
Орлов Роман Догнать и перегнать boost::lexical_cast
23/25
Особенности компиляции
clang -O3 VS gcc -O3
int2str::convert(9001,…)
mov ax,di
movzx ecx,ax
cmp edi,0xff
ja 0x400a38
0x400a38 cmp ecx,0x270f
ja XXXX
cmp ecx,0x3e7
ja 0x400af2
0x400af2 jmp 0x400b00
0x400b00 cmp rdi,0x3e7
ja 0x400b1b
0x400b1b mov rax,rdi
shr rax,0x3
movabs rcx,0x20c49ba5e353f7cf
mul rcx
shr rdx,0x4
lea eax,[rdx+0x30]
mov BYTE PTR [rsi],al
imul rcx,rdx,0xfffffffffffffc18
add rcx,rdi
cmp rcx,0x63
ja XXXX
mov BYTE PTR [rsi+0x1],0x30
cmp rcx,0x9
ja XXXX
mov BYTE PTR [rsi+0x2],0x30
add rcx,0x30
mov BYTE PTR [rsi+0x3],cl
jmp 0x400c51
0x400c51 add rsi,0x4
mov rax,rsi
int2str::convert(9001,…)
cmp cx,0xff
movsx rax,cx
jle XXXX
cmp cx,0x270f
jle 0x400964
0x400964 cmp cx,0x3e7
jle XXXX
xor edx,edx
mov ecx,0x3e8
div rcx
add eax,0x30
cmp rdx,0x63
mov BYTE PTR [rsp],al
ja XXXX
cmp rdx,0x9
mov BYTE PTR [rsp+0x1],0x30
ja XXXX
lea eax,[rdx+0x30]
mov BYTE PTR [rsp+0x2],0x30
mov rsi,rsp
mov BYTE PTR [rsp+0x3],al
lea 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

Mais conteúdo relacionado

Mais procurados

Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVMДмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVMSergey Platonov
 
Использование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработкиИспользование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработкиvictor-yastrebov
 
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017Mikhail Matrosov
 
Статический анализ кода
Статический анализ кода Статический анализ кода
Статический анализ кода Pavel Tsukanov
 
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...Alexey Paznikov
 
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...Alexey Paznikov
 
Обобщенное программирование в C++ или как сделать свою жизнь проще через стра...
Обобщенное программирование в C++ или как сделать свою жизнь проще через стра...Обобщенное программирование в C++ или как сделать свою жизнь проще через стра...
Обобщенное программирование в C++ или как сделать свою жизнь проще через стра...corehard_by
 
хитрости выведения типов
хитрости выведения типовхитрости выведения типов
хитрости выведения типовcorehard_by
 
Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»
Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»
Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»Platonov Sergey
 
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...Alexey Paznikov
 
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++.   Р...ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++.   Р...
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...Alexey Paznikov
 
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...Alexey Paznikov
 
Конкурентные ассоциативные контейнеры
Конкурентные ассоциативные контейнерыКонкурентные ассоциативные контейнеры
Конкурентные ассоциативные контейнерыcorehard_by
 
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программированияПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программированияAlexey Paznikov
 
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...Alexey Paznikov
 
Игорь Кудрин, «Используем неизменяемые данные и создаем качественный код»
Игорь Кудрин, «Используем неизменяемые данные и создаем качественный код»Игорь Кудрин, «Используем неизменяемые данные и создаем качественный код»
Игорь Кудрин, «Используем неизменяемые данные и создаем качественный код»Platonov Sergey
 
ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...
ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...
ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...Alexey Paznikov
 
Евгений Зуев, С++ в России: Стандарт языка и его реализация
Евгений Зуев, С++ в России: Стандарт языка и его реализацияЕвгений Зуев, С++ в России: Стандарт языка и его реализация
Евгений Зуев, С++ в России: Стандарт языка и его реализацияPlatonov Sergey
 

Mais procurados (20)

Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVMДмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
 
Parallel STL
Parallel STLParallel STL
Parallel STL
 
Использование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработкиИспользование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработки
 
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
Повседневный С++: алгоритмы и итераторы @ C++ Russia 2017
 
Статический анализ кода
Статический анализ кода Статический анализ кода
Статический анализ кода
 
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
 
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
ПВТ - весна 2015 - Лекция 8. Многопоточное программирование без использования...
 
Обобщенное программирование в C++ или как сделать свою жизнь проще через стра...
Обобщенное программирование в C++ или как сделать свою жизнь проще через стра...Обобщенное программирование в C++ или как сделать свою жизнь проще через стра...
Обобщенное программирование в C++ или как сделать свою жизнь проще через стра...
 
хитрости выведения типов
хитрости выведения типовхитрости выведения типов
хитрости выведения типов
 
C++ exceptions
C++ exceptionsC++ exceptions
C++ exceptions
 
Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»
Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»
Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»
 
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
 
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++.   Р...ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++.   Р...
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...
 
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
 
Конкурентные ассоциативные контейнеры
Конкурентные ассоциативные контейнерыКонкурентные ассоциативные контейнеры
Конкурентные ассоциативные контейнеры
 
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программированияПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
 
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
ПВТ - весна 2015 - Лекция 3. Реентерабельность. Сигналы. Локальные данные пот...
 
Игорь Кудрин, «Используем неизменяемые данные и создаем качественный код»
Игорь Кудрин, «Используем неизменяемые данные и создаем качественный код»Игорь Кудрин, «Используем неизменяемые данные и создаем качественный код»
Игорь Кудрин, «Используем неизменяемые данные и создаем качественный код»
 
ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...
ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...
ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...
 
Евгений Зуев, С++ в России: Стандарт языка и его реализация
Евгений Зуев, С++ в России: Стандарт языка и его реализацияЕвгений Зуев, С++ в России: Стандарт языка и его реализация
Евгений Зуев, С++ в России: Стандарт языка и его реализация
 

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

Tech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVMTech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVMTech Talks @NSU
 
Как приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVMКак приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVMTech Talks @NSU
 
Лекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building BlocksЛекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building BlocksMikhail Kurnosov
 
Дмитрий Прокопцев — R-ссылки в С++11
Дмитрий Прокопцев — R-ссылки в С++11Дмитрий Прокопцев — R-ссылки в С++11
Дмитрий Прокопцев — R-ссылки в С++11Yandex
 
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...Yandex
 
Cpp0x Introduction
Cpp0x IntroductionCpp0x Introduction
Cpp0x IntroductionFedor Vompe
 
Как написать JIT компилятор
Как написать JIT компиляторКак написать JIT компилятор
Как написать JIT компиляторAndrew Aksyonoff
 
Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...
Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...
Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...Yandex
 
статический анализ кода
статический анализ кодастатический анализ кода
статический анализ кодаAndrey Karpov
 
Как не сделать врагами архитектуру и оптимизацию, Кирилл Березин, Mail.ru Group
Как не сделать врагами архитектуру и оптимизацию, Кирилл Березин, Mail.ru GroupКак не сделать врагами архитектуру и оптимизацию, Кирилл Березин, Mail.ru Group
Как не сделать врагами архитектуру и оптимизацию, Кирилл Березин, Mail.ru GroupMail.ru Group
 
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
C++ CoreHard Autumn 2018. Полезный constexpr - Антон ПолухинC++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухинcorehard_by
 
C++ refelection and cats
C++ refelection and catsC++ refelection and cats
C++ refelection and catscorehard_by
 
разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3Eugeniy Tyumentcev
 
разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3etyumentcev
 
Семинар 4. Многопоточное программирование на OpenMP (часть 4)
Семинар 4. Многопоточное программирование на OpenMP (часть 4)Семинар 4. Многопоточное программирование на OpenMP (часть 4)
Семинар 4. Многопоточное программирование на OpenMP (часть 4)Mikhail Kurnosov
 
СИ++ УМЕР. ДА ЗДРАВСТВУЕТ СИ++
СИ++ УМЕР. ДА ЗДРАВСТВУЕТ СИ++СИ++ УМЕР. ДА ЗДРАВСТВУЕТ СИ++
СИ++ УМЕР. ДА ЗДРАВСТВУЕТ СИ++Pavel Tsukanov
 
Лекция 6. Стандарт OpenMP
Лекция 6. Стандарт OpenMPЛекция 6. Стандарт OpenMP
Лекция 6. Стандарт OpenMPMikhail Kurnosov
 
Семинар 2. Многопоточное программирование на OpenMP (часть 2)
Семинар 2. Многопоточное программирование на OpenMP (часть 2)Семинар 2. Многопоточное программирование на OpenMP (часть 2)
Семинар 2. Многопоточное программирование на OpenMP (часть 2)Mikhail Kurnosov
 

Semelhante a Догнать и перегнать boost::lexical_cast (20)

Programming c++ (begin-if-else)
Programming c++ (begin-if-else)Programming c++ (begin-if-else)
Programming c++ (begin-if-else)
 
Tech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVMTech Talks @NSU: Как приручить дракона: введение в LLVM
Tech Talks @NSU: Как приручить дракона: введение в LLVM
 
Как приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVMКак приручить дракона: введение в LLVM
Как приручить дракона: введение в LLVM
 
Лекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building BlocksЛекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building Blocks
 
Дмитрий Прокопцев — R-ссылки в С++11
Дмитрий Прокопцев — R-ссылки в С++11Дмитрий Прокопцев — R-ссылки в С++11
Дмитрий Прокопцев — R-ссылки в С++11
 
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
 
Cpp0x Introduction
Cpp0x IntroductionCpp0x Introduction
Cpp0x Introduction
 
Как написать JIT компилятор
Как написать JIT компиляторКак написать JIT компилятор
Как написать JIT компилятор
 
Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...
Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...
Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...
 
статический анализ кода
статический анализ кодастатический анализ кода
статический анализ кода
 
Как не сделать врагами архитектуру и оптимизацию, Кирилл Березин, Mail.ru Group
Как не сделать врагами архитектуру и оптимизацию, Кирилл Березин, Mail.ru GroupКак не сделать врагами архитектуру и оптимизацию, Кирилл Березин, Mail.ru Group
Как не сделать врагами архитектуру и оптимизацию, Кирилл Березин, Mail.ru Group
 
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
C++ CoreHard Autumn 2018. Полезный constexpr - Антон ПолухинC++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
 
C++ refelection and cats
C++ refelection and catsC++ refelection and cats
C++ refelection and cats
 
разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3
 
разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3
 
Семинар 4. Многопоточное программирование на OpenMP (часть 4)
Семинар 4. Многопоточное программирование на OpenMP (часть 4)Семинар 4. Многопоточное программирование на OpenMP (часть 4)
Семинар 4. Многопоточное программирование на OpenMP (часть 4)
 
Erlang
ErlangErlang
Erlang
 
СИ++ УМЕР. ДА ЗДРАВСТВУЕТ СИ++
СИ++ УМЕР. ДА ЗДРАВСТВУЕТ СИ++СИ++ УМЕР. ДА ЗДРАВСТВУЕТ СИ++
СИ++ УМЕР. ДА ЗДРАВСТВУЕТ СИ++
 
Лекция 6. Стандарт OpenMP
Лекция 6. Стандарт OpenMPЛекция 6. Стандарт OpenMP
Лекция 6. Стандарт OpenMP
 
Семинар 2. Многопоточное программирование на OpenMP (часть 2)
Семинар 2. Многопоточное программирование на OpenMP (часть 2)Семинар 2. Многопоточное программирование на OpenMP (часть 2)
Семинар 2. Многопоточное программирование на OpenMP (часть 2)
 

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

  • 1. 1/25 Догнать и перегнать boost::lexical_cast Быстрое преобразование целого числа в строку Орлов Роман 18 февраля 2017 г. Орлов Роман Догнать и перегнать boost::lexical_cast
  • 2. 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. 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. 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
  • 5. 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
  • 6. 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
  • 7. 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
  • 8. 4/25 Производительность boost::lexical_cast Для всех xi = 100, i = 1, . . . , 10000 Clang 3.6.0 GCC 6.1.1 0 50 100 150 17 9 140 89 38 17 28 14 t,мс lexical_cast std::stringstream+ctor std::stringstream printf Орлов Роман Догнать и перегнать boost::lexical_cast
  • 9. 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 } Орлов Роман Догнать и перегнать boost::lexical_cast
  • 10. 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 } • Неизвестно количество итераций на момент компиляции. Орлов Роман Догнать и перегнать boost::lexical_cast
  • 11. 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
  • 12. 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 end return false; } memcpy(&output[0], start, size * sizeof(CharT)); output[size] = Traits::to_char_type(0); return true; } • Использование временного буфера с последующим копированием. • Сложность O(2N), где N – количество разрядов в числе. Орлов Роман Догнать и перегнать boost::lexical_cast
  • 13. 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; } Орлов Роман Догнать и перегнать boost::lexical_cast
  • 14. 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
  • 15. 8/25 Требования к алгоритму • Без динамического выделения памяти • Известно число итераций на момент компиляции • Получение результата без промежуточной буферизации • Поддержка итераторов Орлов Роман Догнать и перегнать boost::lexical_cast
  • 16. 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
  • 17. 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
  • 18. 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
  • 19. 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
  • 20. 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? } Орлов Роман Догнать и перегнать boost::lexical_cast
  • 21. 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, делителю наибольшего числа. Орлов Роман Догнать и перегнать boost::lexical_cast
  • 22. 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
  • 23. 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; } … Орлов Роман Догнать и перегнать boost::lexical_cast
  • 24. 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
  • 25. 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)); } Орлов Роман Догнать и перегнать boost::lexical_cast
  • 26. 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); } Орлов Роман Догнать и перегнать boost::lexical_cast
  • 27. 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
  • 28. 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; }; Орлов Роман Догнать и перегнать boost::lexical_cast
  • 29. 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; }; Орлов Роман Догнать и перегнать boost::lexical_cast
  • 30. 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 long next_type<unsigned long long> → unsigned long long Орлов Роман Догнать и перегнать boost::lexical_cast
  • 31. 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
  • 32. 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); } }; Орлов Роман Догнать и перегнать boost::lexical_cast
  • 33. 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
  • 34. 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
  • 35. 20/25 Результаты тестирования Синтетический случай Для всех xi = i, i = INT_MIN, . . . , INT_MAX clang -O3 gcc -O3 clang -O2 gcc -O2 msvc /O2 /GL 0 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
  • 36. 21/25 Результаты тестирования Общий случай Для всех xi = random(INT_MIN, INT_MAX), i = 1, . . . , 10000000 clang -O3 gcc -O3 clang -O2 gcc -O2 msvc /O2 /GL 0 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.21 2.75 2.48 2.73 9.86 t,с null int2str::convert boost::lexical_cast karma::generate Орлов Роман Догнать и перегнать boost::lexical_cast
  • 37. 22/25 Особенности компиляции int2str::convert VS boost::lexical_cast ON clang -O3 int2str::convert(9001,…) mov ax,di movzx ecx,ax cmp edi,0xff ja 0x400a38 0x400a38 cmp ecx,0x270f ja XXXX cmp ecx,0x3e7 ja 0x400af2 0x400af2 jmp 0x400b00 0x400b00 cmp rdi,0x3e7 ja 0x400b1b 0x400b1b mov rax,rdi shr rax,0x3 movabs rcx,0x20c49ba5e353f7cf mul rcx shr rdx,0x4 lea eax,[rdx+0x30] mov BYTE PTR [rsi],al imul rcx,rdx,0xfffffffffffffc18 add rcx,rdi cmp rcx,0x63 ja XXXX mov BYTE PTR [rsi+0x1],0x30 cmp rcx,0x9 ja XXXX mov BYTE PTR [rsi+0x2],0x30 add rcx,0x30 mov BYTE PTR [rsi+0x3],cl jmp 0x400c51 0x400c51 add rsi,0x4 mov rax,rsi Орлов Роман Догнать и перегнать boost::lexical_cast
  • 38. 22/25 Особенности компиляции int2str::convert VS boost::lexical_cast ON clang -O3 int2str::convert(9001,…) mov ax,di movzx ecx,ax cmp edi,0xff ja 0x400a38 0x400a38 cmp ecx,0x270f ja XXXX cmp ecx,0x3e7 ja 0x400af2 0x400af2 jmp 0x400b00 0x400b00 cmp rdi,0x3e7 ja 0x400b1b 0x400b1b mov rax,rdi shr rax,0x3 movabs rcx,0x20c49ba5e353f7cf mul rcx shr rdx,0x4 lea eax,[rdx+0x30] mov BYTE PTR [rsi],al imul rcx,rdx,0xfffffffffffffc18 add rcx,rdi cmp rcx,0x63 ja XXXX mov BYTE PTR [rsi+0x1],0x30 cmp rcx,0x9 ja XXXX mov BYTE PTR [rsi+0x2],0x30 add rcx,0x30 mov BYTE PTR [rsi+0x3],cl jmp 0x400c51 0x400c51 add rsi,0x4 mov rax,rsi boost::lexical_cast<…>(9001) 0x401390 mov rdx,QWORD PTR [rbx+0x8] lea rsi,[rdx-0x1] mov QWORD PTR [rbx+0x8],rsi mov esi,ecx imul rsi,rax shr rsi,0x23 add esi,esi lea esi,[rsi+rsi*4] sub ecx,esi add ecx,DWORD PTR [rbx+0x14] mov BYTE PTR [rdx-0x1],cl movsxd rdx,DWORD PTR [rbx] imul rcx,rdx,0x66666667 mov rsi,rcx shr rsi,0x3f sar rcx,0x22 add ecx,esi mov DWORD PTR [rbx],ecx lea edx,[rdx+0x9] cmp edx,0x12 ja 0x401390 Орлов Роман Догнать и перегнать boost::lexical_cast
  • 39. 22/25 Особенности компиляции int2str::convert VS boost::lexical_cast ON clang -O3 int2str::convert(9001,…) mov ax,di movzx ecx,ax cmp edi,0xff ja 0x400a38 0x400a38 cmp ecx,0x270f ja XXXX cmp ecx,0x3e7 ja 0x400af2 0x400af2 jmp 0x400b00 0x400b00 cmp rdi,0x3e7 ja 0x400b1b 0x400b1b mov rax,rdi shr rax,0x3 movabs rcx,0x20c49ba5e353f7cf mul rcx shr rdx,0x4 lea eax,[rdx+0x30] mov BYTE PTR [rsi],al imul rcx,rdx,0xfffffffffffffc18 add rcx,rdi cmp rcx,0x63 ja XXXX mov BYTE PTR [rsi+0x1],0x30 cmp rcx,0x9 ja XXXX mov BYTE PTR [rsi+0x2],0x30 add rcx,0x30 mov BYTE PTR [rsi+0x3],cl jmp 0x400c51 0x400c51 add rsi,0x4 mov rax,rsi boost::lexical_cast<…>(9001) 0x401390 mov rdx,QWORD PTR [rbx+0x8] lea rsi,[rdx-0x1] mov QWORD PTR [rbx+0x8],rsi mov esi,ecx imul rsi,rax shr rsi,0x23 add esi,esi lea esi,[rsi+rsi*4] sub ecx,esi add ecx,DWORD PTR [rbx+0x14] mov BYTE PTR [rdx-0x1],cl movsxd rdx,DWORD PTR [rbx] imul rcx,rdx,0x66666667 mov rsi,rcx shr rsi,0x3f sar rcx,0x22 add ecx,esi mov DWORD PTR [rbx],ecx lea edx,[rdx+0x9] cmp edx,0x12 ja 0x401390 x4 Орлов Роман Догнать и перегнать boost::lexical_cast
  • 40. 23/25 Особенности компиляции clang -O3 VS gcc -O3 int2str::convert(9001,…) mov ax,di movzx ecx,ax cmp edi,0xff ja 0x400a38 0x400a38 cmp ecx,0x270f ja XXXX cmp ecx,0x3e7 ja 0x400af2 0x400af2 jmp 0x400b00 0x400b00 cmp rdi,0x3e7 ja 0x400b1b 0x400b1b mov rax,rdi shr rax,0x3 movabs rcx,0x20c49ba5e353f7cf mul rcx shr rdx,0x4 lea eax,[rdx+0x30] mov BYTE PTR [rsi],al imul rcx,rdx,0xfffffffffffffc18 add rcx,rdi cmp rcx,0x63 ja XXXX mov BYTE PTR [rsi+0x1],0x30 cmp rcx,0x9 ja XXXX mov BYTE PTR [rsi+0x2],0x30 add rcx,0x30 mov BYTE PTR [rsi+0x3],cl jmp 0x400c51 0x400c51 add rsi,0x4 mov rax,rsi int2str::convert(9001,…) cmp cx,0xff movsx rax,cx jle XXXX cmp cx,0x270f jle 0x400964 0x400964 cmp cx,0x3e7 jle XXXX xor edx,edx mov ecx,0x3e8 div rcx add eax,0x30 cmp rdx,0x63 mov BYTE PTR [rsp],al ja XXXX cmp rdx,0x9 mov BYTE PTR [rsp+0x1],0x30 ja XXXX lea eax,[rdx+0x30] mov BYTE PTR [rsp+0x2],0x30 mov rsi,rsp mov BYTE PTR [rsp+0x3],al lea rax,[rsp+0x4] jmp XXXX Орлов Роман Догнать и перегнать boost::lexical_cast
  • 41. 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
  • 42. 25/25 Спасибо за внимание! https://github.com/compmaniak/int2str Орлов Роман Догнать и перегнать boost::lexical_cast