1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package org.apache.commons.io.file; 19 20 import java.math.BigInteger; 21 import java.util.Objects; 22 23 /** 24 * Provides counters for files, directories, and sizes, as a visit proceeds. 25 * 26 * @since 2.7 27 */ 28 public class Counters { 29 30 /** 31 * Counts files, directories, and sizes, as a visit proceeds. 32 */ 33 private static class AbstractPathCounters implements PathCounters { 34 35 private final Counter byteCounter; 36 private final Counter directoryCounter; 37 private final Counter fileCounter; 38 39 /** 40 * Constructs a new instance. 41 * 42 * @param byteCounter the byte counter. 43 * @param directoryCounter the directory counter. 44 * @param fileCounter the file counter. 45 */ AbstractPathCounters(final Counter byteCounter, final Counter directoryCounter, final Counter fileCounter)46 protected AbstractPathCounters(final Counter byteCounter, final Counter directoryCounter, final Counter fileCounter) { 47 this.byteCounter = byteCounter; 48 this.directoryCounter = directoryCounter; 49 this.fileCounter = fileCounter; 50 } 51 52 @Override equals(final Object obj)53 public boolean equals(final Object obj) { 54 if (this == obj) { 55 return true; 56 } 57 if (!(obj instanceof AbstractPathCounters)) { 58 return false; 59 } 60 final AbstractPathCounters other = (AbstractPathCounters) obj; 61 return Objects.equals(byteCounter, other.byteCounter) 62 && Objects.equals(directoryCounter, other.directoryCounter) 63 && Objects.equals(fileCounter, other.fileCounter); 64 } 65 66 @Override getByteCounter()67 public Counter getByteCounter() { 68 return byteCounter; 69 } 70 71 @Override getDirectoryCounter()72 public Counter getDirectoryCounter() { 73 return directoryCounter; 74 } 75 76 /** 77 * Gets the count of visited files. 78 * 79 * @return the byte count of visited files. 80 */ 81 @Override getFileCounter()82 public Counter getFileCounter() { 83 return this.fileCounter; 84 } 85 86 @Override hashCode()87 public int hashCode() { 88 return Objects.hash(byteCounter, directoryCounter, fileCounter); 89 } 90 91 @Override reset()92 public void reset() { 93 byteCounter.reset(); 94 directoryCounter.reset(); 95 fileCounter.reset(); 96 } 97 98 @Override toString()99 public String toString() { 100 return String.format("%,d files, %,d directories, %,d bytes", Long.valueOf(fileCounter.get()), 101 Long.valueOf(directoryCounter.get()), Long.valueOf(byteCounter.get())); 102 } 103 104 } 105 106 /** 107 * Counts using a {@link BigInteger} number. 108 */ 109 private static final class BigIntegerCounter implements Counter { 110 111 private BigInteger value = BigInteger.ZERO; 112 113 @Override add(final long val)114 public void add(final long val) { 115 value = value.add(BigInteger.valueOf(val)); 116 117 } 118 119 @Override equals(final Object obj)120 public boolean equals(final Object obj) { 121 if (this == obj) { 122 return true; 123 } 124 if (!(obj instanceof Counter)) { 125 return false; 126 } 127 final Counter other = (Counter) obj; 128 return Objects.equals(value, other.getBigInteger()); 129 } 130 131 @Override get()132 public long get() { 133 return value.longValueExact(); 134 } 135 136 @Override getBigInteger()137 public BigInteger getBigInteger() { 138 return value; 139 } 140 141 @Override getLong()142 public Long getLong() { 143 return Long.valueOf(value.longValueExact()); 144 } 145 146 @Override hashCode()147 public int hashCode() { 148 return Objects.hash(value); 149 } 150 151 @Override increment()152 public void increment() { 153 value = value.add(BigInteger.ONE); 154 } 155 156 @Override reset()157 public void reset() { 158 value = BigInteger.ZERO; 159 } 160 161 @Override toString()162 public String toString() { 163 return value.toString(); 164 } 165 } 166 167 /** 168 * Counts files, directories, and sizes, as a visit proceeds, using BigInteger numbers. 169 */ 170 private final static class BigIntegerPathCounters extends AbstractPathCounters { 171 172 /** 173 * Constructs a new initialized instance. 174 */ BigIntegerPathCounters()175 protected BigIntegerPathCounters() { 176 super(Counters.bigIntegerCounter(), Counters.bigIntegerCounter(), Counters.bigIntegerCounter()); 177 } 178 179 } 180 181 /** 182 * Counts using a number. 183 */ 184 public interface Counter { 185 186 /** 187 * Adds the given number to this counter. 188 * 189 * @param val the value to add. 190 */ add(long val)191 void add(long val); 192 193 /** 194 * Gets the counter as a long. 195 * 196 * @return the counter as a long. 197 */ get()198 long get(); 199 200 /** 201 * Gets the counter as a BigInteger. 202 * 203 * @return the counter as a BigInteger. 204 */ getBigInteger()205 BigInteger getBigInteger(); 206 207 /** 208 * Gets the counter as a Long. 209 * 210 * @return the counter as a Long. 211 */ getLong()212 Long getLong(); 213 214 /** 215 * Adds one to this counter. 216 */ increment()217 void increment(); 218 219 /** 220 * Resets this count to 0. 221 */ reset()222 default void reset() { 223 // binary compat, do nothing 224 } 225 226 } 227 228 /** 229 * Counts using a {@code long} number. 230 */ 231 private final static class LongCounter implements Counter { 232 233 private long value; 234 235 @Override add(final long add)236 public void add(final long add) { 237 value += add; 238 239 } 240 241 @Override equals(final Object obj)242 public boolean equals(final Object obj) { 243 if (this == obj) { 244 return true; 245 } 246 if (!(obj instanceof Counter)) { 247 return false; 248 } 249 final Counter other = (Counter) obj; 250 return value == other.get(); 251 } 252 253 @Override get()254 public long get() { 255 return value; 256 } 257 258 @Override getBigInteger()259 public BigInteger getBigInteger() { 260 return BigInteger.valueOf(value); 261 } 262 263 @Override getLong()264 public Long getLong() { 265 return Long.valueOf(value); 266 } 267 268 @Override hashCode()269 public int hashCode() { 270 return Objects.hash(value); 271 } 272 273 @Override increment()274 public void increment() { 275 value++; 276 } 277 278 @Override reset()279 public void reset() { 280 value = 0L; 281 } 282 283 @Override toString()284 public String toString() { 285 return Long.toString(value); 286 } 287 } 288 289 /** 290 * Counts files, directories, and sizes, as a visit proceeds, using long numbers. 291 */ 292 private final static class LongPathCounters extends AbstractPathCounters { 293 294 /** 295 * Constructs a new initialized instance. 296 */ LongPathCounters()297 protected LongPathCounters() { 298 super(Counters.longCounter(), Counters.longCounter(), Counters.longCounter()); 299 } 300 301 } 302 303 /** 304 * Counts nothing. 305 */ 306 private final static class NoopCounter implements Counter { 307 308 static final NoopCounter INSTANCE = new NoopCounter(); 309 310 @Override add(final long add)311 public void add(final long add) { 312 // noop 313 } 314 315 @Override get()316 public long get() { 317 return 0; 318 } 319 320 @Override getBigInteger()321 public BigInteger getBigInteger() { 322 return BigInteger.ZERO; 323 } 324 325 @Override getLong()326 public Long getLong() { 327 return 0L; 328 } 329 330 @Override increment()331 public void increment() { 332 // noop 333 } 334 335 /** 336 * Returns {@code "0"}, always. 337 * 338 * @return {@code "0"}, always. 339 * @since 2.12.0 340 */ 341 @Override toString()342 public String toString() { 343 return "0"; 344 } 345 346 } 347 348 /** 349 * Counts nothing. 350 */ 351 private static final class NoopPathCounters extends AbstractPathCounters { 352 353 static final NoopPathCounters INSTANCE = new NoopPathCounters(); 354 355 /** 356 * Constructs a new initialized instance. 357 */ NoopPathCounters()358 private NoopPathCounters() { 359 super(Counters.noopCounter(), Counters.noopCounter(), Counters.noopCounter()); 360 } 361 362 } 363 364 /** 365 * Counts files, directories, and sizes, as a visit proceeds. 366 */ 367 public interface PathCounters { 368 369 /** 370 * Gets the byte counter. 371 * 372 * @return the byte counter. 373 */ getByteCounter()374 Counter getByteCounter(); 375 376 /** 377 * Gets the directory counter. 378 * 379 * @return the directory counter. 380 */ getDirectoryCounter()381 Counter getDirectoryCounter(); 382 383 /** 384 * Gets the file counter. 385 * 386 * @return the file counter. 387 */ getFileCounter()388 Counter getFileCounter(); 389 390 /** 391 * Resets the counts to 0. 392 */ reset()393 default void reset() { 394 // binary compat, do nothing 395 } 396 397 } 398 399 /** 400 * Returns a new BigInteger Counter. 401 * 402 * @return a new BigInteger Counter. 403 */ bigIntegerCounter()404 public static Counter bigIntegerCounter() { 405 return new BigIntegerCounter(); 406 } 407 408 /** 409 * Returns a new BigInteger PathCounters. 410 * 411 * @return a new BigInteger PathCounters. 412 */ bigIntegerPathCounters()413 public static PathCounters bigIntegerPathCounters() { 414 return new BigIntegerPathCounters(); 415 } 416 417 /** 418 * Returns a new long Counter. 419 * 420 * @return a new long Counter. 421 */ longCounter()422 public static Counter longCounter() { 423 return new LongCounter(); 424 } 425 426 /** 427 * Returns a new BigInteger PathCounters. 428 * 429 * @return a new BigInteger PathCounters. 430 */ longPathCounters()431 public static PathCounters longPathCounters() { 432 return new LongPathCounters(); 433 } 434 435 /** 436 * Returns the no-op Counter. 437 * 438 * @return the no-op Counter. 439 * @since 2.9.0 440 */ noopCounter()441 public static Counter noopCounter() { 442 return NoopCounter.INSTANCE; 443 } 444 445 /** 446 * Returns the no-op PathCounters. 447 * 448 * @return the no-op PathCounters. 449 * @since 2.9.0 450 */ noopPathCounters()451 public static PathCounters noopPathCounters() { 452 return NoopPathCounters.INSTANCE; 453 } 454 } 455