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 */
020package org.sonar.plugins.core.timemachine.tracking;
021
022/**
023 * Equivalence function for {@link StringText}.
024 */
025public 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}