/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.core.monitoring.system.internal;
import de.rcenvironment.core.monitoring.system.api.model.AverageOfDoubles;
/**
* Implements a ring buffer of native double elements. No object wrapping is performed around the elements (as opposed to Commons
* Collections CircularFifoBuffer, for example). This makes it CPU cache friendly, which keeps it suitable for constant background logging
* and fairly high element counts.
*
* @author Robert Mischke
*/
public final class RingBufferOfDouble {
private final double[] elements;
private final int capacity; // redundant to elements.length, but better for clarity
private int nextInsertPos;
private int currentElementCount;
public RingBufferOfDouble(int capacity) {
this.capacity = capacity;
this.elements = new double[capacity];
}
/**
* Inserts the next element, evicting the oldest element if the buffer is already at capacity.
*
* @param element the new element
*/
public void add(double element) {
elements[nextInsertPos] = element;
nextInsertPos = (nextInsertPos + 1) % capacity;
currentElementCount = Math.min(currentElementCount + 1, capacity);
}
/**
* Returns the average value of a certain number of the most recent elements, together with information about how many elements were
* actually included in the average. If that count is zero (because no elements have been recorded yet), the average should be
* considered undefined; as a convention, it is set to 0.0.
*
* @param maxElements the maximum number of elements to include
* @return a holder of the average and the number of elements
*/
public AverageOfDoubles getAverageOfLatest(final int maxElements) {
final int numElementsToInclude = Math.min(maxElements, currentElementCount);
if (numElementsToInclude == 0) {
return new AverageOfDoubles(); // placeholder constructor
}
double sum = 0.0;
for (int i = 0, pos = (nextInsertPos - numElementsToInclude + capacity) % capacity; i < numElementsToInclude; i++, pos =
(pos + 1) % capacity) {
sum += elements[pos];
}
return new AverageOfDoubles(numElementsToInclude, sum / numElementsToInclude);
}
}