Skip to content

Commit

Permalink
[basicprofiles] optimise calculate and method order
Browse files Browse the repository at this point in the history
Signed-off-by: Andrew Fiddian-Green <software@whitebear.ch>
  • Loading branch information
andrewfg committed Jan 25, 2025
1 parent 065a280 commit 1cb58bd
Showing 1 changed file with 82 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -146,72 +146,6 @@ public StateFilterProfile(ProfileCallback callback, ProfileContext context, Item
configMismatchState = parseState(config.mismatchState, context.getAcceptedDataTypes());
}

/**
* Initialize the reference zero based system unit of the linked item. If there is no linked item, or it is not a
* {@link NumberItem} or if the item does not have a unit, then the systemUnit is null.
*
* @return the systemUnit or null
*/
protected @Nullable Unit<?> initSystemUnit() {
if (systemUnitInitialized) {
return systemUnit;
}
Unit<?> systemUnit = (getLinkedItem() instanceof NumberItem numberItem)
&& (numberItem.getUnit() instanceof Unit<?> numberItemUnit) ? numberItemUnit.getSystemUnit() : null;
this.systemUnit = systemUnit;
systemUnitInitialized = true;
return systemUnit;
}

/**
* Return true if 'systemUnit' is defined.
*/
protected boolean hasSystemUnit() {
return initSystemUnit() != null;
}

/**
* Convert a {@link State} to a {@link QuantityType} with its value converted to the 'systemUnit'.
* Returns null if the state is not a {@link QuantityType} or it does not convert to 'systemUnit'.
*
* The conversion can be made to both inverted and non-inverted units, so invertible type conversions
* (e.g. Mirek <=> Kelvin) are supported.
*
* @return a {@link QuantityType} based on 'systemUnit'
*/
protected @Nullable QuantityType<?> systemUnitQuantityType(State state) {
return (state instanceof QuantityType<?> quantity) && hasSystemUnit()
? quantity.toInvertibleUnit(Objects.requireNonNull(systemUnit))
: null;
}

/**
* Convert a list of {@link State} to a list of {@link QuantityType} converted to 'systemUnit'. Exclude any
* {@link State} that are not a {@link QuantityType}. Convert any remaining {@link QuantityType} to the 'systemUnit'
* and exclude any values that did not convert.
*
* @param states list of {@link State} values
* @return list of {@link QuantityType} values
*/
@SuppressWarnings("rawtypes")
protected List<QuantityType> systemUnitQuantityTypes(List<State> states) {
return !hasSystemUnit() ? List.of()
: states.stream().map(s -> systemUnitQuantityType(s)).filter(Objects::nonNull)
.map(s -> (QuantityType) s).toList();
}

/**
* Check if the given {@link State} is allowed. Non allowed means that there is a 'systemUnit', the {@link State}
* is a {@link QuantityType}, and the value is not compatible with 'systemUnit'.
*
* @param state the incoming state
* @return true if allowed
*/
protected boolean isStateAllowed(State state) {
return !(state instanceof QuantityType<?>) || !hasSystemUnit()
|| Objects.nonNull(systemUnitQuantityType(state));
}

private List<StateCondition> parseConditions(List<String> conditions, String separator) {
List<StateCondition> parsedConditions = new ArrayList<>();

Expand Down Expand Up @@ -621,20 +555,25 @@ public FunctionType(Function type, Optional<Integer> windowSize) {

public @Nullable State calculate() {
logger.debug("Calculating function: {}", this);
List<State> states = hasSystemUnit()
? systemUnitQuantityTypes(previousStates).stream().map(q -> (State) q).toList()
: previousStates;
int size = states.size();
int start = windowSize.map(w -> size - w).orElse(0);
states = start <= 0 ? states : states.subList(start, size);
return switch (type) {
case DELTA -> calculateDelta();
case DELTA_PERCENT -> calculateDeltaPercent();
case AVG, AVERAGE -> calculateAverage(states);
case MEDIAN -> calculateMedian(states);
case STDDEV -> calculateStdDev(states);
case MIN -> calculateMin(states);
case MAX -> calculateMax(states);
default -> {
List<State> states = hasSystemUnit()
? systemUnitQuantityTypes(previousStates).stream().map(q -> (State) q).toList()
: previousStates;
int size = states.size();
int start = windowSize.map(w -> size - w).orElse(0);
states = start <= 0 ? states : states.subList(start, size);
yield switch (type) {
case AVG, AVERAGE -> calculateAverage(states);
case MEDIAN -> calculateMedian(states);
case STDDEV -> calculateStdDev(states);
case MIN -> calculateMin(states);
case MAX -> calculateMax(states);
default -> null;
};
}
};
}

Expand Down Expand Up @@ -808,4 +747,70 @@ public String toString() {
return new DecimalType(percent);
}
}

/**
* Initialize the reference zero based system unit of the linked item. If there is no linked item, or it is not a
* {@link NumberItem} or if the item does not have a unit, then the systemUnit is null.
*
* @return the systemUnit or null
*/
protected @Nullable Unit<?> initSystemUnit() {
if (systemUnitInitialized) {
return systemUnit;
}
Unit<?> systemUnit = (getLinkedItem() instanceof NumberItem numberItem)
&& (numberItem.getUnit() instanceof Unit<?> numberItemUnit) ? numberItemUnit.getSystemUnit() : null;
this.systemUnit = systemUnit;
systemUnitInitialized = true;
return systemUnit;
}

/**
* Return true if 'systemUnit' is defined.
*/
protected boolean hasSystemUnit() {
return initSystemUnit() != null;
}

/**
* Convert a {@link State} to a {@link QuantityType} with its value converted to the 'systemUnit'.
* Returns null if the state is not a {@link QuantityType} or it does not convert to 'systemUnit'.
*
* The conversion can be made to both inverted and non-inverted units, so invertible type conversions
* (e.g. Mirek <=> Kelvin) are supported.
*
* @return a {@link QuantityType} based on 'systemUnit'
*/
protected @Nullable QuantityType<?> systemUnitQuantityType(State state) {
return (state instanceof QuantityType<?> quantity) && hasSystemUnit()
? quantity.toInvertibleUnit(Objects.requireNonNull(systemUnit))
: null;
}

/**
* Convert a list of {@link State} to a list of {@link QuantityType} converted to 'systemUnit'. Exclude any
* {@link State} that are not a {@link QuantityType}. Convert any remaining {@link QuantityType} to the 'systemUnit'
* and exclude any values that did not convert.
*
* @param states list of {@link State} values
* @return list of {@link QuantityType} values
*/
@SuppressWarnings("rawtypes")
protected List<QuantityType> systemUnitQuantityTypes(List<State> states) {
return !hasSystemUnit() ? List.of()
: states.stream().map(s -> systemUnitQuantityType(s)).filter(Objects::nonNull)
.map(s -> (QuantityType) s).toList();
}

/**
* Check if the given {@link State} is allowed. Non allowed means that there is a 'systemUnit', the {@link State}
* is a {@link QuantityType}, and the value is not compatible with 'systemUnit'.
*
* @param state the incoming state
* @return true if allowed
*/
protected boolean isStateAllowed(State state) {
return !(state instanceof QuantityType<?>) || !hasSystemUnit()
|| Objects.nonNull(systemUnitQuantityType(state));
}
}

0 comments on commit 1cb58bd

Please sign in to comment.