1. C++ / Говнокод #27486

    +1

    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
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    // https://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/global/qglobal.h?h=v5.13.1#n1017
    
    #if __cplusplus >= 201703L
    // Use C++17 if statement with initializer. User's code ends up in a else so
    // scoping of different ifs is not broken
    #define Q_FOREACH(variable, container)                                   \
    for (auto _container_ = QtPrivate::qMakeForeachContainer(container);     \
         _container_.i != _container_.e;  ++_container_.i)                   \
        if (variable = *_container_.i; false) {} else
    #else
    // Explanation of the control word:
    //  - it's initialized to 1
    //  - that means both the inner and outer loops start
    //  - if there were no breaks, at the end of the inner loop, it's set to 0, which
    //    causes it to exit (the inner loop is run exactly once)
    //  - at the end of the outer loop, it's inverted, so it becomes 1 again, allowing
    //    the outer loop to continue executing
    //  - if there was a break inside the inner loop, it will exit with control still
    //    set to 1; in that case, the outer loop will invert it to 0 and will exit too
    #define Q_FOREACH(variable, container)                                \
    for (auto _container_ = QtPrivate::qMakeForeachContainer(container); \
         _container_.control && _container_.i != _container_.e;         \
         ++_container_.i, _container_.control ^= 1)                     \
        for (variable = *_container_.i; _container_.control; _container_.control = 0)
    #endif

    А можно ли свой foreach сделать через какую-нибудь шаблонопарашу? Или тут, как обычно, нужна гомоиконность?

    Запостил: j123123, 28 Июня 2021

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

    • Вот вы тут офанареть как извращаетесь. Аж джва раза кончил. Выкладывай на порнхаб - там разберуться
      Ответить
    • Q_REQUIRED_RESULT Q_DECL_CONSTEXPR static inline Q_DECL_UNUSED bool qFuzzyCompare(double p1, double p2)
      {
          return (qAbs(p1 - p2) * 1000000000000. <= qMin(qAbs(p1), qAbs(p2)));
      }
      
      Q_REQUIRED_RESULT Q_DECL_CONSTEXPR static inline Q_DECL_UNUSED bool qFuzzyCompare(float p1, float p2)
      {
          return (qAbs(p1 - p2) * 100000.f <= qMin(qAbs(p1), qAbs(p2)));
      }
      
      Q_REQUIRED_RESULT Q_DECL_CONSTEXPR static inline Q_DECL_UNUSED bool qFuzzyIsNull(double d)
      {
          return qAbs(d) <= 0.000000000001;
      }
      
      Q_REQUIRED_RESULT Q_DECL_CONSTEXPR static inline Q_DECL_UNUSED  bool qFuzzyIsNull(float f)
      {
          return qAbs(f) <= 0.00001f;
      }


      Нахуя это? Откуда они взяли эти замечательные константы 0.00001f, 0.000000000001, 100000.f, 1000000000000. ? Может надо std::numeric_limits<T>::epsilon использовать?
      Ответить
      • /*
           This function tests a double for a null value. It doesn't
           check whether the actual value is 0 or close to 0, but whether
           it is binary 0, disregarding sign.
        */
        Q_REQUIRED_RESULT static inline Q_DECL_UNUSED bool qIsNull(double d)
        {
            union U {
                double d;
                quint64 u;
            };
            U val;
            val.d = d;
            return (val.u & Q_UINT64_C(0x7fffffffffffffff)) == 0;
        }
        
        /*
           This function tests a float for a null value. It doesn't
           check whether the actual value is 0 or close to 0, but whether
           it is binary 0, disregarding sign.
        */
        Q_REQUIRED_RESULT static inline Q_DECL_UNUSED bool qIsNull(float f)
        {
            union U {
                float f;
                quint32 u;
            };
            U val;
            val.f = f;
            return (val.u & 0x7fffffff) == 0;
        }

        Так вроде бы type punning в крестах это UB.
        https://stackoverflow.com/questions/11373203/
        > The confusion is that C explicitly permits type-punning through a union, whereas C++ (c++11) has no such permission.

        Какой багор )))

        И нахуя они понаделали quint32 quint64 но например не сделали qfloat qdouble? Чем их не устроило uint32_t uint64_t?
        Ответить
        • Не было тогда uint32_t. А потом переделывать было влом.
          Ответить
        • З.Ы. Ну кстати здесь один фиг копирование, можно было и мемсру.
          Ответить
          • Кстати, если делать по стандарту, надо всегда мемсру вместо Туре-риппіп9?
            Ответить
            • Да, в крестах это к сожалению так.

              Хотя мне и в сишке статик ассёрт + мемсру больше нравится. Короче выглядит, не надо юнион на ровном месте выдумывать. Да и по пирфомансу то на то и выйдет.
              Ответить
              • > Да и по пирфомансу то на то и выйдет.

                Пруф:
                float cast(uint32_t x) {
                    float tmp;
                    static_assert(sizeof(tmp) == sizeof(x), "size mismatch");
                    memcpy(&tmp, &x, sizeof(tmp));
                    return tmp;
                }
                
                // movd    xmm0, edi
                Даже через память тащить не стало.
                Ответить
            • А нельзя отказаться от стрикт алайзинг?
              Ответить
              • UB-шность хуйни с union и стрикт алиазинг - это разное.

                От стрикт-алиазинга в GCC отказываться можно через -fno-strict-aliasing или __attribute((__may_alias__))

                А хуйня с UB с юнионами в GCC для крестопараши и старой сишки разрешена и так
                https://stackoverflow.com/a/25672839

                > GNU extensions to standard C++ (and to C90) do explicitly allow type-punning with unions. Other compilers that don't support GNU extensions may also support union type-punning, but it's not part of the base language standard.

                https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#Type-punning

                > Pay special attention to code like this:

                union a_union {
                  int i;
                  double d;
                };
                
                int f() {
                  union a_union t;
                  t.d = 3.0;
                  return t.i;
                }


                > The practice of reading from a different union member than the one most recently written to (called “type-punning”) is common. Even with -fstrict-aliasing, type-punning is allowed, provided the memory is accessed through the union type. So, the code above works as expected.
                Ответить
        • ты еще спраси зачем QString
          Ответить
        • >> The confusion is that C explicitly permits type-punning through a union, whereas C++ (c++11) has no such permission.


          пушо десктрукторы не понятно когда вызывацьт?
          Ответить
          • А разве у union есть деструкторы? Если там в юнионе две какие-то хуйни с деструкторами, то там вообще по-идее должно быть неясно, деструктор к той или к той хуйне вызывать при выходе из скоупа.
            Ответить
            • У «ипіоп» вообще ничего нет. Именно поэтому я за «ипіоп».
              Ответить
            • > А разве у union есть деструкторы?

              Если напишешь -- будет. Может быть там у элементов юниона есть какой-то общий хедер и ты хочешь по нему по-ня-ть тип и правильно всё почистить.
              Ответить
              • Тут тебя ждет багор: надо этот общий хедер прочитать у одного из элементов, и если не из того прочитаешь, будет UB.

                Вот если сделать структуру с хедером, и в ней уже юнион - это другое дело
                Ответить
                • Если у элементов standard layout и они все начинаются одинаково, то можно юзать этот общий хедер без UB через любой из них.
                  Ответить
                  • В каком месте в стандарте это написано?
                    Ответить
                    • 9.2 Class members

                      18. If a standard-layout union contains two or more standard-layout structs that share a common initial sequence,and if the standard-layout union object currently contains one of these standard-layout structs, it is permitted to inspect the common initial part of any of them. Two standard-layout structs share a common initial sequence if corresponding members have layout-compatible types and either neither member is a bit-field or both are bit-fields with the same width for a sequence of one or more initial members.
                      Ответить
                      • стандарт лейаут это всмысле что я ручками не покрутил там паддинги всякие?

                        грубо говоря, если два петуха начинаются на int, то этот int можно читать через любого питуха?
                        Ответить
                        • 9.2 Class members

                          7. A standard-layout class is a class that:

                          — has no non-static data members of type non-standard-layout class (or array of such types) or reference,
                          — has no virtual functions (10.3) and no virtual base classes (10.1),
                          — has the same access control (Clause 11) for all non-static data members,
                          — has no non-standard-layout base classes,
                          — either has no non-static data members in the most derived class and at most one base class with non-static data members, or has no base classes with non-static data members, and
                          — has no base classes of the same type as the first non-static data member.


                          Совместимый по лейауту с сишной структурой, если интуитивно.
                          Ответить
                          • Фишчека тут
                            > — has no virtual functions (10.3) and no virtual base classes (10.1),
                            остальное из нее выводится

                            А цимес небось в том, что в начале виртуального класса может таится какая-то хуйня типа указателя на vtb или на предка, да?

                            ну тоесть
                            struct Fooo {
                            int i;
                            }

                            реально начинается с инта (плюс минус специфичный для платформы алайн, общий для всех)

                            а если он виртуально наследует Petuh, то там уже в начале хуууй знает что
                            Ответить
                            • Ну да, потому что вся эта виртуальная требуха implementation defined.

                              З.Ы. Про последний пункт я не помню, если честно, почему так. Вроде чтобы не пересеклись адреса при empty base class optimization.
                              Ответить
                          • Пиздец какой-то. Почему они не сделали как в сишке, и наворотили каких-то ебанутых правил что если какая-то там хуйня вначале совпадает, то вот эту хуйню можно и там и там спокойно читать?
                            Ответить
                            • Дык standard layout + trivially copyable -- это и есть "как в сишке". Раньше это POD'ом называлось, потом разбили на отдельные правила чтобы удобнее было если что-то из них не нужно.
                              Ответить
                              • Нет, в сишке сейчас вполне легально можно прочитать флоат как инт из юниона.

                                > If the member used to read the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called ‘‘type punning’’). This might be a trap representation.
                                Ответить
                                • Ну это видимо оптимизацию убивает, конпелятор постоянно думает "а вдруг прочитают через жопу?!" и боится кешировать и т.п.

                                  З.Ы. Что-то мне намекает, что в няшной они бы тоже рады убрать. Но уже все юзают.
                                  Ответить
                                  • Покажи реальный пример, где это убивает оптимизацию
                                    Ответить
                                    • union U {
                                          uint32_t u;
                                          float f;
                                      };
                                      
                                      float test(U* u, float* f) {
                                          // *f и u->u могут алиаситься из-за наличия u->f
                                          // поэтому конпелятор сгенерит говно
                                          // и не сможет оптимизировать обращения к *f
                                          *f = 5;
                                          u->u = 42;
                                          *f = *f + 1;
                                          u->u = 43;
                                          return *f;
                                      }
                                      Можешь поменять в юнионе float на что-то другое и увидеть, что код стал лучше. Хотя реально это поле здесь вообще не юзается.
                                      Ответить
                                      • Кажется, что тут проблема не столько в том, что к флоату и инту обращаются одинаково, а в том, что поле становится как-бы волатильным: нельзя срзу вернуть шесть, потому что существует еще один способ насрать в ту же самую память (в теории это можно посчитать в компайл тайме, но наверное очень заёбно)
                                        Ответить
                                      • Для этого есть __restrict.

                                        Кроме того, если у тебя что-то вроде

                                        float test(char* u, float* f) {
                                            // *f и *u могут алиаситься
                                            // потому что char* хуйпойми с чем может алиаситься
                                            // поэтому конпелятор сгенерит говно
                                            // и не сможет оптимизировать обращения к *f
                                            *f = 5;
                                            *u = 42;
                                            return *f;
                                        }


                                        Так что тут и кресты обосрутся.

                                        А еще они обосрутся если у тебя в функцию просто передаются два указателя на флоат, и ты точно знаешь, что они на разную хуйню указывают. Так что я за __restrict
                                        Ответить
                                        • > Так что я за __restrict

                                          Так то да... В кресты его тоже пытаются протолкнуть, но пока запутались в сёмантике и отложили.
                                          Ответить
                                      • Кстати, твой пример и в кланге и в gcc в крестах нихрена не оптимизируется без restrict. https://godbolt.org/z/zY71jM5Mr

                                        Знание компилятора о том, что там вот этот юнион пишется через uint32_t ему не помогают
                                        Ответить
                                        • Кланг и гцц просто разрешают пуннинг через юнион в крестах. А мсвц вообще не умеет стрикт алиасинг.

                                          Т.е. в общем-то все популярные крестоконпеляторы по-сишному это трактуют.
                                          Ответить
                                          • А есть реальный пример компилятора, который бы запрещал это, и чтобы это в крестах оптимизировалось из-за запрета?
                                            Ответить
                                            • Судя по тому, что в qt нет для него ифдефа, скорее всего нет. Или это совсем маргинальный и никому не нужный конпелятор.

                                              З.Ы. Ну просто это сразу ломает копипасту из сишного кода, а конпеляторы не любят её ломать.
                                              Ответить
                                          • https://godbolt.org/z/6TEqTdYno - а верно ли, что компилятор icc тут не прав, и без __restrict так нельзя оптимизировать?

                                            #include <inttypes.h>
                                            union U {
                                                uint32_t u;
                                                float f;
                                            };
                                            
                                            float test(union U* __restrict u, float* __restrict f)
                                            {
                                                *f = 5;
                                                u->u = 42;
                                                *f = *f + 1;
                                                u->u = 43;
                                                return *f;
                                            }
                                            
                                            
                                            float test2(union U* u, float* f)
                                            {
                                                *f = 5;
                                                u->u = 42;
                                                *f = *f + 1;
                                                u->u = 43;
                                                return *f;
                                            }


                                            test:
                                                    movss     xmm0, DWORD PTR .L_2il0floatpacket.0[rip]     #11.15
                                                    movss     DWORD PTR [rsi], xmm0                         #11.6
                                                    mov       DWORD PTR [rdi], 43                           #12.5
                                                    ret                                                     #13.13
                                            test2:
                                                    movss     xmm0, DWORD PTR .L_2il0floatpacket.0[rip]     #21.15
                                                    movss     DWORD PTR [rsi], xmm0                         #21.6
                                                    mov       DWORD PTR [rdi], 43                           #22.5
                                                    ret                                                     #23.13
                                            .L_2il0floatpacket.0:
                                                    .long   0x40c00000


                                            Не нарушает ли icc стандарт Си?
                                            Ответить
                                  • > З.Ы. Что-то мне намекает, что в няшной они бы тоже рады убрать. Но уже все юзают.

                                    В крестах вот убрали, но все юзают, так что компиляторы такую хуйню поддерживают по-факту. И похуй на стандарт.
                                    Ответить
                            • Ну вот у тебя есть union от двух классов с ``unit32_t`` в начале.

                              Ты не знаешь какой там класс сейсас "активный", но думаешь: раз они оба начинается с ``unit32_t``, то считаю-ка я первые 4 байта, и будет заебись.

                              В сишке так и будет.

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

                                Во-вторых, виртуальное говно можно по отрицательным смещениям размещать, а данные пусть сразу начинается. Например, размер виртуального говна можно размещать по смещению class_ptr[-4] как 32-битное число, а по еще более отрицательным будет само виртуальное говно.
                                Ответить
                                • >Во-первых в сишке нет классов, так что "В сишке так и будет" это уже хуйня какая-то.

                                  Ебать ты буквоед, ну замени класс на структуру же.

                                  >Во-вторых, виртуальное говно можно по отрицательным смещениям размещать

                                  А как будет работать какое-нить memcpy?
                                  Ответить
                                  • > А как будет работать какое-нить memcpy?

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

                                      Я думал, если объект trivilaly copyable (ну то есть без сложных конструкторов всяких в себе и полях) то его можно memcpyить куда-то..
                                      Ответить
                                      • Не запрещает, но зачем это может понадобиться? Чисто ради пирфоманса в векторе?

                                        Виртуальное говно очень редко trivially copyable, как мне кажется.

                                        З.Ы. Или вообще никогда...
                                        Ответить
                                        • ну да, чтобы быстро скопировать куда-то много говна. ``memcpy`` может быть оче оптимизированной для конкретной платформы же

                                          >редко
                                          тоже так кажется (если там виртуальное, то туда уже оопидор пролез, и значит там конструкторы строго следят за инвариантом класса итд)

                                          Тем не менее, если стандарт это уже разрешил, то хранить что-то "перед" указателем будет тяжеловато

                                          >З.Ы. Или вообще никогда...

                                          абстрактная фабрика, или стратегия с несколькими методами (если один, то наверное лучше лямбдой)

                                          тока в них копировать нечего, лол
                                          Ответить
                                          • Виртуальное говно вообще не может быть trivially copyable, оказывается. Ибо конструктор копирования у такого класса нетривиален (Base b = child меняет vtbl).

                                            Так что этот кейс можно не рассматривать. Минусы в мемсру никогда не попадут.
                                            Ответить
                                            • Ебать овно, и правда добавление virtual метода сразу ломает
                                              ``std::is_trivially_copyable``

                                              Всё равно меня пугает идея джейцифирек, тебя нет?

                                              >Base b = child меняет vtb

                                              ну да, при копировании нужно не просто байтики скопировать, а указатель с ребенка перевести на родителя, не подумал
                                              Ответить
                                              • Да не особо пугает. В крестах уже есть кейс, когда ссылка на объект указывает не на начало блока памяти: множественное наследование. Т.е. в общем-то язык готов к работе с отрицательными оффсетами.
                                                Ответить
                                                • Угу, читал про такое

                                                  class Child:  Par1,  Par2


                                                  И там
                                                  par1_data
                                                  par2_data
                                                  child_data

                                                  а потом ты static_cast указателя Child* в Par2*, и стрелочка перемещается в par2_data, а "par1_data" оказывается "в минусе"

                                                  Или даже тупо передаешь Child в функцию, ожидающую Parent2&
                                                  Ответить
        • typedef qreal
          Typedef for double unless Qt is configured with the -qreal float option.
          Ответить
    • Кстати, чёт я разочаровался в этих всех парадигмах и прочих погромированиях. В последнее время, самый лучший погромист - это тот который знает все библиотеки. Но сам, блять, нихуя ничего не может. Очередной кассир пятёрочки на гитхабе. Бесит вообще.
      Пора уходить в строительную деятельность. Там хоть настоящий креатив можно применить, при оштукатуривании стен и прочих прокладках сантехники. А не вот это вот всё.
      Ответить
      • У меня в ``Erlang'' никаких библиотек нет...
        Ответить
      • Это в крестах-то?:)
        Ответить
      • знает все библиотеки на JavaScript, гы
        (да, я про NPM)
        Ответить
        • Кстати в JS знание фреймворков и инструментов действительно важны, бо сам язык прост (хоть и коряв), а инструменты сложны (один webpack чего стоит, лол)_
          Ответить
    • Qt-бляди как обычно без аутофелляции не могут:
      https://en.cppreference.com/w/cpp/language/range-for

      Но для крестоценителей всегда есть такая жемчужина, как
      https://www.boost.org/doc/libs/1_76_0/boost/foreach.hpp
      Ответить
      • > Но для крестоценителей всегда есть такая жемчужина, как
        > https://www.boost.org/doc/libs/1_76_0/boost/foreach.hpp

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

          BOOST_FOREACH разъебал в одну калитку этот ламерский Q_FOREACH
          написать макрос на 500 строк могут не только лишь все
          Ответить
    • я думал там форыч в компайл тайме, а там просто красивая обертка вокруг цыкла, как в асемблере
      Ответить

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