001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2008-2012 SonarSource
004     * mailto:contact AT sonarsource DOT com
005     *
006     * Sonar is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU Lesser General Public
008     * License as published by the Free Software Foundation; either
009     * version 3 of the License, or (at your option) any later version.
010     *
011     * Sonar is distributed in the hope that it will be useful,
012     * but WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     * Lesser General Public License for more details.
015     *
016     * You should have received a copy of the GNU Lesser General Public
017     * License along with Sonar; if not, write to the Free Software
018     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
019     */
020    package org.sonar.plugins.core.timemachine.tracking;
021    
022    /**
023     * Equivalence function for {@link StringText}.
024     */
025    public abstract class StringTextComparator implements SequenceComparator<StringText> {
026    
027      /**
028       * Ignores all whitespace.
029       */
030      public static final StringTextComparator IGNORE_WHITESPACE = new StringTextComparator() {
031    
032        public boolean equals(StringText a, int ai, StringText b, int bi) {
033          ai++;
034          bi++;
035          int as = a.lines.get(ai);
036          int bs = b.lines.get(bi);
037          int ae = a.lines.get(ai + 1);
038          int be = b.lines.get(bi + 1);
039          ae = trimTrailingWhitespace(a.content, as, ae);
040          be = trimTrailingWhitespace(b.content, bs, be);
041          while ((as < ae) && (bs < be)) {
042            char ac = a.content.charAt(as);
043            char bc = b.content.charAt(bs);
044            while ((as < ae - 1) && (Character.isWhitespace(ac))) {
045              as++;
046              ac = a.content.charAt(as);
047            }
048            while ((bs < be - 1) && (Character.isWhitespace(bc))) {
049              bs++;
050              bc = b.content.charAt(bs);
051            }
052            if (ac != bc) {
053              return false;
054            }
055            as++;
056            bs++;
057          }
058          return (as == ae) && (bs == be);
059        }
060    
061        @Override
062        protected int hashRegion(String content, int start, int end) {
063          int hash = 5381;
064          for (; start < end; start++) {
065            char c = content.charAt(start);
066            if (!Character.isWhitespace(c)) {
067              hash = ((hash << 5) + hash) + (c & 0xff);
068            }
069          }
070          return hash;
071        }
072    
073      };
074    
075      public int hash(StringText seq, int line) {
076        final int begin = seq.lines.get(line + 1);
077        final int end = seq.lines.get(line + 2);
078        return hashRegion(seq.content, begin, end);
079      }
080    
081      protected abstract int hashRegion(String content, int start, int end);
082    
083      public static int trimTrailingWhitespace(String content, int start, int end) {
084        end--;
085        while (start <= end && Character.isWhitespace(content.charAt(end))) {
086          end--;
087        }
088        return end + 1;
089      }
090    
091    }