GCC Code Coverage Report


Directory: ./
File: firmware/controllers/sensors/converters/func_chain.h
Date: 2025-10-03 00:57:22
Coverage Exec Excl Total
Lines: 47.0% 95 0 202
Functions: 65.0% 39 0 60
Branches: 20.5% 9 0 44
Decisions: -% 0 - 0

Line Branch Decision Exec Source
1 /**
2 * @author Matthew Kennedy, (c) 2019
3 *
4 * This lets us compose multiple functions in to a single function. If we have
5 * conversion functions F(x), G(x), and H(x), we can define a new function
6 * FuncChain<F, G, H> that will compute H(G(F(X))). F first, then G, then H.
7 */
8
9 #pragma once
10
11 #include "sensor_converter_func.h"
12
13 #include <type_traits>
14 #include <utility>
15
16 namespace priv {
17 template <class... _Types>
18 class FuncChain;
19
20 template <>
21 class FuncChain<> {
22 protected:
23 9 SensorResult convert(float input) const {
24 // Base case is the identity function
25 9 return input;
26 }
27
28 void showInfo(float testInputValue) const {
29 // base case does nothing
30 (void)testInputValue;
31 }
32 };
33
34 template <typename TFirst, typename... TRest>
35 class FuncChain<TFirst, TRest...> : private FuncChain<TRest...> {
36 static_assert(std::is_base_of_v<SensorConverter, TFirst>, "Template parameters must inherit from SensorConverter");
37
38 private:
39 using TBase = FuncChain<TRest...>;
40
41 public:
42 20 SensorResult convert(float input) const {
43 // Convert the current step
44 20 SensorResult currentStep = m_f.convert(input);
45
46 // if it was valid, pass this result to the chain of (n-1) functions that remain
47
9/22
priv::FuncChain<SubOne>::convert(float) const:
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
priv::FuncChain<Doubler, SubOne>::convert(float) const:
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
priv::FuncChain<Doubler>::convert(float) const:
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
priv::FuncChain<AddOne, Doubler, SubOne>::convert(float) const:
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
priv::FuncChain<AddOne, Doubler>::convert(float) const:
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
priv::FuncChain<AddOne>::convert(float) const:
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
priv::FuncChain<MafFilter>::convert(float) const:
✗ Branch 0 not taken.
✗ Branch 1 not taken.
priv::FuncChain<MafTable, MafFilter>::convert(float) const:
✗ Branch 0 not taken.
✗ Branch 1 not taken.
priv::FuncChain<MafVoltageCheck, MafTable, MafFilter>::convert(float) const:
✗ Branch 0 not taken.
✗ Branch 1 not taken.
priv::FuncChain<ThermistorFunc>::convert(float) const:
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
priv::FuncChain<ResistanceFunc, ThermistorFunc>::convert(float) const:
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
20 if (currentStep.Valid) {
48 18 return TBase::convert(currentStep.Value);
49 } else {
50 2 return SensorResult(currentStep.Code);
51 }
52 }
53
54 // Get the element in the current level
55 template <class TGet>
56 14 std::enable_if_t<std::is_same_v<TGet, TFirst>, TGet &> get() {
57 14 return m_f;
58 }
59
60 template <class TGet>
61 5 std::enable_if_t<std::is_same_v<TGet, TFirst>, TGet *> getPtr() {
62 5 return &m_f;
63 }
64
65 // We don't have it - check level (n - 1)
66 template <class TGet>
67 10 std::enable_if_t<!std::is_same_v<TGet, TFirst>, TGet &> get() {
68 10 return TBase::template get<TGet>();
69 }
70
71 // We don't have it - check level (n - 1)
72 template <class TGet>
73 5 std::enable_if_t<!std::is_same_v<TGet, TFirst>, TGet *> getPtr() {
74 5 return TBase::template getPtr<TGet>();
75 }
76
77 void showInfo(float testInputValue) const {
78 // Print info about this level
79 m_f.showInfo(testInputValue);
80
81 // If valid, recurse down
82 auto res = m_f.convert(testInputValue);
83 if (res.Valid) {
84 TBase::showInfo(res.Value);
85 }
86 }
87
88 private:
89 TFirst m_f;
90 };
91 } // namespace priv
92
93 template <typename... TFuncs>
94 class FuncChain : public SensorConverter {
95 public:
96 // Perform chained conversion of all functions in TFuncs
97 11 SensorResult convert(float input) const override {
98 11 return m_fs.convert(input);
99 }
100
101 // Access the sub-function of type TGet
102 template <typename TGet>
103 14 TGet &get() {
104 14 return m_fs.template get<TGet>();
105 }
106
107 // references would be sometimes implicitly deleted, right? adding parallel pointer API which would stay?
108 template <typename TGet>
109 5 TGet *getPtr() {
110 5 return m_fs.template getPtr<TGet>();
111 }
112
113 void showInfo(float testInputValue) const override {
114 m_fs.showInfo(testInputValue);
115 }
116
117 private:
118 priv::FuncChain<TFuncs...> m_fs;
119 };
120