void (@NotNull String path, int startIndex) { if (myPaths.size() > DIRTY_SCOPE_SIZE_THRESHOLD) { // Avoid performance issues for specific 'poorly mergeable' dirty path configurations. // This should not happen in practice. markEverythingDirty(); return; } int index = startIndex; int previousPrefixHash = 0; IntList prefixHashes = new IntArrayList(); prefixHashes.add(0); int prevCounter = myPathHashCounters.get(0); boolean needCutOff = false; while (index < path.length()) { int nextIndex = path.indexOf('/', index + 1); if (nextIndex == -1) nextIndex = path.length(); int prefixHash = FilePathHashUtil.pathHashCode(myCaseSensitive, path, index, nextIndex, previousPrefixHash); if (myPathHashSet.contains(prefixHash)) { String prefix = path.substring(startIndex, nextIndex); if (myPaths.contains(prefix)) return; } int counter = myPathHashCounters.get(prefixHash); boolean addParentFolder = needCutOff && counter < prevCounter || prevCounter - counter > FOLDER_SIZE_THRESHOLD; if (counter < FOLDER_SIZE_THRESHOLD && prevCounter >= FOLDER_SIZE_THRESHOLD) { needCutOff = true; // merge current folder } if (addParentFolder) { if (startIndex == index) { markEverythingDirty(); return; } myPaths.add(path.substring(startIndex, index)); myPathHashSet.add(previousPrefixHash); for (int i = 0; i < prefixHashes.size(); i++) { int hash = prefixHashes.getInt(i); myPathHashCounters.mergeInt(hash, 1 - prevCounter, (val1, val2) -> Math.max(val1 + val2, 1)); } return; } // do not increase counter - handle hash collisions if (counter < prevCounter) { prevCounter = counter; } prefixHashes.add(prefixHash); previousPrefixHash = prefixHash; index = nextIndex; } myPaths.add(path.substring(startIndex, index)); myPathHashSet.add(previousPrefixHash); for (int i = 0; i < prefixHashes.size(); i++) { int hash = prefixHashes.getInt(i); myPathHashCounters.mergeInt(hash, 1, (val1, val2) -> val1 + val2); } }