您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

BlocksGroup.java 6.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2021 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. package org.sonar.duplications.detector.original;
  21. import java.util.ArrayList;
  22. import java.util.Comparator;
  23. import java.util.List;
  24. import javax.annotation.CheckForNull;
  25. import org.sonar.duplications.block.Block;
  26. import org.sonar.duplications.utils.FastStringComparator;
  27. /**
  28. * Set of {@link Block}s, which internally stored as a sorted list.
  29. */
  30. final class BlocksGroup {
  31. final List<Block> blocks;
  32. /**
  33. * Factory method.
  34. *
  35. * @return new empty group
  36. */
  37. public static BlocksGroup empty() {
  38. return new BlocksGroup();
  39. }
  40. private BlocksGroup() {
  41. this.blocks = new ArrayList<>();
  42. }
  43. public int size() {
  44. return blocks.size();
  45. }
  46. /**
  47. * @return true, if this group subsumed by specified group
  48. * @see #subsumedBy(BlocksGroup, BlocksGroup, int)
  49. */
  50. public boolean subsumedBy(BlocksGroup other, int indexCorrection) {
  51. return subsumedBy(this, other, indexCorrection);
  52. }
  53. /**
  54. * @return intersection of this group with specified
  55. * @see #intersect(BlocksGroup, BlocksGroup)
  56. */
  57. public BlocksGroup intersect(BlocksGroup other) {
  58. return intersect(this, other);
  59. }
  60. public List<Block[]> pairs(BlocksGroup other, int len) {
  61. return pairs(this, other, len);
  62. }
  63. /**
  64. * First block from this group with specified resource id.
  65. */
  66. @CheckForNull
  67. public Block first(String resourceId) {
  68. for (Block block : blocks) {
  69. if (resourceId.equals(block.getResourceId())) {
  70. return block;
  71. }
  72. }
  73. return null;
  74. }
  75. @Override
  76. public String toString() {
  77. return blocks.toString();
  78. }
  79. /**
  80. * Intersection of two groups is a group, which contains blocks from second group that have corresponding block from first group
  81. * with same resource id and with corrected index.
  82. */
  83. private static BlocksGroup intersect(BlocksGroup group1, BlocksGroup group2) {
  84. BlocksGroup intersection = new BlocksGroup();
  85. List<Block> list1 = group1.blocks;
  86. List<Block> list2 = group2.blocks;
  87. int i = 0;
  88. int j = 0;
  89. while (i < list1.size() && j < list2.size()) {
  90. Block block1 = list1.get(i);
  91. Block block2 = list2.get(j);
  92. int c = RESOURCE_ID_COMPARATOR.compare(block1.getResourceId(), block2.getResourceId());
  93. if (c > 0) {
  94. j++;
  95. continue;
  96. }
  97. if (c < 0) {
  98. i++;
  99. continue;
  100. }
  101. if (c == 0) {
  102. c = block1.getIndexInFile() + 1 - block2.getIndexInFile();
  103. }
  104. if (c == 0) {
  105. // list1[i] == list2[j]
  106. i++;
  107. j++;
  108. intersection.blocks.add(block2);
  109. }
  110. if (c > 0) {
  111. // list1[i] > list2[j]
  112. j++;
  113. }
  114. if (c < 0) {
  115. // list1[i] < list2[j]
  116. i++;
  117. }
  118. }
  119. return intersection;
  120. }
  121. /**
  122. * One group is subsumed by another group, when each block from first group has corresponding block from second group
  123. * with same resource id and with corrected index.
  124. */
  125. private static boolean subsumedBy(BlocksGroup group1, BlocksGroup group2, int indexCorrection) {
  126. List<Block> list1 = group1.blocks;
  127. List<Block> list2 = group2.blocks;
  128. int i = 0;
  129. int j = 0;
  130. while (i < list1.size() && j < list2.size()) {
  131. Block block1 = list1.get(i);
  132. Block block2 = list2.get(j);
  133. int c = RESOURCE_ID_COMPARATOR.compare(block1.getResourceId(), block2.getResourceId());
  134. if (c != 0) {
  135. j++;
  136. continue;
  137. }
  138. c = block1.getIndexInFile() - indexCorrection - block2.getIndexInFile();
  139. if (c < 0) {
  140. // list1[i] < list2[j]
  141. break;
  142. }
  143. if (c != 0) {
  144. // list1[i] != list2[j]
  145. j++;
  146. }
  147. if (c == 0) {
  148. // list1[i] == list2[j]
  149. i++;
  150. j++;
  151. }
  152. }
  153. return i == list1.size();
  154. }
  155. private static List<Block[]> pairs(BlocksGroup beginGroup, BlocksGroup endGroup, int len) {
  156. List<Block[]> result = new ArrayList<>();
  157. List<Block> beginBlocks = beginGroup.blocks;
  158. List<Block> endBlocks = endGroup.blocks;
  159. int i = 0;
  160. int j = 0;
  161. while (i < beginBlocks.size() && j < endBlocks.size()) {
  162. Block beginBlock = beginBlocks.get(i);
  163. Block endBlock = endBlocks.get(j);
  164. int c = RESOURCE_ID_COMPARATOR.compare(beginBlock.getResourceId(), endBlock.getResourceId());
  165. if (c == 0) {
  166. c = beginBlock.getIndexInFile() + len - 1 - endBlock.getIndexInFile();
  167. }
  168. if (c == 0) {
  169. result.add(new Block[] {beginBlock, endBlock});
  170. i++;
  171. j++;
  172. }
  173. if (c > 0) {
  174. j++;
  175. }
  176. if (c < 0) {
  177. i++;
  178. }
  179. }
  180. return result;
  181. }
  182. private static final Comparator<String> RESOURCE_ID_COMPARATOR = FastStringComparator.INSTANCE;
  183. /**
  184. * Compares {@link Block}s first using {@link Block#getResourceId() resource id} and then using {@link Block#getIndexInFile() index in file}.
  185. */
  186. public static class BlockComparator implements Comparator<Block> {
  187. public static final BlockComparator INSTANCE = new BlockComparator();
  188. @Override
  189. public int compare(Block b1, Block b2) {
  190. int c = RESOURCE_ID_COMPARATOR.compare(b1.getResourceId(), b2.getResourceId());
  191. if (c == 0) {
  192. return b1.getIndexInFile() - b2.getIndexInFile();
  193. }
  194. return c;
  195. }
  196. }
  197. }