1. Си / Говнокод #12822

    +140

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    static inline uint64_t parse_hex_uint64(const char *s) {
        const uint64_t m1 = 0x4040404040404040ll;
        const uint64_t m2 = 0x000F000F000F000Fll;
        const uint64_t m3 = 0x0F000F000F000F00ll;
        const uint64_t *p = (const uint64_t*)s;
        int64_t a = p[0], b = p[1];
        a += ((a & m1) >> 6) * 9;
        b += ((b & m1) >> 6) * 9;
        a = (a & m2) << 12 | (a & m3);
        b = (b & m2) << 12 | (b & m3);
        a |= a >> 24;
        b = b >> 8 | b << 16;
        return (a & 0x0000FFFF00000000ll) | (a & 0xFFFF) << 48 | b >> 48 | (b & 0xFFFF0000);
    }

    По мотивам http://govnokod.ru/12800#comment173346.

    Байтоёбский парсинг шестнадцатеричного числа. Версия для 64 битного проца.

    https://ideone.com/IFG0fH

    Запостил: bormand, 29 Марта 2013

    Комментарии (124) RSS

    • В строке 6 конечно же uint64_t.
      Ответить
    • не знаю, плюсовать или нет, плюс ведь будет означать, что говнокод

      ждём base64
      Ответить
      • Вы так говорите, как будто это не говнокод ;)

        base64 на стадии проектирования на бумажке, свободного времени на него пока нет.
        Ответить
      • Почти пять лет ушло на разработку ядра преобразования:
        static uint64_t decode_chunk(uint64_t a)
        {
            uint64_t m = 0x0101010101010101ull;
            uint64_t u, r = a;
            u = (a >> 5) & m;
            r -= 6 * u;
            u = (a >> 6) & m;
            r -= 75 * u;
            u |= (a >> 4) & m;
            r -= 12 * u;
            u |= (a >> 2) & m;
            r -= 3 * u;
            return r + 0x1919191919191919ull;
        }
        Ответить
        • Осталось убрать лишние биты...
          Ответить
        • В первом приближении получается так (8 символов в base64 → 6 байт):
          static uint64_t decode(uint64_t a)
          {
              uint64_t m = 0x0101010101010101ull;
              uint64_t u, r = a + 0x1919191919191919ull;
          
              u = (a >> 5) & m;
              r -= 6 * u;
              u = (a >> 6) & m;
              r -= 75 * u;
              u |= (a >> 4) & m;
              r -= 12 * u;
              u |= (a >> 2) & m;
              r -= 3 * u;
          
              r = (r & 0x00FF00FF00FF00FFull) | (r & 0xFF00FF00FF00FF00ull) >> 2;
              r = (r & 0x0000FFFF0000FFFFull) | (r & 0xFFFF0000FFFF0000ull) >> 4;
              r = (r & 0x00000000FFFFFFFFull) | (r & 0xFFFFFFFF00000000ull) >> 8;
          
              return r;
          }
          Ответить
          • Блин, не всё так просто с поклейкой битов... Base64 то big-endian. Опять я какую-то хуету написал.
            Ответить
            • Ты петух, в дурном смысле этого слова.
              Ответить
            • Вот так надо:
              r = (r & 0x0000003F0000003Full) << 2 |
                  (r & 0x0000300000003000ull) >> 12 |
                  (r & 0x00000F0000000F00ull) << 4 |
                  (r & 0x003C0000003C0000ull) >> 10 |
                  (r & 0x0003000000030000ull) << 6 |
                  (r & 0x3F0000003F000000ull) >> 8;
              r = (r & 0x00000000FFFFFFFFull) |
                  (r & 0xFFFFFFFF00000000ull) >> 8;
              Ответить
          • > FFFFull
            Всё, хватит, оно уже полное!
            Ответить
            • Когда у тебя первый раз возникло желание засунуть в прямую кишку карандаш?
              Испытал ли ты при этом оргазм?
              Ответить
              • Кто о чем, а стертор о прямой кишке.

                Карандаш же острый. Насколько надо упороться, чтобы куда-то его совать?
                Ответить
        • > Почти пять лет
          и вот наконец-то я понял о чем мне постоянно твердили более опытные товарищи
          только ведь не 100 строк в неделю, а 30 в 5 лет!
          Ответить
      • Кого ебёт твой плюс или минус?
        Ответить
    • Я жду ваших объяснений
      Ответить
      • В строках 7-8 парсятся шестнадцатеричные цифры, в 9-13 они переставляются местами и формируют ответ. Что тут непонятного, guest?
        Ответить
    • Кроме base64 есть еще один хороший кандидат:
      http://en.wikipedia.org/wiki/Cantor_function
      . Нужно представлять числа в троичной системе, делать хитрые замены битов.
      Вот написать бы к этой функцие прямое (вместо итеративного) вычисление? ;)
      Ответить
      • В троичное без цикла хер переведешь...
        Ответить
      • кому нужно представлять числа в троичной системе?
        base64 туда-сюда гоняется по сети гораздо чаще, причем его объемы вполне позволяют пачкой обрабатывать блоки
        Ответить
        • Подождите... вы же не говорите, что функция выше кому-то нужна. В том смысле, что цикл / таблица почти наверняка будут и короче и оптимальнее.
          Ответить
          • всем, кто прогулял вчерашнюю байтоёбскую оргию, рекомендовано пройти по ссылке в описании
            Ответить
          • > цикл
            > оптимальнее
            *facepalm*. Здесь 39 ассемблерных инструкций (если я не обсчитался), т.е. в районе 2.5 инструкций на разряд, и ни одного перехода.

            Обогнать по идее можно только раскрученным циклом и табличкой которая преобразовывает 2 цифры в один байт (65кб). Но это нанесет удар по L1.

            > почти наверняка
            Предлагайте алгоритм, буду рад провести бенчмарк ;)

            P.S. У этой функции, конечно же есть и недостаток - на кривых данных ее поведение не определено.
            Ответить
            • http://liveworkspace.org/code/33rWZ9$1
              что-то не сходится в твоей функции, не знаю почему
              но показатели времени хорошие
              Ответить
              • А это та самая бага сказалась: в строке 6 конечно же uint64_t..

                http://liveworkspace.org/code/33rWZ9$3
                Ответить
                • Домен liveworkspace.org прокукарекали.

                  Кстати, какие подобные сервисы сейчас существуют? У меня в кокококоллекции такие:
                  https://ideone.com/
                  https://godbolt.org/
                  https://wandbox.org/
                  https://rextester.com/
                  http://codepad.org/
                  http://coliru.stacked-crooked.com/
                  Ответить
                  • Добавляю:
                    https://www.codechef.com/ide
                    https://tio.run/
                    https://code.hackerearth.com/
                    Ответить
                    • "Forth" есть только на ideone.com и tio.run :(

                      На tio.run, кстати, самое большое число языков, ограничение по времени там, если не ошибаюсь чуть ли не минута, и вообще он самый удобный.

                      З.Ы. вопрос об онлайн-конпеляторах: достаточно ли им запускать код в виртуоленной мышыне которой нет доступа к сети и там ещё не знаю что, чтобы было бизапасна?
                      Ответить
                    • https://www.tutorialspoint.com/codingground.htm
                      Очень много языков, включая «Аду», «Brainfuck» и «Forth».
                      Ответить
                  • http://quick-bench.com/
                    Быстрый бенчмарк для кода на крестах/цэ, очень удобная штука для холиваров.
                    Ответить
                    • Нет "Forth'а" —– сразу нахуй.
                      Ответить
                      • Разве божественному «Forth» нужны какие-то анскильные «бенчмарки»?!
                        Ответить
                        • Действительно, я ни разу нигде не слышал про программы написанные на "Forth" что они тормозные.

                          Именно поэтому я за "Forth".

                          Походу кто-то опять досит говнокодик :(
                          Ответить
                  • В копилку:
                    https://cppinsights.io/about.html

                    Не компилятор и не песочница, а что-то типа современного аналога Cfront: компилирует лямбды, for по итераторам, auto, decltype, рекурсивные шаблоны, инициализаторы в фигурных скобках в конструкции, понятные C++03/C++98.

                    Спасибо Elvenfighter.
                    Ответить
            • const unsigned char table[23] =
                { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15 };
              
              const unsigned int hex_to_int(const char* hex) {
                int i = -1;
                unsigned int result = 0;
                unsigned char digit;
                while (digit = hex[++i]) {
                  result = result << 4 | table[digit - 48];
                }
                return result;
              }

              Хз, бенчмарков не делал, ну и как бы ничего в этом нетривиальног вроде нет... Ну да делать бенчмарки функций которые в принципе никогда не будут выполнять ничего такого, что может повлиять на производительность? :) Как бы даже не знаю... я чет совсем не в настроении спорить, ну точно не про производительность такой функции.
              Ответить
              • http://liveworkspace.org/code/33rWZ9$13
                да разве ж нам жалко сделать бенчмарк?

                вот так вот одно вычитание ухудшает почти в 2 раза результат, притом, что с маленькими буквами не работает вовсе
                Ответить
                • Маладца Борманд! Всех забайтоебал!
                  Ответить
                  • Вообще-то я эту идею предложил: конвертить пачками без условий и лупов, а в ответ же были скептические отзывы.
                    И потом распинался почему оно должно быть быстрее.

                    >вот так вот одно вычитание ухудшает почти в 2 раза
                    > маленькими буквами не работает вовсе
                    В старом треде вы же сами постили:
                    chr & ~(_T('a') - _T('A'))
                    Ответить
                    • почему снова все ко мне на вы, я так плохо выгляжу?
                      Ответить
                      • Вовсе нет, сер Пикард.
                        Ответить
                      • У меня возникла идея. Добавить в личную кабинку селектор:
                        Как ко мне обращаться?
                        (о) на «вы»
                        (•) на «ты»
                        (о) на «ёб твою мать»
                        (о) мне не нужно отвечать


                        Забавно, но раньше на «Говнокоде» было популярным обращение на «вы», а сейчас чаще обращаются на «ты».
                        Ответить
                  • >Маладца Борманд! Всех забайтоебал!
                    Вот у меня руки дошли сделать бенч. И оказалось, как я и думал впрочем, бутылочое горлышко в перестановке. И всё работает еще быстрее.
                    http://liveworkspace.org/code/1lmQMa$15

                    Да и в целом всё оказалось еще удивительное. Не пойму почему мой вариант с проверками (который содержит раза в 3-4 больше кода) работает так же быстро как и борманда:? 26ms

                    Логично предположить что еще где-то есть тормознутый кусок. То есть преимущество над жалкими потугами с условиями и таблицами, как я и предполагал, в десятки раз.
                    Хе-хе-хе.
                    Ответить
                    • Бормондовский оптимизирован под интел, а твой под амд
                      Ответить
                      • Поясните мысль.
                        Ответить
                        • интел лучше без условий работает на чистой арифметики, а амд под с условиями, убирающими лишнее исполнение
                          Ответить
                          • >интел лучше без условий работает на чистой арифметики, а амд под с условиями
                            Спорное утверждение. У интела уже лет 7 лучше переходы предсказываются. Вообще интел лучше работает. А у амд ядер больше за те же деньги.

                            Тем более что Борманд и я реализовывали одну идею. Только я добавил проверку корректности, на "чистой" же "арифметике".
                            Исключение один if, который проверяет валидность входных данных и кидает исключение, например (чего не было у Борманда). Без него тут никак.
                            inline
                            uint64_t fMask(uint64_t x){     
                                    uint64_t im,lm;//invalid mask, letter mask
                                    uint64_t x1  =  x-hm*3;
                                    uint64_t i   =  x1 ^ hm*2;
                                    im           =  i;
                                    im           |= (im << 1);
                                    lm           =  im ^ (im << 2);
                                    return (~im & lm) ;
                            }
                            inline uint64_t crapCheck(uint64_t x)
                            {
                               const uint64_t lm=0x0101010101010101ll;
                                uint64_t a,b,l,s,fm;
                                    fm      =       fMask(x);
                                    a       =       x &     hm*4;
                                    l       =       a>>4    ; //0100 in letter case
                                    b       =       a>>6    ; //0001 in letter case
                                    x       -=      b               ; //for 40,60   
                                    s       =       x |     hm*7;
                                    s       +=      l +     lm*6;
                                    s       |=      fm ^ hm*8;
                                    s       &=      hm*8;
                                    
                                    if (0!=s){
                                        printf("Borken. Error In Bytes=%X; x=%X \n",s % 127,x);         
                                    }
                                    uint64_t res=x-l-(b<<1);
                                    return res;
                            }
                            Ответить
                    • Проблема в том что я пока что не вижу радикального способа переписать это:
                      inline uint64_t compress(uint64_t a,uint64_t b) {
                          const uint64_t m2 = 0x000F000F000F000Fll;
                          const uint64_t m3 = 0x0F000F000F000F00ll;
                          a = (a & m2) << 12 | (a & m3);
                          b = (b & m2) << 12 | (b & m3);
                          a |= a >> 24;
                          b = b >> 8 | b << 16;
                          return (a & 0x0000FFFF00000000ll) | (a & 0xFFFF) << 48 | b >> 48 | (b & 0xFFFF0000);
                      }

                      За исключением очевидного
                      >(a & 0xFFFF) << 48
                      >a<<48
                      Ответить
                      • Я восхищен этим. Превосходное байтоебство. C неким опозданием, но я полностью оценил круть и оффициально подтверждаю что это предел.
                        Мои попытки написать reverse+compress с нуля заняли тоже ровно 20 инструкций и обе медленее.

                        Я чуть-чуть причесал код борманда, так что оба упакованных способа (с проверкой и без) делают самый быстрый из примеров на 1мс :)
                        http://liveworkspace.org/code/1lmQMa$56
                        crap_PI: 96 ms, control 3811068283262806208
                        bormand: 92 ms, control 3811068283262806208
                        dual un: 97 ms, control 3811068283262806208

                        PS Православные шаффлы SSE серъезно усилили бы разрыв.
                        Ответить
                • Вот еще один вариант, про который я упоминал выше (табличка которая преобразовывает 2 цифры в один байт):
                  http://liveworkspace.org/code/33rWZ9$18
                  Ответить
                  • вполне логично
                    таблица 256 получилась в 2 раза медленнее таблицы 256*256
                    Ответить
                    • Ну и анроллед версия, которая догнала байтоебство из топика: http://liveworkspace.org/code/33rWZ9$20
                      Ответить
            • http://pastebin.com/MteKQqcJ
              %)

              Кстати, первый раз в жизни пишу что-то на сиплюсплюс.
              Ответить
              • Вот она, просветительская миссия Говнокода.
                Многие экзотические языки пробовал именно тут.
                Ответить
        • >base64 туда-сюда гоняется по сети
          А HEX тоже много гоняется по сети. Уникод в xmlе (&#x20;) и в jsone
          Вот StringEscapeUtils в apache commons он практически все символы, без разбору, превращал при экранировании в такой hex.
          Так что практическое применение, безусловно есть.
          Ответить
      • Похоже на кривые Пеано и Гильберта.
        >бы к этой функцие прямое (вместо итеративного) вычисление? ;)
        Надо много думать. Но нет ничего невозможного.
        А какая практическая ценность такого?
        Ответить
        • На сколько я понимаю - практической ценности никакой. Функция известна только как учебное пособие / каверзный вопрос в контексте производных / лимитов и т.п. Своего рода как граф Петерсона в теории графов.
          Ответить
          • Охуеть. Зачем её тогда делать? Чтобы показать что так можно сделать всё?
            От HEXа - явно польза есть. А методы куда более общие: можно быстро искать в тексте, сравнивать текст по маске.
            И кривая Гильберта на практике используется.
            Ответить
            • Ну я даже не знаю... в Сауспарке был такой эпизод, когда отец Стена никак не мог остановиться делать саркастические замечания по поводу окружающей его действительности, а действительность продолжала воспринимать эти самые замечания всерьез...
              Ответить
              • Отец Стена...
                звучит...
                Всего лишь перепутал "э" с "е" и какой результат!
                Ответить
                • ХЗ. Я спорить не буду, но на поверку большинство английских слов, которые заимствованы в русский язык фонетичекси (по Куприну) пишутся через "е", а не "э" в закрытом слоге. Особенно в именах собственных. Например Стендаль, Соммерсет Моэм. Закрытый ударный слог - сложный случай, но тем не мение, Соммерсет пишется с "е".
                  В последнее время много заимствований делается по принципу "кто первый перевел - так и будет". Особенно в этом смысле показательны заимствования из Китайского, где русская фонетическая транскрипция, как правило, абсолютно не похожа ни на один из использующихся диалектов, плюс к тому еще и непхожа каждый раз по-разному. Обычный китаец никогда в жизни бы не догадался, кто такой Чан Кайши или Мао Дзедун.
                  Ответить
                  • > СТЭН — английский пистолет-пулемёт времён Второй мировой войны.
                    Хотя, конечно, викижопия не является достоверным источником информации.

                    > из Китайского
                    Оный Китай почти во всём мире называется "Сина" (в старорусском тоже), там сама история с азиатскими языками лютая.
                    Ответить
                    • Стэн - это не английское имя, а немецкое, происходит от Stein. Как его правильно произносить по-английски? - я хз. Тем более, какую транскрипцию использовать... Я не уверен на счет распространнености, но американцы обычно больше предрасположены к использованию æ в иностранных словах, хотя, чисто теоретически, обычно, если бы это было исконно английское слово, тут была бы ɛ. В мультфильме используют ɛ, если что.
                      Ответить
                      • Штайн!
                        Ответить
                        • https://translate.google.ru/?tab=wT#en/ru/stein
                          Ответить
                          • Штейн это чувак, который утверждал, что умеет в машину времени.

                            Не, я вру. Его подругому звали.
                            Ответить
    • Так а чо. Если работает, то и хай с ним.
      Ответить
    • О, хорошо. Отдельный тред.
      > a += ((a & m1) >> 6) * 9;
      > b += ((b & m1) >> 6) * 9;
      Не асспараллельно как-то. Или оно в одну коммаду компилируется?
      Ответить
      • Они 64 битные же, обе строчки за раз только mmx/sse смогут ;(
        Ответить
        • Так а какой смысл тогда брать по 2?
          >mmx
          Не сможет. Он 64.
          Зато AVX2 сможет и по 4 за раз.
          Ответить
          • > Так а какой смысл тогда брать по 2?
            Брал 2 блока чтобы заполнить 64 битное число. Если читать его как 2 32битных а потом сдвигать и клеить - получим немного лишних операций, а тут 3-4 такта выигрываю засчет этого "инлайна".
            Ответить
            • Блин. Совсем не пойму.
              У вас 2 64-битных.
              >int64_t a = p[0], b = p[1];
              Почему не обрабатывать одним махом, раз это для x64
              Ответить
              • 16 символов же
                одним махом - это 128 разрядное целое должно быть
                Ответить
                • Так а зачем брать 128? Если считаем в 64.
                  GCC оптимизирует при наличии SSE? Или это своеобразный анроллинг?
                  Ответить
                  • Инлайнинг двух парсеров 32 битного числа в одну функцию.
                    Ответить
                    • А-а-а. А я всё думаю что то такая хитрая оптимизация.
                      Ответить
    • > этой функции, конечно же есть и недостаток - на кривых данных ее поведение не определено.
      Это фиксится теми же способами. Вчера я чего-то тупил, никак не мог найти маски.
      А сегодня мне очевидно как искать.
      Вот, примерная версия с заделом на оптимизацию:
      int fm,im,lm;//final mask,invalid mask, letter mask
      i=x & F0F0F0F0;
      int d=0x10101010;
      		int i = i1 ^ d*2
      		im = i;
      		im	= ((i & d*8)>>1) | im;
      		im |= ((im & d*14)>>2); 
      		im |= ((im & d*5)<<1);
      		
      		lm	= ((i & d*2)>>1 | i);
      		lm ^= (lm & d*3) << 2;
      		
      		int fm=~ im & lm;
      Ответить
      • А вот проверка на валидность побыстрее. Думаю можно сократить до 10 инструкций.
        int check(int x){
        	const int hm=0x10101010;
        	int im,lm;//invalid mask, letter mask
        	int x1= x-hm*3;
        	int i 	= x1 ^ hm*2;
        	im 	= i;
        	im 	|= (im <<1);
        	lm 	= im ^ (im << 2);
        //im |= (im<<1);	//даёт возможность генерировать чистую маску с 0000
        	int fm	= (~im & lm) & (hm*8);
        	return fm ^= (hm*8);
        }

        lm и im могут быть полезны сами по себе.
        Тут:
        http://ideone.com/hCqsxb
        Ответить
        • Бажновато, однако: http://ideone.com/wHh0hq
          Ответить
          • Это ж для диапазонов. Я не говорю что окончательный вариант.
            Просто это самый сложный кусок, на мой взгляд. Как проверка на диапазоны [30-50),[60,70) - багов не имеет.

            Остальное - довольно тривиально. Будет отдельным патчем.

            Да и мой подход универсальный. если не хватает денег на процессор с SSE 4.2 c pcmpestri, а сильно хочется быстрого поиска по диапазонам, или конкретных значений.
            Все буквы, цифры. По сути это простейшие регэксы, но ускоренные на аппаратном уровне. Область применения шире hex-ов.
            Ответить
            • Можете привести пример на котором SSE4.2 с pcmpestri будет значительно превосходить по производительности вариант без этой приблуды.
              Использовал на дня эту фичу. Поиск подстроки получался где-то на 30% быстрее (чем strstr). Поиск строки из 4-х элементов уже 2-3 раза в зависимости от компилятора.
              А хочется перфоманса. В конце концов парсеры спирита на него переписать;)
              Ответить
          • Я вот всё думаю можно ли упростить последние три выражения в однострочник.
            Прям просятся. Просто lm может быть ценен сам по себе, потому я оставил промежуточные значения.
            Ответить
          • Я считаю что эксепшен более уместен чем нули вместо неправильных полей.
            Но нули тоже просто сделать, используя мою маску fm и выполнив еще 2 комманды.
            Итак продолжаем наш праздник.
            Когда мы знаем что числа в диапазоне 30-50, то тут уже всё просто.
            К тем цифрам что в диапазоне 30-40 надо прибавить 6.
            А к буквам в диапазоне 40-50 надо прибавить 10.
            То есть 3 -> 6, а 4(6) ->10
            Это s=((a>>2)+a)<<1.
            Маскируем верхний полубайт | 7 и потом прибавляем s к младшему ниблу .
            В итоге получаем корректность верхнем бите , как и в прошлом случае.
            Остается одно говно. 40/60h
            Ответить
            • Полный вариант с проверками, нахождениями индексов проблемных байт и парсингом. Всего 20 инструкций.
              http://ideone.com/tm6MZT
              const unsigned int hm=0x10101010;
              
              //range check. 8 instructions.
              inline
              unsigned int fMask(int x){
              	unsigned
              	int im,lm;//invalid mask, letter mask
              	int x1	= x-hm*3;
              	int i 	= x1 ^ hm*2;
              	im 		= i;
              	im 	   |= (im <<1);
              	lm 		= im ^ (im << 2);
              	return (~im & lm) ;
              }
              
              int main(){
              int test[10] =
              { 
              	0x66666666 
              	,0x36426630
              	,0x56374146
              	,0x36F76146
              	,0x36F7E146        
              	,0x36C7D166
              	,0xB6A79166
              	,0x66668771
              	,0x30676869
              	,0x3A413047
              };
              for (int i=0;i<10;++i)
              {
              	unsigned int x=test[i];
              	//after check +8 instructions.
              	unsigned int a,b,s,fm;
              	fm 	=	fMask(x);
              	a	= 	x &	hm*4;
              	b	=	a;
              	a	+=		hm*5;
              	s	=	x |	hm*7;
              	s	+=	a>>4;
              	s 	|=	fm ^ hm*8;
              	s	&= 	hm*8;
              	
              	if (0!=s){
              		printf("%d is borken. Error In Bytes=%X; x=%X \n",i,s % 127,x);
              		//printf("%d is borken. s=%X; fm=%X; x=%X \n",i,s,fm & 	hm*8,x);		
              		continue;
              	}
                      //parsing +4 instructions.
              	b>>=3;
              	int res=x+(b>>3)+b;
              	printf("%d is parsed. x=%X; res=%X \n",i,x,res & 0x0F0F0F0F);
              }
              
              return 0;
              
              }
              Ответить
              • last fix
                http://ideone.com/2rpXth
                Делайте ваши тесты, господа.
                Ответить
    • > const uint64_t *p = (const uint64_t*)s;
      А как же выравнивание? UB будет. Надо через memcpy.

      Нельзя просто так взять, и скастовать из char* в uint64_t*
      Ответить
      • > Нельзя просто так взять, и скастовать из char* в uint64_t*
        Можно же, стандарт разрешает. Указатель на char и другой указатель могут алиаситься, лишь бы выравнивания хватало...
        Ответить
      • > > const uint64_t *p = (const uint64_t*)s;
        > А как же выравнивание? UB будет. Надо через memcpy.
        const uint64_t *p = (const uint64_t*)(s-s%sizeof(uint64_t));
        fixed.
        Ответить
    • Да, годный был тред.
      Ответить
      • Выше есть base64 декодер, проверь.
        Ответить
        • Переведи на "SSE".
          Ответить
          • В принципе можно. Упаковка битов даже проще станет (можно тупо сделать shuffle и не ебаться с переворачиванием битов).
            Ответить
          • Ну и shuffle может пригодиться как табличка с 16 элементами.
            Ответить
            • В принципе, можно по 4 старшим битам определить сколько надо вычитать из каждого байта за 1 shuffle...
              Ответить
          • static void decode_chunk(const char* s, uint8_t* out)
            {
                __m128i a = _mm_loadu_si128((const __m128i*)s);
            
                __m128i u = _mm_and_si128(a, _mm_set1_epi8(0x74));
                u = _mm_add_epi8(u, _mm_set1_epi8(0x04));
                u = _mm_srli_epi32(u, 0x03);
                u = _mm_and_si128(u, _mm_set1_epi8(0x0F));
                u = _mm_shuffle_epi8(_mm_set_epi32(0xB9B9B9B9, 0xBFBFBFBF, 0x04041013, 0x00000000), u);
                a = _mm_add_epi8(a, u);
            
                __m128i m1 = _mm_set1_epi32(0xFF00FF00);
                __m128i m2 = _mm_set1_epi32(0xFFFF0000);
                a = _mm_shuffle_epi8(a, _mm_set_epi32(0x00010203, 0x04050607, 0x08090A0B, 0x0C0D0E0F));
                a = _mm_or_si128(_mm_srli_epi32(_mm_and_si128(m1, a), 2), _mm_andnot_si128(m1, a));
                a = _mm_or_si128(_mm_srli_epi32(_mm_and_si128(m2, a), 4), _mm_andnot_si128(m2, a));
                a = _mm_shuffle_epi8(a, _mm_set_epi32(0x80808080, 0x00010204, 0x05060809, 0x0A0C0D0E));
            
                _mm_storeu_si128((__m128i*)out, a);
            }
            Распаковывает 7 гигабайт в секунду, лол (не SSE'шная всего 1.3 гига успевала).

            З.Ы. Удачного разбора, ня.
            Ответить
    • показать все, что скрытоvanished
      Ответить

    Добавить комментарий