Add std::array-based ErrorCounter
Essentially the same interface as the existing error counter, but
doesn't require that you keep a flatbuffer around to back the memory.
Change-Id: I52338016f749395ad7d2d9b2443e3e6b30aee9b8
Signed-off-by: James Kuszmaul <jabukuszmaul+collab@gmail.com>
diff --git a/aos/util/error_counter.h b/aos/util/error_counter.h
index cf6cb7f..9fbe242 100644
--- a/aos/util/error_counter.h
+++ b/aos/util/error_counter.h
@@ -67,5 +67,40 @@
private:
flatbuffers::Vector<flatbuffers::Offset<Count>> *vector_ = nullptr;
};
+
+// The ArrayErrorCounter serves the same purpose as the ErrorCounter class,
+// except that:
+// (a) It owns its own memory, rather than modifying a flatbuffer in-place.
+// (b) Because of this, the user has greater flexibility in choosing when to
+// reset the error counters.
+template <typename Error, typename Count>
+class ArrayErrorCounter {
+ public:
+ static constexpr size_t kNumErrors = ErrorCounter<Error, Count>::kNumErrors;
+ ArrayErrorCounter() { ResetCounts(); }
+
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Count>>>
+ PopulateCounts(flatbuffers::FlatBufferBuilder *fbb) {
+ const flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Count>>>
+ offset = ErrorCounter<Error, Count>::Initialize(fbb);
+ flatbuffers::Vector<flatbuffers::Offset<Count>> *vector =
+ flatbuffers::GetMutableTemporaryPointer(*fbb, offset);
+ for (size_t ii = 0; ii < kNumErrors; ++ii) {
+ vector->GetMutableObject(ii)->mutate_count(error_counts_.at(ii));
+ }
+ return offset;
+ }
+
+ void IncrementError(Error error) {
+ DCHECK_LT(static_cast<size_t>(error), error_counts_.size());
+ error_counts_.at(static_cast<size_t>(error))++;
+ }
+
+ // Sets all the error counts to zero.
+ void ResetCounts() { error_counts_.fill(0); }
+
+ private:
+ std::array<size_t, kNumErrors> error_counts_;
+};
} // namespace aos::util
#endif // AOS_UTIL_ERROR_COUNTER_H_
diff --git a/aos/util/error_counter_test.cc b/aos/util/error_counter_test.cc
index 2166cea..567d71d 100644
--- a/aos/util/error_counter_test.cc
+++ b/aos/util/error_counter_test.cc
@@ -34,4 +34,45 @@
EXPECT_EQ(0u, message.message().error_counts()->Get(0)->count());
EXPECT_EQ(0u, message.message().error_counts()->Get(1)->count());
}
+
+// Tests the ArrayErrorCounter
+TEST(ErrorCounterTest, ARrayErrorCounter) {
+ ArrayErrorCounter<aos::timing::SendError, aos::timing::SendErrorCount>
+ counter;
+ flatbuffers::FlatBufferBuilder fbb;
+ fbb.ForceDefaults(true);
+ counter.IncrementError(aos::timing::SendError::MESSAGE_SENT_TOO_FAST);
+ counter.IncrementError(aos::timing::SendError::MESSAGE_SENT_TOO_FAST);
+ counter.IncrementError(aos::timing::SendError::INVALID_REDZONE);
+ {
+ const flatbuffers::Offset<
+ flatbuffers::Vector<flatbuffers::Offset<aos::timing::SendErrorCount>>>
+ counts_offset = counter.PopulateCounts(&fbb);
+ aos::timing::Sender::Builder builder(fbb);
+ builder.add_error_counts(counts_offset);
+ fbb.Finish(builder.Finish());
+ aos::FlatbufferDetachedBuffer<aos::timing::Sender> message = fbb.Release();
+ ASSERT_EQ(2u, message.message().error_counts()->size());
+ EXPECT_EQ(aos::timing::SendError::MESSAGE_SENT_TOO_FAST,
+ message.message().error_counts()->Get(0)->error());
+ EXPECT_EQ(2u, message.message().error_counts()->Get(0)->count());
+ EXPECT_EQ(aos::timing::SendError::INVALID_REDZONE,
+ message.message().error_counts()->Get(1)->error());
+ EXPECT_EQ(1u, message.message().error_counts()->Get(1)->count());
+ }
+
+ counter.ResetCounts();
+ {
+ const flatbuffers::Offset<
+ flatbuffers::Vector<flatbuffers::Offset<aos::timing::SendErrorCount>>>
+ counts_offset = counter.PopulateCounts(&fbb);
+ aos::timing::Sender::Builder builder(fbb);
+ builder.add_error_counts(counts_offset);
+ fbb.Finish(builder.Finish());
+ aos::FlatbufferDetachedBuffer<aos::timing::Sender> message = fbb.Release();
+ ASSERT_EQ(2u, message.message().error_counts()->size());
+ EXPECT_EQ(0u, message.message().error_counts()->Get(0)->count());
+ EXPECT_EQ(0u, message.message().error_counts()->Get(1)->count());
+ }
+}
} // namespace aos::util::testing