1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * See LICENSE.txt included in this distribution for the specific 9 * language governing permissions and limitations under the License. 10 * 11 * When distributing Covered Code, include this CDDL HEADER in each 12 * file and include the License file at LICENSE.txt. 13 * If applicable, add the following below this CDDL HEADER, with the 14 * fields enclosed by brackets "[]" replaced with your own identifying 15 * information: Portions Copyright [yyyy] [name of copyright owner] 16 * 17 * CDDL HEADER END 18 */ 19 20 /* 21 * Copyright (c) 2020, Chris Fraire <cfraire@me.com>. 22 */ 23 package org.opengrok.indexer.index; 24 25 import org.opengrok.indexer.analysis.AccumulatedNumLinesLOC; 26 import org.opengrok.indexer.analysis.NumLinesLOC; 27 import org.opengrok.indexer.web.Util; 28 29 import java.io.File; 30 import java.util.HashMap; 31 import java.util.Iterator; 32 import java.util.Map; 33 34 /** 35 * Represents an accumulator of net-deltas of #Lines and LOC for directories. 36 */ 37 public class NumLinesLOCAggregator { 38 private final Object syncRoot = new Object(); 39 40 private final HashMap<String, DeltaData> registeredDeltas = new HashMap<>(); 41 42 /** 43 * Gets an iterator over all registered data, explicit and derived, and not 44 * ordered. 45 * @return a defined instance 46 */ iterator()47 public Iterator<AccumulatedNumLinesLOC> iterator() { 48 return new AccumulationsIterator(registeredDeltas.entrySet().iterator()); 49 } 50 51 /** 52 * Registers the specified counts. Values should be negative when deleting a 53 * file or when updating a file's analysis to reverse former values before 54 * re-registering. 55 */ register(NumLinesLOC counts)56 public void register(NumLinesLOC counts) { 57 File file = new File(counts.getPath()); 58 File directory = file.getParentFile(); 59 if (directory != null) { 60 synchronized (syncRoot) { 61 do { 62 String dirPath = Util.fixPathIfWindows(directory.getPath()); 63 DeltaData extantDelta = registeredDeltas.get(dirPath); 64 if (extantDelta == null) { 65 extantDelta = new DeltaData(); 66 registeredDeltas.put(dirPath, extantDelta); 67 } 68 extantDelta.numLines += counts.getNumLines(); 69 extantDelta.loc += counts.getLOC(); 70 } while ((directory = directory.getParentFile()) != null && 71 directory.getPath().length() > 0); 72 } 73 } 74 } 75 76 private static class DeltaData { 77 long numLines; 78 long loc; 79 } 80 81 private static class AccumulationsIterator implements Iterator<AccumulatedNumLinesLOC> { 82 private final Iterator<Map.Entry<String, DeltaData>> underlying; 83 AccumulationsIterator(Iterator<Map.Entry<String, DeltaData>> underlying)84 AccumulationsIterator(Iterator<Map.Entry<String, DeltaData>> underlying) { 85 this.underlying = underlying; 86 } 87 88 @Override hasNext()89 public boolean hasNext() { 90 return underlying.hasNext(); 91 } 92 93 @Override next()94 public AccumulatedNumLinesLOC next() { 95 Map.Entry<String, DeltaData> underlyingNext = underlying.next(); 96 String path = underlyingNext.getKey(); 97 DeltaData values = underlyingNext.getValue(); 98 return new AccumulatedNumLinesLOCImpl(path, values.numLines, values.loc); 99 } 100 } 101 102 private static class AccumulatedNumLinesLOCImpl implements AccumulatedNumLinesLOC { 103 104 private final String path; 105 private final long numLines; 106 private final long loc; 107 AccumulatedNumLinesLOCImpl(String path, long numLines, long loc)108 AccumulatedNumLinesLOCImpl(String path, long numLines, long loc) { 109 this.path = path; 110 this.numLines = numLines; 111 this.loc = loc; 112 } 113 114 @Override getPath()115 public String getPath() { 116 return path; 117 } 118 119 @Override getNumLines()120 public long getNumLines() { 121 return numLines; 122 } 123 124 @Override getLOC()125 public long getLOC() { 126 return loc; 127 } 128 } 129 } 130