std::string, копирование с трансформацией символов
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 08.07.18 14:17
Оценка:
Проблема на ровном месте

Есть строка, которую надо скопировать в std::string с приведением символов к верхнему регистру.

Как это сделать оптимальным способом?

Текущие варианты, которые не нравятся.

нулевой
устанавливаем строку в std::string и приводим символы к верхнему регистру. Нафига устанавливать данные, которые потом перезапишутся?

первый
делаем resize получателю и заменяем символы. не нравится resize — он установит значения символов, которые потом будут перезаписаны.

второй
делаем reserve и push_back-ом добавляем преобразованные символы. Не нравится push_back — он будет каждый раз пытаться резервировать место, которое и так уже есть.

Пока писал, на ум пришел шаблонный метод std::string::assign, которому передают хитрые итераторы, которые будут преобразовывать поток символов.

Как-то так:

char upper_char_op(char c) {...}

//...

transform_range r(source_begin, source_end, upper_char_op);

// оператор * будет пропускать символы через upper_char_op
std::string s(r.begin(), r.end());


То есть, в итоге, вопрос такой — в STL есть что-то подобное transform_range или нужно изобретать свой велосипед?
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re: std::string, копирование с трансформацией символов
От: LaptevVV Россия  
Дата: 08.07.18 14:20
Оценка: +2
КД>Проблема на ровном месте
КД>Есть строка, которую надо скопировать в std::string с приведением символов к верхнему регистру.
toupper() посмотри
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re: std::string, копирование с трансформацией символов
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 09.07.18 08:29
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>То есть, в итоге, вопрос такой — в STL есть что-то подобное transform_range или нужно изобретать свой велосипед?

Тут, первая ссылка в гугле
std::string str_toupper(std::string s) 
{
    std::transform(s.begin(), s.end(), s.begin(), 
                   [](unsigned char c){ return std::toupper(c); }
                  );
    return s;
}
Sic luceat lux!
Re: std::string, копирование с трансформацией символов
От: vadfromnu  
Дата: 09.07.18 11:44
Оценка: 20 (2)
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>То есть, в итоге, вопрос такой — в STL есть что-то подобное transform_range или нужно изобретать свой велосипед?


Учитывая, что в бусте есть transform_iterator, который делает то, что вам нужно. Я предположу, что этого нет в стандарте.

#include <iostream>
#include <string>
#include <cctype>
#include <boost/iterator/transform_iterator.hpp>

int main()
{
    const std::string in = "str";
    auto beg = boost::make_transform_iterator(in.begin(), toupper);
    auto end = boost::make_transform_iterator(in.end(), toupper);
    std::string out(beg, end);
    std::cout << out << std::endl;

    const char in2[] = "raw";
    auto beg2 = boost::make_transform_iterator(in2, toupper);
    auto end2 = boost::make_transform_iterator(in2 + 3, toupper);
    std::string out2(beg2, end2);
    std::cout << out2 << std::endl;
    return 0;
}
Re: std::string, копирование с трансформацией символов
От: RedApe Беларусь  
Дата: 11.07.18 04:43
Оценка: +1
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Текущие варианты, которые не нравятся.


Чуда не случится. В итоге в варианте с transform будет то же самое: либо создание буфера через reserve либо добавление по одному символу через push_back, которые оба тебе почему-то не нравятся.
--
RedApe
Re: std::string, копирование с трансформацией символов
От: swingus  
Дата: 11.07.18 17:54
Оценка:
А foreach или for на проекте пользоваться нельзя?

Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Проблема на ровном месте
Re[2]: std::string, копирование с трансформацией символов
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 12.07.18 14:05
Оценка:
Здравствуйте, swingus, Вы писали:

S>А foreach или for на проекте пользоваться нельзя?


Формально, можно что угодно — это мой проект. Но желательно без фанатизма

В итоге я остановился на нулевом варианте (ленивый стал ...):

 std::transform
  (pstr->cbegin(),
   pstr->cend(),
   pstr->begin(),
   structure::t_latin_upper<char_type>());


Но идея с transform_iterator мне очень понравилась.

---
И да — toupper фтопку. Тормозит и глючит
Автор: Коваленко Дмитрий
Дата: 11.10.17
.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Отредактировано 12.07.2018 18:16 DDDX . Предыдущая версия .
Re[2]: std::string, копирование с трансформацией символов
От: cures Россия cures.narod.ru
Дата: 12.07.18 16:21
Оценка:
Здравствуйте, Kernan, Вы писали:

