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

    +119

    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
    26. 26
    27. 27
    28. 28
    29. 29
    30. 30
    31. 31
    32. 32
    33. 33
    34. 34
    35. 35
    36. 36
    37. 37
    38. 38
    39. 39
    40. 40
    41. 41
    42. 42
    43. 43
    44. 44
    45. 45
    46. 46
    47. 47
    48. 48
    49. 49
    50. 50
    51. 51
    52. 52
    53. 53
    54. 54
    55. 55
    56. 56
    57. 57
    58. 58
    59. 59
    60. 60
    61. 61
    62. 62
    63. 63
    64. 64
    65. 65
    66. 66
    67. 67
    68. 68
    69. 69
    70. 70
    71. 71
    72. 72
    73. 73
    /**
         * Parses inlined match flags and set them appropriately.
         */
        private void addFlag() {
            int ch = peek();
            for (;;) {
                switch (ch) {
                case 'i':
                    flags |= CASE_INSENSITIVE;
                    break;
                case 'm':
                    flags |= MULTILINE;
                    break;
                case 's':
                    flags |= DOTALL;
                    break;
                case 'd':
                    flags |= UNIX_LINES;
                    break;
                case 'u':
                    flags |= UNICODE_CASE;
                    break;
                case 'c':
                    flags |= CANON_EQ;
                    break;
                case 'x':
                    flags |= COMMENTS;
                    break;
                case '-': // subFlag then fall through
                    ch = next();
                    subFlag();
                default:
                    return;
                }
                ch = next();
            }
        }
    
        /**
         * Parses the second part of inlined match flags and turns off
         * flags appropriately.
         */
        private void subFlag() {
            int ch = peek();
            for (;;) {
                switch (ch) {
                case 'i':
                    flags &= ~CASE_INSENSITIVE;
                    break;
                case 'm':
                    flags &= ~MULTILINE;
                    break;
                case 's':
                    flags &= ~DOTALL;
                    break;
                case 'd':
                    flags &= ~UNIX_LINES;
                    break;
                case 'u':
                    flags &= ~UNICODE_CASE;
                    break;
                case 'c':
                    flags &= ~CANON_EQ;
                    break;
                case 'x':
                    flags &= ~COMMENTS;
                    break;
                default:
                    return;
                }
                ch = next();
            }
        }

    очередной кусок творчества Chen-Lieh Huang, Alan Liu
    /* @(#)Pattern.java 1.113 07/05/07
    * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
    * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
    */

    продолжение #3976 #3975 #3940 #3998 #3999 #4007

    Запостил: 3.14159265, 21 Августа 2010

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

    • так а где собственно говно? выглядит нормально.

      если и говно - то не очевидное.
      Ответить
      • выглядит просто охуенно, а пахнет еще лучше - потому сюда и запостил
        вот именно из-за таких вот [spoiler]говно[/spoiler]кодеров в классе over95K строк
        Ответить
        • я не спец по Жабе. если на то уже пошло, ты бы уж написал как это правильней делать.
          Ответить
          • дело не в жабе не понимаешь - минусуй
            тут есть гораздо более очевидное говно
            http://govnokod.ru/3566
            Ответить
            • минуснул потому что может и говно, но не очеведное и не интересное.

              а васик (или дельфи) минусовать, это все равно что над ущербными детишками глумится...
              Ответить
              • >минуснул
                мне насрать - твое право, только вот спецом по жабе не надо быть чтоб понять где тут говно ибо оно везде
                Ответить
          • лана, я передумал поиграю очевидное капитанство

            tips:
            a) case не нужен - юзай мап
            б) две функции сливай в одну dsflag(boolean add) и инвертируй в зав add

            private void addFlag() {dsflag(true);}
            private void subFlag() {dsflag(false);}

            алсо как заметил Lure Of Chaos for (;;) - и неочевидный выход из цикла, но это уже тонкости, по сранению с вышенаписанным
            Ответить
            • map будет медленее чем switch/case. последнее будет соптимизоровано джитом, первое - нет. другими словами дело вкуса и придирки.

              я понимаю если бы в коде был реальный и неочевидный баг...
              Ответить
              • повторяю - в коде китайская копипаста.
                как минима - свести 2 функции в 1.
                потом есть for
                почему бы нам не написать, что-то вроде
                for (int ch = peek();<условие мапа>;ch = next();)

                >>map будет медленее чем switch/case.
                да неужели? есть разные мапы - TreeMap например - поиск по дереву быстрее перебора инфа 100%.

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

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

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

                    да-да-да знаем мы эти оптимизации, на словах - чудеса, а на деле в самых простых моментах говно.

                    для тех кто еще сомневается в говености сего, нашел нормальную некитайскую Apache имплементацию класса от (как это не странно) нашего соотечественника @author Nikolay A. Kuznetsov

                    http://www.docjar.com/html/api/java/util/regex/Pattern.java.html

                    1400 строк заместо 5600!!! и это при том что коментариев там дохера и они никуда не делись over 4 раза сокращение объема

                    так вот там этой логики вообще нет, что кагбе намекает...
                    Ответить
                  • http://java.sun.com/docs/books/jvms/second_edition/html/Compiling.doc.html#14942

                    это про то, как компилируются свичи. Если вкратце, то в зависимости от того, какие у свича есть case-ы, они компилируются либо с использованием массива(tableswitch), с доступом за O(1), либо в некоторую струкруту, отсортированную по ключу(lookupswitch). Явно в стандарте не говорится, какой алгоритм использовать, но производительность явно не хуже O(logN), где N -- число case-ов.
                    Ответить
                    • При этом, очевидно, что и tableswitch и lookupswitch работают куда быстрее, чем любая реализация, которую может написать человек на java, т.к. каждый из них -- одна-единственная инструкция для JVM.

                      Дело, правда, в том, что различия в скорости могут оказаться очень мизерными, вплоть до наносекунд, которыми вполне можно принебречь.
                      Ответить
                      • хм, круто, НО
                        Where the cases of the switch are sparse, the table representation of the tableswitch instruction becomes inefficient in terms of space. The lookupswitch instruction may be used instead. The lookupswitch instruction pairs int keys (the values of the case labels) with target offsets in a table. When a lookupswitch instruction is executed, the value of the expression of the switch is compared against the keys in the table. If one of the keys matches the value of the expression, execution continues at the associated target offset. If no key matches, execution continues at the default target.

                        то есть приведенный пример будет компилится в lookupswitch и тут главное
                        the expression of the switch is compared against the keys in the table
                        то есть некий поиск о чем мы и говорим

                        >tableswitch и lookupswitch работают куда быстрее, чем любая реализация, которую может написать человек на java

                        предложенный мною вариант - вообще работает без поиска
                        http://govnokod.ru/4054#comment44492

                        >т.к. каждый из них -- одна-единственная инструкция для JVM.

                        но так как там lookup в table - то это компилится в целую тучу ассм-инструкций
                        Ответить
                        • >то есть приведенный пример будет компилится в lookupswitch и тут главное

                          вот это как раз-таки не факт. В принципе, case-ы не особо разбросаны, так что может закомпилиться и в tableswitch.

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

                          но я всё-таки думаю, что адекватные компиляторы поймут, что в этом случае tableswitch можно юзать спокойно.
                          Ответить
              • На крайняк можно из символов на зоду битовые флаги мутить)
                ЗЫ: я не знаю, с какой скоростью работают мэпы.
                Ответить
    • for (;;) очаровательная конструкция
      Ответить
      • всегда как постю реально китайский гкод и явно пишу - исходники явы, вылазит очередной кто-то и начинает доказывать с кодом все заебись, ОП - нихуя не шарит итд.
        Ответить
        • код старый, а хорошие традиции медленно приживаются. Надо бы сравнить @since классов Pattern и TreeMap - вполне может статься, что тогда не было карт
          Ответить
      • если приглядеться то можно увидеть лицо с тентаклями. Стало быть, содержимое данного блока приносится в жертву Ктулху!
        Ответить
    • и вообще я бы наверное сделал как-то так
      private void subFlag() {
      	int[] maskmap = { 
      		'i', CASE_INSENSITIVE,
      		'm', MULTILINE,
      		's', DOTALL,
      		'd', UNIX_LINES,
      		'u', UNICODE_CASE,
      		'c', CANON_EQ,
      		'x', COMMENTS
      	};
      	boolean valid = true;
      	for(int ch = peek() ; valid; ch=next(), valid=false) {
      		for(int i=0; i<maskmap.length; i+=2) {
      			if (ch == maskmap[i]) {
      				flags &= ~( maskmap[i+1] );
      				valid = true;
      			}
      		}		
      	}
      }

      но всё же думаю, что вариант со switch-case будет шустрее, а в регулярках важнее всего скорость, как ни крути. Юзать Map из 7 элементов = из пушки по воробьям.

      По поводу дублирования функций согласен.
      Ответить
      • У тебя во вложенном цикле забыт break в конце. Плюс, линейный поиск элемента всегда будет проигрывать двоичному. Я бы попробовал написать так:

        private static final char[] FLAG_SYMBOLS = {
        'i', 'm', 's', 'd', 'u', 'c', 'x'
        };

        private static final int[] FLAG_BITS = {
        CASE_INSENSITIVE, MULTILINE, DOTALL, UNIX_LINES, UNICODE_CASE, CANON_EQ, COMMENTS
        };

        private void addFlag() {
        boolean valid = true;
        for(char ch = peek(); valid; ch = next()) {
        valid = addFlag(ch, false);
        }
        }

        private boolean addFlag(char ch, boolean resetFlag) {
        if (ch == '-') {
        addFlag(next(), true);
        }
        int index = Arrays.binarySearch(FLAG_SYMBOLS, ch);
        if (index != -1) {
        int flagBit = FLAG_BITS[index];
        if (resetFlag) {
        flags &= ~flagBit;
        } else {
        flags |= flagBit;
        }
        return true;
        }
        return false;
        }

        правда, читать это немного сложнее, чем китайский вариант, плюс, добавляется зависимость от класса Arrays.
        Ответить
        • Да, FLAG_SYMBOLS нужно отсортировать (текущий вариант нерабочий), поменяв также местами значения из FLAG_BITS, но суть остается прежней - использовать Arrays.binarySearch.

          private static final char[] FLAG_SYMBOLS = {
          		'i', 'm', 's', 'd', 'u', 'c', 'x'
          	};
          	
          	private static final int[] FLAG_BITS = {
          		CASE_INSENSITIVE, MULTILINE, DOTALL, UNIX_LINES, UNICODE_CASE, CANON_EQ, COMMENTS
          	};
          	
          	private void addFlag() {
          		boolean valid = true;
          		for(char ch = peek(); valid; ch = next()) {
          			valid = addFlag(ch, false);			
          		}
          	}
          	
          	private boolean addFlag(char ch, boolean resetFlag) {
          		if (ch == '-') {
          			addFlag(next(), true);
          		}
          		int index = Arrays.binarySearch(FLAG_SYMBOLS, ch);
          		if (index != -1) {
          			int flagBit = FLAG_BITS[index];
          			if (resetFlag) {
          				flags &= ~flagBit;				
          			} else {
          				flags |= flagBit;
          			}
          			return true;
          		} 
          		return false;
          	}
          Ответить
          • 2 Мистер Хэнки, RuslanSch2
            Ыыы)) ну вы блин даете.
            итак мой вариант (заточенный на скорость)

            1.сначала проверяем является ли символ маленькой буквой - нет на выход (отдельно прописываем if (ch == '-') {)

            2.создаем static final char[] SYMB 26 элементов для маленьких букв - всю ту хероту заносим в массив, все окромя 'i', 'm', 's', 'd', 'u', 'c', 'x' забиваем неким EMPTY.

            условие выхода из цикла SYMB[ch-'a']==EMPTY - все никаких бинарных поисков и пр.
            Ответить
            • У меня была идея сделать более быстрый маппинг за счет избыточности. Для конкретной заранее известной локали вариант сработает (коды букв 'a', 'b', 'c' и пр. известны, поэтому вычитание ch - 'a' пройдет на "ура"). Только, как я понял, у тебя будет не char[] SYMB, а int[] FLAGS, где, к примеру FLAGS[8] = CASE_INSENSITIVE (8 - индекс 'i' в латинице). Правда, и у такого решения есть свои минусы: 1) оно нерасширяемо. Если для получения флагов будут использоваться цифры, то 26-символьного int[] массива уже будет недостаточно. А если еще добавить и русские символы, то наступит полнейший кошмар 2) этот код будет сложнее сопровождать, т.е. если нужно будет по-быстрому добавить или удалить еще один флаг, то придется вникать в весь блок и аккуратно делать замену в массиве. Чтобы сделать мэппинг более очевидным, придется его задавать более понятном для человека виде, т.е. создавать static-блок, состоящем из строчек вида: FLAGS['i'-'a'] = CASE_INSENSITIVE;
              Ответить
              • имхо, сопровождать проще изменив массив в одном месте, чем кейсы по проекту.

                + массив - самая быстрая реализация, быстрее огромного свитча. ИНФА 100%

                >Если для получения флагов будут использоваться цифры, то 26-символьного int[] массива уже будет недостаточно.
                это был пример заточеннный на скорость
                Ответить
        • Лучше б словами написал, что ты там сделать хочешь. Не засирай комменты.
          Ответить
          • >Не засирай комменты.
            +1
            В комментах срать лучше словами.
            Кодом срут только в самом верху.
            Ответить
            • зато ж наглядно, КАК
              Ответить
              • Для меня как-то не наглядно: если сверху как-то еще могу втыкнуть, то здесь ваще ощущаю себя тупым)) И прокручивать через пару дней невозможно будет.
                Ответить
          • Учту на будущее :))) Просто это мой самый первый пост здесь. Кстати, вариант с мэппингом через одну из реализаций Map<Object, Object> не самый удачный - в качестве ключа нужно всегда передавать объект, а это лишняя работа для GC. Разумеется, для случаев с Integer-ами из диапазона от -128 до 127 Java-машина может использовать заранее выделенные объекты, но все же
            Ответить
        • > линейный поиск элемента всегда будет проигрывать двоичному
          Константа у бинпоиска больше, если массив маленький, то линейный поиск будет быстрее. Как, например, в этом случае.
          Ответить
      • +1 что будет шустрее
        да и если не так много элементов - switch еще и наглядней
        Ответить

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