Кресты / Говнокод #27050 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
template <typename T, typename OUT_T = uint8_t> 
OUT_T subdecoder_nbt::extract_bits(T bits, uint8_t pos, uint8_t end)
{
    auto invert_bytes = [](T bytes) -> T
    {
        auto *p     = reinterpret_cast<uint8_t*>(&bytes), 
             *p_end = reinterpret_cast<uint8_t*>(&bytes) + sizeof(bytes) - 1; 
        for(; p < p_end; ++p, --p_end)
        {
            *p = *p ^ *p_end;
            *p_end = *p ^ *p_end;
            *p = *p ^ *p_end;
        }

        return bytes;
    };

    bits = invert_bytes(bits);

    bits <<= pos;
    bits >>= (sizeof(bits) * 8 - (end - pos) - 1);

    return (OUT_T)bits;
}

Как правильно доставать биты из промежутка из стандартных типов C++ на x86.
Изучал эту проблему в сумме почти сутки.

А всё потому, что x86 хранит байты в Little-Endian, из-за чего при сдвиге биты окажутся не там, где ожидаешь.

Запостил: YpaHeLI_ YpaHeLI_, (Updated )

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

  • Сам говнокод выглядит так же, только без invert_bytes
    Ответить
  • Little-endian влияет только на порядок байтов, если что.
    Ответить
    • Ну т.е. с битами и сдвигами всё ок. У тебя само число неправильно прочитано, арифметика на нём тоже работать не будет.

      З.Ы. invert_bytes аля htons/htonl/bswap_64 обычно делают сразу после чтения, до любой работы с числом, а не посреди неё.
      Ответить
      • Классический сишный способ:
        // читаем структуру из файла
        Header hdr;
        // ... тут вызов read ...
        
        // и фиксим endian во всех полях с числами длиннее байта
        hdr.field16 = htons(hdr.field16);
        hdr.field32 = htonl(hdr.field32);
        
        // теперь с ними можно спокойно работать
        // биты и арифметика ведут себя как положено
        Ответить
        • А так можно читать структуру? Структуры на всех платформах имеют одинаковый сдвиг? Недавно обсуждалось, что bool внутри может хранится как угодно.

          P.S. ты отредактировал комментарий, там был read
          Ответить
          • Обычно в таких структурах только кошерные типы и все поля аккуратно разложены.
            Ответить
            • Мы на работе сериализуем в protobuf. Это позволяет безболезненно добавлять и удалять поля. Нахуй ещё задумываться о такой хуйне типа внутреннего строения и индейцах.
              Ответить
              • Протобуф уже научился юзать чужеродные структуры не в его формате?
                Ответить
                • Хз. Ты хочешь написать структуру в "C", и чтобы он сгенерил описание в своём формате?
                  Ответить
                  • Я не хочу её писать, но многие структуры уже написаны за годы до нас. И десериализатор протобуфа на них, увы, не натянуть.
                    Ответить
                    • CastXML может выдать XML файл с описанием структур. Для
                      #include <inttypes.h>
                      #include <stddef.h>
                      
                      struct uint8pair
                      {
                        uint8_t a;
                        uint8_t b;
                      };
                      
                      struct uint16pair
                      {
                        uint16_t a;
                        uint16_t b;
                      };


                      будет какое-то такое описание:
                      ...
                        <Typedef id="_12" name="__uint8_t" type="_111" context="_1" location="f1:37" file="f1" line="37"/>
                        <Typedef id="_14" name="__uint16_t" type="_112" context="_1" location="f1:39" file="f1" line="39"/>
                      ...
                        <Typedef id="_66" name="uint8_t" type="_12" context="_1" location="f3:24" file="f3" line="24"/>
                        <Typedef id="_67" name="uint16_t" type="_14" context="_1" location="f3:25" file="f3" line="25"/>
                      ...
                        <FundamentalType id="_111" name="unsigned char" size="8" align="8"/>
                        <FundamentalType id="_112" name="short unsigned int" size="16" align="16"/>
                      ...
                        <Struct id="_104" name="uint8pair" context="_1" location="f8:4" file="f8" line="4" members="_132 _133" size="16" align="8"/>
                        <Struct id="_105" name="uint16pair" context="_1" location="f8:10" file="f8" line="10" members="_134 _135" size="32" align="16"/>
                      ...
                        <Field id="_132" name="a" type="_66" context="_104" access="public" location="f8:6" file="f8" line="6" offset="0"/>
                        <Field id="_133" name="b" type="_66" context="_104" access="public" location="f8:7" file="f8" line="7" offset="8"/>
                        <Field id="_134" name="a" type="_67" context="_105" access="public" location="f8:12" file="f8" line="12" offset="0"/>
                        <Field id="_135" name="b" type="_67" context="_105" access="public" location="f8:13" file="f8" line="13" offset="16"/>
                      ...

                      Можно потом из этого XML генерить протобуфную питушню какую-нибудь
                      Ответить
                      • > протобуфную питушню

                        Дык у протобуфа парсер в принципе не пригоден для кастомных форматов. Ибо там что-то в духе тегированных полей. Или что-то изменилось?

                        Ну что-то своё можно сгенерить. На крестах в общем-то просто имён полей хватает для генерации, остальное в компайлтайме доступно.
                        Ответить
          • > там был read

            read() я убрал потому что я обосрался с проверкой его результата (signed-unsigned mismatch).
            Ответить
      • Классический способ с побайтовой десериализацией:
        // ... убедились, что в буфере есть sizeof(T) байт ...
        
        // и теперь читаем их из буфера как big-endian
        T res = 0;
        for (size_t i = 0; i < sizeof(T); ++i)
            res = (res << 8) | (uint8_t)buf[i];
        
        // теперь с res можно спокойно работать
        // биты и арифметика ведут себя как положено
        Ответить
        • Ну тогда, имхо, надо всё равно разделить переворачивание числа и выдирание битов.
          Ответить
    • Да, но если есть стык, то например, если тебе нужен отрезок 7-12,
      то окажется, что не инвертировав байты ты достанешь не оттуда.
      там вообще в этот отрезок войдет еще один отрезок, который ему не должен принадлежать.

      15 14 13 [12] 11 10 9 8 | [7] 6 5 4 3 2 1 0 | LE
      ~~~~~~~~ -------------------------- ~~~~~~~~~~~
      [7] 6 5 4 3 2 1 0 | 15 14 13 [12] 11 10 9 8 | BE
      --- ~~~~~~~~~~~~~~~~~~~~ --------------------
      Ответить
  • Блин, нафиг ты пилишь xor-swap в строках 10-12, олимпиадник штоле? Есть же стандартный std::swap.
    Ответить
      • Я бы тоже:
        a ^= b ^= a ^= b;

        Сейас прилетит питух, и скажет, что это UB
        Ответить
        • > и скажет, что это UB

          Или не скажет, а потом у тебя это в продакшене навернётся.
          Ответить
    • Минуснулслучайно, куриной лапой тяжело мышью рулить.
      Ответить
    • Потому что это стильно, модно, молодежно!
      На самом деле я хз как устроен std::swap для стандартных типов.
      Используется ли там xor-обмен.
      Ответить
      • > используется ли там xor-обмен

        xor-обмен никто в здравом уме не юзает, разве что выебнуться. Впрочем, компиляторы его умеют оптимизировать в один xchg. Как и классическую перестановку через временную переменную, которая юзается в дефолтном std::swap.
        Ответить
        • Кстати XCHG между регистром и памятью это относительно дорогая операция т.к. шина блокируется.
          Ответить
          • я думал, она между регистром и буфером ядра, если ты явно там заборов не понастроил, нет?
            Ответить
            • https://www.agner.org/optimize/instruction_tables.pdf
              > Instructions with a LOCK prefix have a long latency that depends on cache organization and possibly RAM speed. If there are multiple processors or cores or direct memory access (DMA) devices, then all locked instructions will lock a cache line for exclusive access, which may involve RAM ac-cess. A LOCK prefix typically costs more than a hundred clock cycles, even on single-processor systems. This also applies to the XCHG instruction with a memory operand.
              Ответить
              • спасибо

                я не думал, что он вот прямо обязан писать в память. Не все ведь инструкции обязаны, слава богу
                Ответить
              • > hundred clock cycles

                Ну это уже неправда вроде. Если нет реальной драки за кешлайн, то атомики относительно дешёвые.
                Ответить
          • > шина блокируется

            Зачем? Зачем? Даже при обычном xchg, а не lock xchg у которого гарантии?

            З.Ы. Бля, и правда. If a memory operand is referenced, the processor’s locking protocol is automatically implemented for the duration of the exchange operation, regardless of the presence or absence of the LOCK prefix or of the value of the IOPL.
            Ответить
            • У инженеров интеля спроси. Наверное было много скверно написанных программ, где под xchg подразумевали lock xchg. И их сделали одним и тем же.
              Ответить
              • То есть раньше было одно ядро, и великой разницы между lock xchg и xchg не было, и тупые лалки понаписали без лока, а потом интел завез SMP, и побоялся сломать старые программы?
                Ответить
                  • так можно далеко пойти, и вообще запретить параллельное исполне.. хотя погодите-ка.. GIL
                    Ответить
                      • SMP нет смысла поддерживать в окамле: SMP никогда не выстрелит
                        Скорее уж у людей будут 64х битные компьюетеры с 16-ю гигами памяти, и серьезный софт начнут писать, например, на джаваскрипте, ахаха
                        Ответить
                          • Ему не нужно, тупорылые макаки (абстрактные, не говнокодные) и так спокойно жрут все ядра скриптами на одностраничном сайте с пятью картинками.
                            Ответить
                          • Сам JS нет, но движку ничто не мешает делать что-то во много потоков

                            Я могу написать на си функцию doAll которая делает форк на 16 ядров, потом джойн, и возвращает результат ожидающему потоку в JS
                            Ответить
                • Если они так боялись сломать старый софт, то почему не добавили автоматический lock и ко всяким add?

                  И какой-нибудь флажок smp-aware в eflags, который отключает все автоблокировки.
                  Ответить
                  • >почему
                    если уж вы с циферками не знаете, то я и подавно не знаю. Можно спросить на форуме у интела. Я там как-то чото спрашивал, там крутые челы сидят

                    https://community.intel.com/
                    Ответить
                • > интел завёз SMP

                  Лол, в доке по оригинальному 8086 уже есть глава про Multiprocessing Features! И там xchg ещё не брал lock автоматически.

                  The 8086 and 8088 are designed for the multiprocessing environment. They have built-in features that help solve the coordination problems that have discouraged multiprocessing system development in the past.

                  LOCK may be used in multiprocessing systems to coordinate access to a common resource.

                  It is possible for another processor to obtain the bus between these two cycles and to gain access to the partially-updated semaphore. This can be prevented by preceding the XCHG instruction with a LOCK prefix.
                  Ответить
                  • А вот в 286 уже так написано: When used with a memory operand, XCHG automatically activates the LOCK signal.

                    Видимо какие-то лалки уже успели обосраться за 4 года.
                    Ответить
                    • какие могли лалки обосраться с двумя ядрами до 286?
                      разве что там был хитрый DMA, который сам читал с шины данные и писал в память
                      Ответить
                      • А я кажется понял почему...

                        LOCK на двойке был привилегированной инструкцией! А мутексов в юзермоде то хотелось. Вот и прикрутили автолочку к XCHG.

                        80386 перестал проверять привилегии на LOCK. Но уже было поздно.

                        Такой вот очередной плевок в вечность.
                        Ответить
                        • А почему? чтобы обычный юзеровый процесс не мог поставить системму раком и проебать прерывания?
                          Ответить
                          • Х.з., возможно тогда LOCK ещё на любых инструкциях работал, включая всякую строковую фигню? Я не вижу в доке от двойки ограничения на конкретный набор инструкций, которое в свежих доках есть.
                            Ответить
                          • Короче да, в доке по 80386 есть глава Restricted Semantics of LOCK. И замечание, что при неправильном использовании LOCK теперь может вылететь invalid opcode.
                            Ответить
                            • ранаьше не мог?
                              раньше я мог писать lock к каждой инструкции, и течь?
                              Ответить
                              • Походу да.

                                The 80386 defines new exceptions that can occur even in systems designed for the 80286.

                                Exception #6 - invalid opcode

                                This exception can result from improper use of the LOCK instruction.
                                Ответить
                              • The 80286 processor implements the bus lock function differently than the 80386. Programs that use forms of memory locking specific to the 80286 may not execute properly when transported to a specific application of the 80386.

                                Т.е. совместимость - это святое, но иногда можно и забить )))
                                Ответить
                                • ну надо же, интел забил на обратную совместимость
                                  Ответить
                                  • К слову о совместимости:

                                    Despite the fact that Pentium 4, Intel Xeon, and P6 family processors support processor ordering, Intel does not guarantee that future processors will support this model.

                                    Какой дисклеймер )))

                                    Т.е. интел внезапно может дропнуть гарантии про реордеринг. Но что-то мне намекает, что юзеры после этого дропнут интел.
                                    Ответить
                                    • не понел

                                      они гарантировали реордеринг или его отсутсвие при фенсах?
                                      Ответить
                                      • Они гарантируют (пока?) что даже без фенсов, лочек и т.п. у тебя чтения и записи почти не реордерятся.

                                        Насколько я помню, на x86 только read вперёд write может проскочить (если они в разные места, само собой). Всё остальное идёт строго как написано в коде. Ну смёржиться разве что могут если WB или WC режим.
                                        Ответить
                                        • ну то есть они не настолько релаксд как некоторые другие архитектуры, ок
                                          Ответить
                                          • Они настолько не релаксед, что целые поколения программистов безнадёжно испорчены и избалованы.
                                            Ответить
                • не знаю, я про этот хак тока что узнал от циферок

                  звучит как остыль конечно
                  Ответить
                  • В инструкции к 80386 указана только инструкция XCHG.

                    11.2.2 Automatic Locking

                    In several instances, the processor itself initiates activity on the data
                    bus. To help ensure that such activities function correctly in
                    multiprocessor configurations, the processor automatically asserts the LOCK#
                    signal. These instances include:
                    • Acknowledging interrupts.
                    • Setting busy bit of TSS descriptor.
                    • Loading of descriptors.
                    • Updating page-table A and D bits.
                    • Executing XCHG instruction.
                    Ответить
                    • ну вот брмнд пишет, что уже в 286
                      в Executing XCHG instruction был LOCK#

                      блядь, как всё сложно
                      именно по этому я за 5150
                      Ответить
                      • Я уже забыл про такой багор:
                        14.7 Differences From 8086
                        ...
                        4. Value written by PUSH SP.
                        The 80386 pushes a different value on the stack for PUSH SP than the
                        8086/8088. The 80386 pushes the value of SP before SP is incremented
                        as part of the push operation; the 8086/8088 pushes the value of SP
                        after it is incremented. If the value pushed is important, replace
                        PUSH SP instructions with the following three instructions:
                              PUSH  BP
                              MOV   BP, SP
                              XCHG  BP, [BP]

                        This code functions as the 8086/8088 PUSH SP instruction on the 80386.

                        Видимо, поэтому инструкцию PUSH SP почти нигде не встретишь: SP сначала кладут в какой-нибудь регистр, потом пушат.
                        Ответить
                        • Какой UB ))
                          Точнее, какой имплементейш дефанд

                          Ну и пойомка эти ваши процессоры. Понятно теперь, почему пуш не трогают. Кому было охота иметь разное поведние
                          Ответить
                          • Представляешь, программы для 8088, которые использовали PUSH SP, на 80386 работать не будут. Их придётся патчить.

                            Хак для определения процессора (когда-то не было CPUID):
                            PUSH SP
                            POP AX
                            SUB AX, SP
                            JE @80386
                            ; программа запущена на 8086/8088
                            JMP END
                            @80386:
                            ; программа запущена на 80386
                            END:
                            Ответить
                            • напоминает как раньше JSом узнавали браузер по фичам))

                              Правда кстати, что CPUID ставит барьер почему-то?
                              Ответить
                              • Правда, ставит.

                                CPUID can be executed at any privilege level to serialize instruction execution. Serializing instruction execution guarantees that any modifications to flags, registers, and memory for previous instructions are completed before the next instruction is fetched and executed.
                                Ответить
                                  • > а зачем?

                                    Х.з., на самом деле это единственная инструкция, которая сериализует исполнение в юзермоде.

                                    Формально ещё можно iret дёрнуть, но ты же не будешь это делать посреди кода.
                                    Ответить
                                    • Я может быть скажу глупость, но нельзя в юзермоде явно заборы расставить?
                                      Ответить
                                      • > заборы

                                        cpuid - самый сильный из заборов, доступных юзермоду. Остальные заборы что-то да разрешают переставлять.
                                        Ответить
                                        • то есть получить такой же эффект вызвав разного вида *fence нельзя?

                                          надо про них почитать, я опять забыл чем они все отличаются
                                          Ответить
                                          • Если инструкция не лезет в память, то она может проскочить под забором.
                                            Ответить
                                            • если она не лезет, то кто вообще узнает о том, что ее реордернули? или можно писнуть в какой-то регистр, и идущий за тобой этого не заметит? Это было бы странно

                                              Ведь нельзя же читать чужие регистры из соседнегоядра?
                                              Ответить
                                              • Никто не узнает, поэтому обычно настолько жёсткий барьер нинужен.

                                                По-моему это только для замера пирфоманса может пригодиться.
                                                Ответить
                                                • Могло быть так, что какой-то софт типа аиды начинал тест с CPUID (чтобы знать с чем имеет дело), потом Intel оптимизнул что-то, и сломал тест, пересрался, и сериализнул в том месте?

                                                  Нормальные проги CPUID не юзают, и по пиформансу не просядут
                                                  Ответить
                                                  • Х.з., нигде не гуглится зачем, зачем cpuid сделали сериализующей инструкцией.
                                                    Ответить
                                                    • ну теперь уже питухи на это завязались, и обратно не откатишь

                                                      Программирование это костыли
                                                      Ответить
                                                      • > завязались

                                                        Я сейчас открыл доку по первому пню, где она изначально появилась. И она там уже сериализует исполнение.

                                                        The CPUID instruction can be executed at any privilege level to serialize instruction execution.
                                                        Ответить
                                                        • я не понимаю, зачем они это публично задокумнтировали и коммитнулись
                                                          ради кого?
                                                          Ответить
                                                        • Вроде на каких-то 80486 она появилась, но поскольку в более старых процессорах её не было, её не использовали, чтобы не ловить исключение 6, а вместо неё применяли другие методы.
                                                          Ответить
                                                          • Очень хороший метод применили в игре Gobliins и в игре Lode Runner.

                                                            Пользователя спрашивали какой у вас проц: 286, 386 или 486.

                                                            В зависимости от этого считали сколько времени занимает инструкция, чтобы делать delay
                                                            Ответить
                                                            • Это ху... хуже всего, в общем.

                                                              486 мог быть от 25 МГц до 80(2×40) МГц или 100(3×33) МГц.
                                                              386 мог быть от 16 МГц до 40 МГц.

                                                              Т. е. можно было нарваться и на 40-мегагерцовую «трёшку», и на 25-мегагерцовую «четвёрку».
                                                              Ответить
                                                              • видимо это работало на доступных разработчикам компах
                                                                на всех трёх
                                                                в 1987-м году
                                                                Ответить
                        • Да она просто нинужна... Зачем тебе может понадобиться сохранять sp на стек?
                          Ответить
                          • Чтобы в вызываемую функцию передать контекст текущей функции.
                            Ответить
                  • Кстати, а про костыль с mov ss знаешь же? Что он запрещает прерывания на следующую инструкцию.
                    Ответить
                    • ничего я не знаю

                      mov ss загружает сегмент стека? зачем запрещает? для какой-то дыры в безопансоти?
                      Ответить
                      • Чтобы ты мог написать

                        mov ss, ...
                        mov sp, ...

                        И наебнуться от прерывания между ними.
                        Ответить
                        • иными словами, чтобы запись сегмента и поинтера была более ли менее "атомарной"?
                          Ответить
                            • Какой бегер)

                              напихали локи в какие-то места что что-то работало

                              Почему нельзя было сказать так
                              * все инструкции никогда явно не берут лок
                              * бери лок сам
                              * хочет пирформанса -- вот тебе спец атомарная инструкция, которую проц оптимизирует

                              Напоминает код в одном проекте, где чуваки в случайные места вставили синхронизацию к комментом "без этого чото падает иногда". без царя вголове
                              Ответить
                              • воще я уже не понимаю

                                процы оптимизируют под хуевый код
                                а потом код оптимизируют под хуевые процы
                                и так по кругу
                                Ответить
                                • Ну да. А ещё языки оптимизируют под хуёвый код и хуёвые процы.
                                  Ответить
                                  • А ещё бывает такое:

                                    /*****************************************************************************\
                                        FUNCTION: CFtpDrop::CopyStorage
                                    
                                        DESCRIPTION:
                                            Copy a file contents provided as an IStorage.  Gack.
                                        We have to do this only because Exchange is a moron.
                                    
                                        Since there is no way to tell OLE to create a .doc file
                                        into an existing stream, we need to create the .doc file
                                        on disk, and then copy the file into the stream, then delete
                                        the .doc file.
                                    
                                        Note that CDropOperation::DoOperation() (_CopyOneHdrop) will do the ConfirmCopy
                                        and the FtpDropNotifyCreate(), too!  However, we want to fake
                                        it out and fool it into thinking we are doing a DROPEFFECT_COPY,
                                        so that it doesn't delete the "source" file.  *We* will delete
                                        the source file, because we created it.  (No need to tell the
                                        shell about disk size changes that don't affect it.)
                                    \*****************************************************************************/
                                    Ответить
                                    • Это они по MAPI over OLE пытались создать .doc файл в древнем Exchange в общей папке?
                                      Ответить
                                      • FILE: ftpdrop.cpp - IDropTarget interface


                                        Это расширение «Проводника», чтобы файл можно было мышкой кинуть на окошко, в котором отображается FTP. Почему они упомянули «Exchange», я не понял.
                                        Ответить
                                        • Может быть речь о DDE, на котором работал OLE?
                                          DDE это dyn data Exchange, лол)
                                          Ответить
                                          • В любом случае в исходниках «Винды» регулярно один отдел «Микрософта» обкладывает хуями другой за то, что приходится подставлять костыли.

                                            Где-то там были и патчи ОС под кривые прикладные программы.
                                            Ответить
                                            • Я тоже соседние отделы обкладываю, но у нас нельзя шеймить в комментах, потому приходится писать: "in spite of the documentation, this API doesn't support our case"
                                              Ответить
                                                • нельзя. У нас в канальчике иногда пишут "друзья, проверяйте пожалйста код перед коммитом".

                                                  Это значит, какой-то пидарас сломал компиляцию, и ушел домой

                                                  У нас есть safe push плагин, чтобы сначала код гонялся на TC, а потом попадал в мастер, но некоторые забивают
                                                  Ответить
                                                  • > какой-то пидарас сломал компиляцию

                                                    Да иногда просто не везёт. На той версии мастера, которая была перед мержом твоих изменений и запуском тестов всё было норм. Но за это время кто-то уже пролез в мастер. И всё сломалось.

                                                    Полную сериализацию коммитов никто в здравом уме делать не будет. Поэтому иногда shit happens.
                                                    Ответить
                                                      • Это же не масштабируется...

                                                        Придётся тесты очень сильно поджимать по времени и вбрасывать кучу железа на их распараллеливание.

                                                        По-моему это не особо пригодно для большой команды.

                                                        И 100% багов это всё равно не поймает. Ну не сможешь ты всё-всё-всё протестировать в такой сериализованной модели.
                                                        Ответить
                                                        • можно:

                                                          * компилировать инкрементально на агентах
                                                          * гонять только самые основные тесты

                                                          но железа нужно много, это правда.

                                                          Если у тебя в кодовой базе более ста питухов тусит за раз, то может пора разбиваться на модули, и собирать их отдельно?

                                                          Правда, придется думать про апи и аби: нельзя будет больше одним ловким рефакторингом переименовать метод

                                                          >И 100% багов это всё равно не поймает.

                                                          никакие тесты не ловят 100 процентов, иначе багов бы не было

                                                          ну хотяб прошла компиляция и смок тесты
                                                          Ответить
                                                          • > никакие тесты не ловят 100 процентов

                                                            Ну вопрос в том, насколько полная сериализация коммитов ловит больше багов, чем более слабая но оптимистичная. И насколько она дороже обходится по железу и усилиям программистов.

                                                            Если была пара поломок мастера в месяц, то может и хуй с ними?

                                                            З.Ы. Я не против прекоммит тестов, я против их полной сериализации.
                                                            Ответить
                                                            • сериализация не серилизует работу: пока оно там крутится, ты занят своими делами.

                                                              поломка мастера может быть очень болезненной: я как-то собирал openjdk, и попал на несобираемый мастер, и пытался понять где я обосрался, а потом приехал следующий коммит и все починилось

                                                              у нас правда ботик срет в чатик когда компилция падает на CI, так что обычно все знают
                                                              Ответить
      • > компиляторы его умеют оптимизировать

        З.Ы. Беру свои слова обратно. gcc -O2 не осилило xor-swap оптимизнуть. А вот с std::swap весь твой extract_bits<uint32_t, uint32_t>(n, 0, 31) свернулся в одну ассемблерную инструкцию bswap.
        Ответить
        • чем плох ксор свап кроме того, что он не нужен при наличии готовой инструкции в большинстве процессоров?
          Ответить
          • Не работает для типов, которые нельзя поксорить. По-моему этого уже достаточно.

            Ну и с наивным конпелятором, который не умеет в эту идиому, превращается в сраное говнище, которое не даёт процу распараллелить выполнение (в обычном swap'е по сути просто регистры заренеймятся).
            Ответить
            • >Не работает для типов, которые нельзя поксорить.
              логично) Я говорил про целочисленные типы.

              > обычном swap'е по сути просто регистры заренеймятся
              логично, там же под капотом 100500 внутренних регистров, которыv микрокот просто дает имена типа EAX
              Ответить
            • > Не работает для типов, которые нельзя поксорить.

              Скастовать в тип подходящего размера который ксорить можно, и потом поксорить (точнее, сделать указатель на такой-то тип с поддержкой xor, и присвоить в такие указатели адреса на переменные с неподходящим для перексориванием типы, и потом уже поксорить). Обменять float-ы так вполне можно.
              Ответить
              • ох-ох, а это не убе так кастовать?
                Ответить
              • > Скастовать в тип подходящего размера

                Сможешь это написать без ub'ов и короче наивного свапа?
                Ответить
                • Да, если вырубить стрикт алиазинг или использовать для указателей GNU-расширение __attribute ((may_alias))
                  Ответить
                  • > alias any other type of objects

                    Прощайте, оптимизации, мне будет вас не хватать. Хотя с char * в общем-то так же.
                    Ответить
                    • Если переменная с этим may_alias будет встречаться только в какой-то особой специальной функции обмена, разве это всюду сломает оптимизации?
                      Впрочем, xor swap вообще говоря говно, https://godbolt.org/z/9rT6ax оптимизируется он плохо. Компилятор не может в принципе породить точно такой же код 1 в 1 как при обмене переменных через третью, т.к. если мы меняем переменную саму с собой, xor-swap ее занулит
                      Ответить
                      • > если мы меняем переменную саму с собой, xor-swap ее занулит
                        Ну вот это и есть самое большое говнище в xor-swap. Всё прекрасно работает, а потом кто-нибудь передаёт туда уко-ко-козатели на одинаковые пельменные — и пиздец.
                        Ответить
                      • А на RISC процах xor-swap вообще не имеет никакого смысла. Инструкций для ксора с памятью то нету. Да и регистры экономить не надо.
                        Ответить
              • > сделать указатель на такой-то тип с поддержкой xor

                Ну можно, только strict aliasing не забудь отключить.
                Ответить
                • Некто изобрёл волшебный компьютер, где плавучка живет в одной памяти, а целочисленка в другой. Для каждой есть свои инструкции.

                  Я прпвильно понимаю, что все ваши may_alias и откелючение strict aliasing по пизде пойдут?
                  Ответить
                  • >Некто изобрёл волшебный компьютер, где плавучка живет в одной памяти, а целочисленка в другой.

                    Это ты про Эльбрус?
                    Ответить
                  • Сэмулирует через побайтовое копирование. Оно по стандарту обязано работать.
                    Ответить
    • Еще есть нестандартные функции типа:
      uint16_t __builtin_bswap16 (uint16_t x)
      uint32_t __builtin_bswap32 (uint32_t x)
      uint64_t __builtin_bswap64 (uint64_t x)
      uint128_t __builtin_bswap128 (uint128_t x)
      из GCC, но Clang их вроде тоже умеет.

      У MSVC есть под это своя елда:
      https://docs.microsoft.com/ru-ru/cpp/c-runtime-library/reference/byteswap-uint64-byteswap-ulong-byteswap-ushort?view=vs-2019


      Еще есть интелевые интринсики:
      https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_bswap

      И более-менее стандартный htonl() ntohl() (В стандарте Си нет, но в POSIX есть).

      В крестоговно почему-то не завезли никакой специальной хуйни для разворота байтиков, но зато там можно функцию Бесселя считать.
      Ответить
      • А в стандартах нету скорее всего из-за того, что представление числа стандартами не описывается. Хотя было бы неплохо иметь какие-нибудь шаблонные std::to_network_endian() и std::from_network_endian().
        Ответить
        • >А в стандартах нету скорее всего из-за того, что представление числа стандартами не описывается.

          Ну это не совсем так, в последнем стандарте C++ описывается, что представление signed чисел может быть только в "two's complement" (дополнительный код). http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0907r4.html

          И если это не описываеся, почему б это не описать тогда?
          Ответить
          • Ну про endian там вроде ничего нет.

            С другой стороны, функции которые ты привёл - это такая же чистая математика как и функции бесселя. Можно и добавить, даже если на какой-нибудь платформе в духе PDP они не имеют никакого смысла.

            З.Ы. А потом захочется вращения чисел и поиска старшего бита.
            Ответить
            • > С другой стороны, функции которые ты привёл, это такая же чистая математика как и функции бесселя.

              Нет, пожалуй это ближе к области байтоебства, чем к математике. Зачем математикам разворачивать байтики?
              Ответить
              • Ну я в том смысле, что работа всех этих bswap'ов никак не зависит от платформы. Это просто такая функция над числом. Как и сдвиг или битовое И.
                Ответить
                • Ну вообще как-нибудь может и зависеть, например если байты не 8-битные.
                  Ответить
                  • Ну можно описать как перестановку элементов длиной CHAR_BIT, раз уж на то пошло...
                    Ответить
            • Кстати я так подозреваю, что two's complement для signed чисел сделали чтоб в constexpr поведение было более однозначным (не зависело от платформы). Оно-то всё еще зависит в какой-то мере, из-за implementation defined размеров всяких типов и хуйни с плавучими питухами (хотя может я тут ошибаюсь, и плавучепитуховые вычисления в коконстэкспрах всегда дают известно какой результат?).
              Ответить
              • Вполне возможно. А может быть чтобы убрать UB при касте из uint32_t в int32_t для больших чисел. Всё-таки очень много скверно написанных программ на это полагается.
                Ответить
    • Ну вообще можно и не ссылку передавать, а действовать через лямбда-захват, еще оптимальней будет.
      Ответить
      • У меня в Си никаких лямбда-захватов нет, и оптимальность от этого не страдает. Если функция заинлайнилась, никаких проблем нет.
        Ответить
        • Да я не знаю, чем там лямбда-захват оптимальнее будет... Код скорее всего одинаковый получится, как и с сишной функцией в общем-то.
          Ответить
    • Зачем? Зачем? Это же для целых чисел, их и без ссылок передать не зашквар.
      Ответить

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

Переведи на "PHP", guest!

    А не использовать ли нам bbcode?


    8