K>std::string str_toupper(std::string s)


А аргумент s откуда возьмётся? Его скопируют из старой строки.
Это именно нулевой вариант топикстартера, с установкой и последующей переустановкой символов, два прохода, очень медленно.
Re[2]: std::string, копирование с трансформацией символов
От: cures Россия cures.narod.ru
Дата: 12.07.18 16:37
Оценка:
Здравствуйте, vadfromnu, Вы писали:

V>Учитывая, что в бусте есть transform_iterator, который делает то, что вам нужно.


Он, конечно, делает. Но вся радость от него — он заметает всю лишнюю работу под шкаф, чтобы нежный программист на неё вдруг не наткнулся. Boost — вообще не про скорость, он про высокие материи и глубокий внутренний мир.

V>Я предположу, что этого нет в стандарте.


Увы, если от работы нельзя избавиться по стандарту, то написанные над этим стандартом библиотеки никак в этом не помогут.
По-хорошему, после резерва (в реальности — malloc/realloc) нужно было бы тупо установить текущий size равным capacity. Но на это стандартизаторы пойтить никак не могут, вдруг где-то что-то недоинициализируется. И так не только со строками, но и с массивами. Обходящая это библиотека могла бы тупо, зная смещения переменных относительно объекта в данной версии компилятора и стандартной библиотеки, прочитать и записать по соответствующим адресам. Но за это она сразу станет нерукопожатной, а boost — не такой, он же, фактически, главный резерв партии, поставщик новых фич в стандарт.

В общем, стандартизаторы давно уже отменили правило Трупа Страуса "чем не пользуешься — за то не платишь".
В iostream и вокруг него это гораздо хуже, там за нафиг не нужные (и не используемые) локали приходится платить очень дорого. Ввод массива целых чисел из текстового файла в лучшем случае на полтора порядка дороже их ручного вычитывания.
А недавно они ещё с односвязными списками прикололись, от большого ума потребовали константный по времени метод size. В результате split стал линейным, от чего сам Степанов офигел.
Re: std::string, копирование с трансформацией символов
От: cures Россия cures.narod.ru
Дата: 12.07.18 16:47
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Не нравится push_back — он будет каждый раз пытаться резервировать место, которое и так уже есть.


Не пытаться, а каждый раз проверять. Для больших строк — самый быстрый способ, так так укладывается в один проход по памяти, а память нынче — самое медленное место компьютера.
Для маленьких может зависеть от компилятора. Дело в том, что эта проверка будет всегда выдавать положительный ответ, а значит будет надёжно предсказана процессором, и времени займёт или очень мало или вообще отрицательное. Например, в g++, как правило, выкидывание assert-ов приводит к замедлению программы.

КД>То есть, в итоге, вопрос такой — в STL есть что-то подобное transform_range или нужно изобретать свой велосипед?


Даже если вдруг когда и появится (скажем, из буста, упомянутого в другом комменте), всё равно будет работать через тот же push_back. Уровень абстракции может только повышаться, да и сговора с производителями железа никто не отменял.
Re[2]: std::string, копирование с трансформацией символов
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 12.07.18 18:28
Оценка:
Здравствуйте, cures, Вы писали:

КД>>То есть, в итоге, вопрос такой — в STL есть что-то подобное transform_range или нужно изобретать свой велосипед?


C>Даже если вдруг когда и появится (скажем, из буста, упомянутого в другом комменте), всё равно будет работать через тот же push_back. Уровень абстракции может только повышаться, да и сговора с производителями железа никто не отменял.


Вообще говоря, эти transform-итераторы будут передаваться в string::assign, который не факт что работает через push_back.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[3]: std::string, копирование с трансформацией символов
От: cures Россия cures.narod.ru
Дата: 12.07.18 19:08
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Вообще говоря, эти transform-итераторы будут передаваться в string::assign, который не факт что работает через push_back.


