add expected helper class (#1321)

Co-authored-by: Matthew Kennedy <makenne@microsoft.com>
This commit is contained in:
Matthew Kennedy 2020-04-18 22:53:04 -07:00 committed by GitHub
parent c5a0da2db7
commit 7f60384c75
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 59 additions and 28 deletions

View File

@ -22,7 +22,7 @@ class FuncChain<> {
protected: protected:
SensorResult convert(float input) const { SensorResult convert(float input) const {
// Base case is the identity function // Base case is the identity function
return {true, input}; return input;
} }
void showInfo(Logging* logger, float testInputValue) const { void showInfo(Logging* logger, float testInputValue) const {
@ -48,7 +48,7 @@ public:
if (currentStep.Valid) { if (currentStep.Valid) {
return TBase::convert(currentStep.Value); return TBase::convert(currentStep.Value);
} else { } else {
return {false, 0}; return unexpected;
} }
} }

View File

@ -13,18 +13,18 @@ void ResistanceFunc::configure(float supplyVoltage, float pullupResistor) {
SensorResult ResistanceFunc::convert(float raw) const { SensorResult ResistanceFunc::convert(float raw) const {
// If the voltage is very low, the sensor is a dead short. // If the voltage is very low, the sensor is a dead short.
if (raw < 0.05f) { if (raw < 0.05f) {
return {false, 0.0f}; return unexpected;
} }
// If the voltage is very high (98% VCC), the sensor is open circuit. // If the voltage is very high (98% VCC), the sensor is open circuit.
if (raw > (m_supplyVoltage * 0.98f)) { if (raw > (m_supplyVoltage * 0.98f)) {
return {false, 1e6}; return unexpected;
} }
// Voltage is in a sensible range - convert // Voltage is in a sensible range - convert
float resistance = m_pullupResistor / (m_supplyVoltage / raw - 1); float resistance = m_pullupResistor / (m_supplyVoltage / raw - 1);
return {true, resistance}; return resistance;
} }
void ResistanceFunc::showInfo(Logging* logger, float testInputValue) const { void ResistanceFunc::showInfo(Logging* logger, float testInputValue) const {

View File

@ -13,7 +13,7 @@ SensorResult ThermistorFunc::convert(float ohms) const {
// This resistance should have already been validated - only // This resistance should have already been validated - only
// thing we can check is that it's non-negative // thing we can check is that it's non-negative
if (ohms <= 0) { if (ohms <= 0) {
return {false, 0}; return unexpected;
} }
float lnR = logf(ohms); float lnR = logf(ohms);
@ -26,7 +26,7 @@ SensorResult ThermistorFunc::convert(float ohms) const {
float celsius = convertKelvinToCelcius(kelvin); float celsius = convertKelvinToCelcius(kelvin);
return {true, celsius}; return celsius;
} }
void ThermistorFunc::configure(thermistor_conf_s &cfg) { void ThermistorFunc::configure(thermistor_conf_s &cfg) {

View File

@ -92,7 +92,7 @@ bool Sensor::Register() {
// Next check for mock // Next check for mock
if (entry->useMock) { if (entry->useMock) {
return {true, entry->mockValue}; return entry->mockValue;
} }
// Get the sensor out of the entry // Get the sensor out of the entry
@ -103,7 +103,7 @@ bool Sensor::Register() {
} }
// We've exhausted all valid ways to return something - sensor not found. // We've exhausted all valid ways to return something - sensor not found.
return {false, 0}; return unexpected;
} }
/*static*/ float Sensor::getRaw(SensorType type) { /*static*/ float Sensor::getRaw(SensorType type) {

View File

@ -48,23 +48,11 @@
#pragma once #pragma once
#include "sensor_type.h" #include "sensor_type.h"
#include "expected.h"
#include <cstddef> #include <cstddef>
struct SensorResult { using SensorResult = expected<float>;
const bool Valid;
const float Value;
// Implicit conversion operator to bool, so you can do things like if (myResult) { ... }
constexpr explicit operator bool() const {
return Valid;
}
// Easy default value handling
constexpr float value_or(float valueIfInvalid) const {
return Valid ? Value : valueIfInvalid;
}
};
// Fwd declare - nobody outside of Sensor.cpp needs to see inside this type // Fwd declare - nobody outside of Sensor.cpp needs to see inside this type
struct SensorRegistryEntry; struct SensorRegistryEntry;
@ -156,7 +144,7 @@ private:
return 0; return 0;
} }
SensorType m_type; const SensorType m_type;
// Get this sensor's index in the list // Get this sensor's index in the list
constexpr size_t getIndex() { constexpr size_t getIndex() {

View File

@ -41,7 +41,7 @@ public:
return {false, value}; return {false, value};
} }
return {true, value}; return value;
} }
protected: protected:

43
firmware/util/expected.h Normal file
View File

@ -0,0 +1,43 @@
/**
* @file expected.h
* @brief This utility class provides a way for a function to accept or return a value that may be invalid.
*
* For example, suppose there needs to be a solution for prevention of divide by zero. One could write this function:
*
* expected<int> my_divide(int num, int denom) {
* if (denom == 0) return unexpected;
* return num / denom;
* }
*
* @date April 18, 2020
* @author Matthew Kennedy, (c) 2020
*/
#pragma once
template <class TValue>
struct expected {
const bool Valid;
const TValue Value;
constexpr expected(bool valid, TValue value) : Valid(valid), Value(value) {}
// Implicit constructor to convert from TValue (for valid values, so an expected<T> behaves like a T)
constexpr expected(TValue validValue)
: Valid(true)
, Value(validValue)
{
}
// Implicit conversion operator to bool, so you can do things like if (myResult) { ... }
constexpr explicit operator bool() const {
return Valid;
}
// Easy default value handling
constexpr float value_or(TValue valueIfInvalid) const {
return Valid ? Value : valueIfInvalid;
}
};
constexpr expected<float> unexpected = {false, 0.0f};

View File

@ -4,19 +4,19 @@
struct AddOne final : public SensorConverter { struct AddOne final : public SensorConverter {
SensorResult convert(float input) const { SensorResult convert(float input) const {
return {true, input + 1}; return input + 1;
} }
}; };
struct SubOne final : public SensorConverter { struct SubOne final : public SensorConverter {
SensorResult convert(float input) const { SensorResult convert(float input) const {
return {true, input - 1}; return input - 1;
} }
}; };
struct Doubler final : public SensorConverter { struct Doubler final : public SensorConverter {
SensorResult convert(float input) const { SensorResult convert(float input) const {
return {true, input * 2}; return input * 2;
} }
}; };