1. Java / Говнокод #10381

    +75

    1. 1
    2. 2
    3. 3
    4. 4
    5. 5
    6. 6
    byte[] buf = new byte[8192];
    int len = 0;
    while ((len = is.read(buf))>0)
    {
        requestString += new String(buf, 0, len, "UTF-8");
    }

    Пока никто не кормил туда настоящий UTF-8. Только ascii.

    Запостил: konsoletyper, 28 Мая 2012

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

    • Автор не слышал про InputStreamReader?
      Ответить
      • Лучше уж тогда BufferedReader. А вообще, вариантов куча. Например, IOUtils из apache commons (тем более, что оный обнаружен в classpath'е проекта) или какой-нибудь nio
        Ответить
    • Проблема возникнет, если символ придется на край буфера?
      Ответить
      • Ага. Кроме того, это ещё и велосипед
        Ответить
        • Эх... Вот если бы он еще сам по байтикам разбирал, типа if ((b1 & 0x80) != 0) { b2 = is.readByte(); ... }
          Ответить
          • Тогда бы все работало :)
            Ответить
            • Хотя не все.

              Он бы всяко забыл про то, что следует игнорить символы, записанные не самым кратким образом. Например если 0x0A записали в виде двух-трех байт.
              Ответить
      • А ещё тормоза из-за постоянного перевыделения памяти при конкатенации строк
        Ответить
        • А как делают мастера, если надо собрать n строк в одну?
          Ответить
          • StringBuilder
            Ответить
            • Ну, это частный случай для Java и т.д., а если руками?
              Ответить
              • Ну на низком уровне - сложить все строки во что-то типа стека (лишь бы вставляло за О(1)) и затем за один concat поклеить их.
                Ответить
              • А руками - написать свой StringBuilder :-)
                Ответить
              • Если бы у меня было большое желание написать string-builder на сишке, я бы поступил так:
                завёл структуру
                typedef struct {
                    char *data;
                    size_t capacity;
                    size_t tail;
                } string_builder_t;

                ввёл бы несколько функций
                string_builder_t* new_builder(size_t);
                string_builder_t* append_to(string_builder_t*, char *, size_t);
                char *to_string(string_builder_t*);
                append_to() работает очень просто: складывает символы в массив, обновляя значение tail. Когда кончается место (tail + len> capacity) - реаллочит массив, увеличивая размер в полтора-два раза.
                Ответить
                • Плюсую, в проекте на С использовал именно такой буфер.
                  Только в интерфейсе модуля были еще buffer_free и buffer_size.

                  P.S. А тот вариант который я писал выше (про стек) он для языков с GC (в частности в Lua так реализована склейка строк).
                  Ответить
                  • на что только не пойдут на С люди, лишь бы не использовать С++
                    Ответить
                    • не всегда есть возможность
                      Ответить
                    • На что только не пойдут плюсовики, лишь бы не использовать GObject.

                      (Кстати, о GObject: в GLib есть GString, который в Vala замаплен под именем - да-да, StringBuilder. И реализован он именно так.)
                      Ответить
                      • судя по минусам, мой безобидный вброс таки доставил батхёрта
                        кстати о именно так - именно так реализовано много чего, от std::vector до, ты не поверишь, std::string, обычно лежащего в основе да-да, std::stringbuf
                        и не удивлюсь, если эта незатейливая идея, которую С предлагает изобрести ручками каждый раз заново, именно так реализована в библиотеках еще кучи языков
                        Ответить
                • >увеличивая размер в полтора-два раза
                  Любопытно, кстати, в Qt реализовано: поначалу выделяются степени двойки (минус константа), а при достижении размера около 4080 байт рост дальше идет линейно, размер увеличивается шагами в 4096 байт. Объясняется это тем, что при realloc-е система просто перемапливает старые страницы, а не копирует байты, поэтому наращивание массива происходит очень быстро.
                  Ответить
                  • Но это только при условии, что вектор действительно делает realloc, а не создание нового куска и копирование.
                    Кстати, как realloc подружить с конструктором сдвига?
                    Ответить
                    • для не-POD типов ни realloc, ни memcpy не пригодны
                      но Qt видней, конечно
                      Ответить
                      • Из corelib/tools/qvector.h:
                        template <typename T>
                        void QVector<T>::append(const T &t)
                        {
                            if (d->ref != 1 || d->size + 1 > d->alloc) {
                                const T copy(t);
                                realloc(d->size, QVectorData::grow(sizeOfTypedData(), d->size + 1, sizeof(T),
                                                                   QTypeInfo<T>::isStatic));
                                if (QTypeInfo<T>::isComplex)
                                    new (p->array + d->size) T(copy);
                                else
                                    p->array[d->size] = copy;
                            } else {
                                if (QTypeInfo<T>::isComplex)
                                    new (p->array + d->size) T(t);
                                else
                                    p->array[d->size] = t;
                            }
                            ++d->size;
                        }


                        POD'ы быстро и грязно, а классы как положено.
                        Ответить
                        • Тьфу, не ту функцию кинул. Надо было QVector::realloc(). Но суть та же самая - через тайпинфо проверяется POD ли это, и если да - используется чит.
                          Ответить
                          • фу
                            1) это должно быть через специализации сделано, а не отдано на откуп компиляторной оптимизации if (0) stmt1; else stmt2; --> stmt2;
                            2) размер в байтах на сколько надо вырасти известен аллокатору, не нужно подсовывать никаких sizeOfTypedData() и sizeof(T)
                            как всегда Qt блещет вылизанностью, не то, что мерзкий стандарт для лохов, ага
                            Ответить
                            • >это должно быть через специализации сделано
                              Т.е. вы предлагаете растащить специализации, сосредоточенные в QTypeInfo, по всем подряд контейнерам?
                              Ответить
                              • ничего сверхъестественного там не сосредоточено, разница POD-неPOD очевидно хранится в значении QTypeInfo<T>::isComplex = true|false, известном на этапе компиляции, посему не вижу проблем сделать шаблон от bool, делающий неPOD функционал и рядом специализацию от <true>, делающую POD функционал

                                в голову приходит лишь объяснение, что Qt мол собралась компилироваться компилятором вообще без поддержки partial specialization

                                <наброс>а взрослую библиотеку информации по типам можно посмотреть вот тут http://bit.ly/Jyomed </наброс>
                                Ответить
                                • > посему не вижу проблем сделать шаблон от bool
                                  Согласен
                                  Ответить
                                • >Qt мол собралась компилироваться компилятором вообще без поддержки partial specialization

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

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

                          что должен делать такой менеджер кучи? на каждый чих сохранять адрес копирующего конструктора для каждого выделяемого пойнтера, либо признак что конструктора нет (== plain old data, достаточно побитового копирования)

                          что такое кастомный менеджер кучи в понятии С++ - в первом приближении - свой аллокатор, но типичное для stl stateless использование аллокатора печалит и отторгает
                          тем не менее, myalloc<T>::construct(ptr, T &) и myalloc<T>::destroy(ptr, count) предоставляют понимание какой конкретно тип создается по конкретному указателю, так что можно составлять таблицу типов, привязывать пойнтер к записи в таблице, там искать указатель на копирующий конструктор. как-то так

                          можно избавить контейнер от не очень то сложных действий in place, зато очень сильно усложнить кастомный менеджер кучи, + наверняка вся эта конструкция будет работать еще и медленнее
                          выхлоп не тот, всего то ради выбора memcpy/copy(dest, first, last)

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

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