В хелпе у стринга вижу только один вариант ассигна с итераторами, при этом про них сказано, что должны удовлетворять только требованиям InputIterator, который сугубо последовательный. Оно, конечно, не означает, что разработчики какой-нибудь либы не могут проверить, что там на самом деле рандом акцесс, и оптимизировать этот случай. Но означает (если повар нам не врёт), что не будут обязаны этого делать, а стало быть использование такой оптимизации бедет ненадёжным хаком.
А так-то кто же мешает налабать свои трансформирующие итераторы, скормить ассигну и посмотреть на результат.
Re[2]: std::string, копирование с трансформацией символов
От: vopl Россия  
Дата: 13.07.18 07:41
Оценка:
Здравствуйте, cures, Вы писали:

КД>>Не нравится push_back — он будет каждый раз пытаться резервировать место, которое и так уже есть.


C>Не пытаться, а каждый раз проверять. Для больших строк — самый быстрый способ, так так укладывается в один проход по памяти, а память нынче — самое медленное место компьютера.

C>Для маленьких может зависеть от компилятора. Дело в том, что эта проверка будет всегда выдавать положительный ответ, а значит будет надёжно предсказана процессором, и времени займёт или очень мало или вообще отрицательное. Например, в g++, как правило, выкидывание assert-ов приводит к замедлению программы.

отрицательное — а как это вообще?
Re[3]: std::string, копирование с трансформацией символов
От: cures Россия cures.narod.ru
Дата: 13.07.18 13:42
Оценка:
Здравствуйте, vopl, Вы писали:

V>отрицательное — а как это вообще?


Легко! Внутреннее устройство современных процессоров настолько сложное и закрытое, что компилятор не может толком оценить, какой вариант кода будет дешевле, и, соответственно, оптимизировать порождаемый код для быстродействия.
В современном gcc/g++, а он нынче один из лучших в смысле производительности порождаемого кода, очень часто (на моей практике — почти всегда) добавление внутрь самых горячих циклов assert-а, который всегда выполняется, приводит к ускорению работы программы. В случае push_back имеем то же самое: постоянные проверки, результат которых предсказан, могут ускорить код. Просто за счёт того, что чуть иначе лягут конвейеры инструкций в глубинах процессора.
Такая фигня началась в поздних версиях с мажором 4. У меня была программа, кажется, для задачи 150 с ProjectEuler, которая при компиляции более поздней четвёркой работала ровно вдвое медленней, чем при компиляции более ранней. Ну а когда компилятор тупо сливает двойку самому себе, совершенно не удивительно, что добавление мусора к коду может склонять его к чуть "худшей" оптимизации из предыдущей версии, когда итоговый код работает быстрее.
Re[4]: std::string, копирование с трансформацией символов
От: vopl Россия  
Дата: 13.07.18 14:30
Оценка:
Здравствуйте, cures, Вы писали:

V>>отрицательное — а как это вообще?


C>Легко! Внутреннее устройство современных процессоров настолько сложное и закрытое, что компилятор не может толком оценить, какой вариант кода будет дешевле, и, соответственно, оптимизировать порождаемый код для быстродействия.

C>В современном gcc/g++, а он нынче один из лучших в смысле производительности порождаемого кода, очень часто (на моей практике — почти всегда) добавление внутрь самых горячих циклов assert-а, который всегда выполняется, приводит к ускорению работы программы. В случае push_back имеем то же самое: постоянные проверки, результат которых предсказан, могут ускорить код. Просто за счёт того, что чуть иначе лягут конвейеры инструкций в глубинах процессора.

аа... понятно о чем речь. Есть серьезные сомнения что производительность увеличивается "почти всегда". Есть мнение что она, наоборот, уменьшается почти всегда, а увеличивается крайне редко, если повезет. К сожалению, без пруфов, говорю просто из опыта.
Re[2]: std::string, копирование с трансформацией символов
От: rg45 СССР  
Дата: 18.07.18 08:24
Оценка: 4 (1)
Здравствуйте, vadfromnu, Вы писали:

V>Учитывая, что в бусте есть transform_iterator, который делает то, что вам нужно.



Этот подход хорош тем, что позволяет сразу создать объект строки в нужном состояни, возможно, консттантный (в отличие от других решенией, подразумевающих создание модифицируемой заготовки с последующим допиливанием).

Для достижения большей компактности иногда будет полезно использование boost::range с адапторами:

https://ideone.com/mtDtt0

  const std::string input = "Hello, World!";
  const auto& transformed = boost::adaptors::transform(input, ::toupper);
  const std::string output(transformed.begin(), transformed.end());
--
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.