- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
function test3()
{
const a = 10.5
switch (a)
{
case 10.5:
print("cool. 10.5");
break;
}
}
function test3()
{
switch ("kokoko")
{
case "kokoko":
print("pituh");
break;
}
}
Причём оптимальным образом — сделает бинярный поиск по хэшам!
https://neerc.ifmo.ru/wiki/index.php?title=Идеальное_хеширование
Одними констэспрами это не решить.
Аллокаторы какие-то
Операторы delete какие-то
В сгенерированном коде из
ничего этого нет. Ни единого выделения на хипе. Где ваше хваленое "zero-cost abstraction"?
, но тогда придётся бинярный поиск по хэшам вручную делать (в случае с обычным switch () {case} компилятор его сам делает).
И чтоб из этого допустим switch-case код нагенерился, и количество пар ключ-значение произвольно.
Тут не генерируется никакого switch.
Давай так. Забудь вообще про perfect hash.
В коде https://wandbox.org/permlink/A2SBKuw91OCYKXl1 есть конструкция
Вот я хочу просто сделать штуку, которая принимает через шаблонные параметры пары ключ-значение, и чтоб из этого в компилтайме генерировался код соотв. функции с такими-то свитчами. Я не хочу отдельно что-то описывать!
Где там конкретно конструкция switch - case в твоем примере?
> А компилятор умеет генерировать оптимальные хеши без коллизий, если заранее известы все возможные вариации?
Ответ — да, умеет. Теперь это нядо посыпать сахаром?
Ну так... если не посыпать сахаром, с этим отлично справится кодогенерация, и никакие супер-пупер фичи крестов не требуются.
На констэкспрах, раз уж на то пошло, можно набросать собственный компилтайм-мини-компилятор который понабросает опкодов процессора куда-то, и потом это "куда-то" можно сделать в RX сегменте, кастануть в функцию и вызывать. Надо ли говорить, что такой подход не совсем адекватный?
Вопрос в другом: ты убедился, что constexpr-ушня может сгенерировать perfect hash?
В крестах для генерации кода нужно шаблоноговно использовать, а это уже другая хуйня, которую констэкспрами не выразить.
https://gcc.godbolt.org/z/droEe4Yrs
Задачу прикручивания к этой фигне perfect hash'а и мутабельных лямбд оставляю ня тебя (*^‿^*)!
Что явня быстрее любых perfect hash'ей и бинярных поисков.
И там проблемы с оптимизацией заметны, компилятор почему-то делает jne .L20 на метку для инструкции ret в самом конце, хотя инструкция ret и так есть на метке .L1 которая идет после инструкции jmp puts который управление не вернет, так что кусок кода
нафиг не нужен. Переход на метку .L20 можно заменить на переход на метку .L1
GCC и MSVC. Шланг ня может.
> jne .L20
Это всё равно холодный путь, так что никакого влияния ня перформанс ня окажет.
Кроме того, начиная с какого-то там количества вариантов, подход с таблицей поиска оказывается лучше хрени с условями. И фиг его знает, что там компилятор понакомпилириует
То ли дело сишка!
https://gcc.godbolt.org/z/qq8vxvbze
Позорище!
На сишке я вручную это запрограммирую(возможно даже в асмовставке), если оно окажется боттлнеком.
Имення так. Вообще, сишники — это те же джависты, только вместо get set hashcode equals пишут вручную вообще всё: от управления ресурсами до исключений через setjmp.
И получается, чсх, быстрее и эффективнее, чем какая-то заумная крестометушня, которая работает не во всех компиляторах и требует последний стандарт.
[citation needed]
Пока что мы лишь увидели, как линейный поиск по заранее заданным строкам в крестах как тузик грелку порвал точня такой же линейный поиск по заранее заданным строкам в сишке.
https://wandbox.org/permlink/hrNq6pmrUutcxCt5 - примитивная кодогенерация.
https://gcc.godbolt.org/z/3a631c6Yx - результат.
Сравни это с https://gcc.godbolt.org/z/aa6Eqeze5 по качеству машинного кода.
И сразу же получают оптимальный код.
https://gcc.godbolt.org
компилятор может сделать табличку поиска, т.е. попросту говоря массив из указателей на функции (или возможно на блоки кода), и в arr[1] будет присвоен указатель на функцию smth1(), в arr[2] будет присвоен указатель на функцию smth2() и так далее. И это будет быстрее хешей и бинарного поиска. Оптимизация хуиты в swich это вообще целая наука. Глупо надеяться на то, что можно сделать всё оптимально, используя какой-то там хэш
Но массив указателей это правда круто
ну так где свитч с бинароным поиском по хешу, а где 100500 strcmp
Можно, кстати, и не по хешам, а просто разбить слова на буковки, и сделать дерево по буковкам же
У меня в реальном коде используется имення такой свитч. И да, компилятор действительня превращает его в бинярное дерево:
https://gcc.godbolt.org/z/9jzYYcvha
Проверки ня коллизии выкинуты для няглядности.
https://wasm.in/archive/pub/9/pic/p33.gif
Если крестовым говнометапрограммированием нельзя просто понабрасывать меток case в этот switch и дать компилятору делать свое дело, нужно как-то ручками нагенерировать кучу if() хреней оптимальным образом (занимаясь работой компилятора).
Нет уж, лучше руками написать свитч, и пусть ебется компилятор, ведь он умел это еще в 2002-м году.
Интересно другое: один свитч на 20 веточек получается оптимальнее, чем 20 ифэлсов.
Потому что одна ошибка предсказания дешевле чем пять, лол.
Но замечание Криса в том, что если ты заранее знаешь все возможные варианты, то ты просто ложишь их в двоичное дерево, и потом можешь по ним скакать за логорифм.
Можно кстати посчитать от них хеши, и сделать хетаблицу.
Иногда компиляторы могут 20 ифелсоф распознать как switch и заоптимизировать его по аналогичной схеме.
Это нязывается "бинарный поиск".
https://konyakov.ru/pubs/books/kris-kaspersky-r_i_p/kris-kaspersky-27.pdf
> Балансировка логического дерева
> Учитывая, что x86 процессоры все три операции сравнения <, =, > совмещают в одной машинной команде, двоичное логическое дерево можно преобразовать в троичное,тогда новых гнезд для его балансировки добавлять не нужно. Простейший алгоритм, называемый методом отрезков,работает так: сортируем все числа по возрастанию и делимполучившийся отрезок пополам. Число, находящееся по-середине (в нашем случае это 11), объявляем вершинойдерева, а числа, расположенные слева от него, – его левы-ми ветвями и подветвями (в нашем случае это 0, 3, 4 и 7).Остальные числа (22, 96, 98, 666, 777) идут направо.
Х.з., это точно хороший хак? Пруфы пирфоманса есть?
Я думаю что это от процессора зависит сильно. Ну вообще можно побенчмаркать конечно.
Если какой-то 8-битный говноконтроллер без префетчей, там вполне норм будет
о, бля, у вам там целый тредик про это
изхвини
вообще свищ по строкам -- штука не однозначная, в реальном мире у нее мало полезных кейсов (кроме разве что literal types в TS) и скриптушне
интересно, на кой черт ее завезли в джавы и C#?
LM-хеш вычисляется следующим образом:
* Пароль пользователя приводится к верхнему регистру.
* Пароль дополняется нулями или обрезается до 14 байтов.
* Получившийся пароль разделяется на две части по 7 байтов.
* Эти значения используются для создания двух ключей DES, по одному для каждой 7-байтовой половинки, при этом 7 байтов рассматриваются как битовый поток и после каждых 7 битов вставляется ноль. Так создаются 64 бита, необходимые для ключа DES.
* Каждый из этих ключей используется для DES-шифрования ASCII-строки «KGS!@#$%», в результате получаются два 8-байтовых шифрованных значения.
* Данные шифрованные значения соединяются в 16-байтовое значение, являющееся LM-хешем.
Как вообще можно было додуматься обрезать пароли? Почему бы честно не сказать юзеру, что его пароль слишком длинный?
В 1993-м году о безопасности даже в большом Интернете не думали (finger в inetd наружу торчал), а уж в опенспейсовых кубиках офисов и подавно.
Эти сервисы закрылись после того, как ими воспользовались спамеры. Удобня: раньше можно было брутить е-мейлы для спам-баз без отправки писем.
«Виста» 2006-го года шла со списком таких сервисов, хотя они уже не работали.
Задепрекейтили их только после того, как стало много NAT'ов.
Представляешь, какой был уровень доверия?
Это зачем?
POP3 умел AUTH из коробки, а SMTP не умел.
Его туда завезли относительно недавно (точнее фреймворк SASL)
https://datatracker.ietf.org/doc/html/rfc4954
Как было публичным почтовикам разрещать пользователю посылку пписем?
Только через POP before SMTP.
За натом можно было помочь соседу, конечно.
Но всё таки легитимный юзер и сраный спамер редко сидят в одной локалке
Запросто.
https://ideone.com/dB8clW
Затем оставшееся место добивают нулями.
Как видим в компайл-тайме всё оптимизируется в константы
https://gcc.godbolt.org/z/7xPEabYYx
Теперь работает на длинных строках, однако короткие по-прежнему оптимизируются в mov/cmp/je.
Также сделал SWITCH более «бейсиковским» и добавил поддержку break.
https://ideone.com/a4Ni8C
https://govnokod.ru/27392#comment625532
В той ветке даже решение с идеальным хэшированием есть <( ̄︶ ̄)>!
Мы няк раз ждали девочек-волшебниц: Полиняшу и Бормандяшу.
https://govnokod.ru/27287#comment617046
Мне кажется, я их видел на ГК несколько лет назад.
https://govnokod.ru/27392#comment625532
Мне всё покоя не даёт случай, если в 64-битное сравение подсунут строку с мусором.
В остальном пример с strcmp работает замечательно, лучше хеша.
http://graphics.stanford.edu/~seander/bithacks.html
Я хотел посчитать количество ведущих нулей и сравнить.
Но, во-первых, это непортабельность на big-endian.
Во-вторых, не поможет с "syoma\0\0z" == "syoma"
Хотя технически строки одинаковы.
Придётся при каждом неравенстве звать strcmp (прощай пирформанс).
Похоже без магии девочек-волшебниц мне ня обойтись