результат.
GCC сейчас уже сравнивает строки так, буд-то бы это интегральные типы. т.е. в псевдокоде типа этого: int v0 = *(int64*)"GLOBAL", v1 = *(int64*)levelStr; if (v0==v1) ...
Intel же снова умничает.
в некоторых if`ах он использует memcmp(), а в некоторых поступает как GCC. похоже, зависит от длины константной строки...
корректность использования memcmp() для константных длин — отдельный вопрос, но можем сделать и так:
вопрос эффективности я рассматривать не буду из-за недостаточной компетенции в ассемблерных вопросах, и из-за лени.
к этим тестам я пришел после прочтения кода этого проекта. меня всегда удивляли подобные конструкции, ветвления на основе сравнения строк, иногда множество лишних сравнений пока не найдется нужная ветка.
Код с memcmp приводит в выходу за границу массива когда levelStr короткая.
Код с strcmp тоже сломан, так как gLoBAl уже не прокатит.
Если хочется оптимизации, то не стоит сразу нырять в ассемблер.
Можно проверить длину levelStr, если она укладывается в диапазон длин проверяемых названий, то содержимое levelStr можно копировать в верхнем регистре в буффер и смело сравнивать по одному разу с каждым названием в том же регистре при помощи memcmp. Если названий много и они длинные, то тогда может иметь смысл вместо перебора сделать маp в коком-то виде.
А стоит ли этот кусок вообще оптимизировать? Может он всего один раз за все время жизни приложения вызывается.
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Здравствуйте, VTT, Вы писали:
VTT>Код с memcmp приводит в выходу за границу массива когда levelStr короткая.
я же об этом написал и привел поправленный вариант.
VTT>Код с strcmp тоже сломан, так как gLoBAl уже не прокатит.
а должно? в исходной задаче этого нет.
VTT>Можно проверить длину levelStr, если она укладывается в диапазон длин проверяемых названий
в предпоследнем фрагменте кода я почти так и сделал...почти...
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Здравствуйте, niXman, Вы писали:
X>Здравствуйте, VTT, Вы писали:
VTT>>Код с memcmp приводит в выходу за границу массива когда levelStr короткая. X>я же об этом написал и привел поправленный вариант.
А когда я смотрел пост в первый раз он был намного короче...
VTT>>Код с strcmp тоже сломан, так как gLoBAl уже не прокатит. X>а должно? в исходной задаче этого нет.
Так там и условия задачи нет, и тестов для проверки тоже вроде нет.
Но раз проверяются оба регистра, то наверное эта проверка может считаться не чувствительной к регистру.
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Здравствуйте, niXman, Вы писали:
X>я бы решил это как-то так:
Но ты же понимаешь, что твой код выдаёт другие ответы?
Например, в твоём варианте convertFromString("WTF") == Level::Warning, но Level::Unknown в исходном.
X>вопрос эффективности я рассматривать не буду
А в чём тогда вопрос-то? Если на эффективность плевать, то и исходный вариант сойдёт. Если же эффективность важна, то просто используют PHF. Например, в виде готовой утилиты gperf, которая по списку строк сама сгенерирует код похожий на твой, но с куда меньшим количеством багов (то есть, который будет корректно обрабатывать случаи когда строка ни с чем не совпадает вообще).
Здравствуйте, VTT, Вы писали:
VTT>А когда я смотрел пост в первый раз он был намного короче...
пост не редактировался, иначе было бы видно.
VTT>Так там и условия задачи нет, и тестов для проверки тоже вроде нет. VTT>Но раз проверяются оба регистра, то наверное эта проверка может считаться не чувствительной к регистру.
ну хз. я не любитель гадать, сделал в соответствии с исходным кодом.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Здравствуйте, watchmaker, Вы писали:
W>Но ты же понимаешь, что твой код выдаёт другие ответы? W>Например, в твоём варианте convertFromString("WTF") == Level::Warning, но Level::Unknown в исходном.
ну...теоритически да. на практике же, эта функция парсит лог, который сама и сгенерила.
X>>вопрос эффективности я рассматривать не буду W>А в чём тогда вопрос-то?
я об эфектиности ассемблерных кодов.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Здравствуйте, niXman, Вы писали:
X>занудамод.
.... X>меня всегда удивляли подобные конструкции, ветвления на основе сравнения строк, иногда множество лишних сравнений пока не найдется нужная ветка.
вот тут присоединюсь. всегда вгоняет в депрессию подобный код
лично я предпочитаю в таких случаях делать ассоциативные контейнеры + поиск
мета-код
лишь один if — это гораздо проще, нежели 8 if. декларативно и компактно записывается маппинг.
причем масштабируется легко с увеличением вариантов (все равно 1 if будет)
то есть мои предпочтения по порядку:
1) use switch
2) use map
3) use many if-s
Здравствуйте, niXman, Вы писали:
X>к этим тестам я пришел после прочтения кода этого проекта. меня всегда удивляли подобные конструкции, ветвления на основе сравнения строк, иногда множество лишних сравнений пока не найдется нужная ветка.
Большинство строк в прогах, особено в парсерах, по длине не превосходят размеры SSE2/AVX регистров, эти строки без проблем целиком загружаются в эти регистры и сравниваются одной ассемблерной инструкцией, нужно только написать свою реализацию strcmp/memcmp специально для сравнения небольших строк.
Здравствуйте, antropolog, Вы писали:
A>Здравствуйте, niXman, Вы писали:
A>Сравнение строк всё равно не эффективно. Но лично я бы использовал (и почти всегда использую) тернарный оператор для подобного "паттерн-матчинга":
A>
A>static Level convertFromString(const char* levelStr) {
A> return levelStr == nullptr ? Level::Unknwonwn
A> : strcasecmp(levelStr, "global" ) == 0 ? Level::Global
A> : strcasecmp(levelStr, "debug" ) == 0 ? Level::Debug
A> : strcasecmp(levelStr, "info" ) == 0 ? Level::Info
A> : strcasecmp(levelStr, "warning" ) == 0 ? Level::Warning
A> : strcasecmp(levelStr, "error" ) == 0 ? Level::Error
A> : strcasecmp(levelStr, "fatal" ) == 0 ? Level::Fatal
A> : strcasecmp(levelStr, "verbose" ) == 0 ? Level::Verbose
A> : strcasecmp(levelStr, "trace" ) == 0 ? Level::Trace
A> : Level::Unknown;
A>}
A>
Этот код не эквивалентен оригиналу в начале.
Тут "Global" сработает правильно , а в оригинальном нет.
Здравствуйте, smeeld, Вы писали:
S>Кстати, кто в теме, есть ли в boost какое-либо решение, специально для ускорения сравнения строк?
вот: https://github.com/WojciechMula/simd-string
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)