buffered writer - progress on #1463 (#1875)

* add buffered writer

* rename
This commit is contained in:
Matthew Kennedy 2020-10-12 12:10:34 -07:00 committed by GitHub
parent f5cece03e5
commit 605e2590f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 149 additions and 0 deletions

View File

@ -0,0 +1,63 @@
#pragma once
#include <cstring>
struct Writer {
virtual size_t write(const char* buffer, size_t count) = 0;
virtual size_t flush() = 0;
};
template <int TBufferSize>
class BufferedWriter : public Writer {
public:
size_t write(const char* buffer, size_t count) override {
size_t bytesFlushed = 0;
while (count) {
if (m_bytesUsed == 0 && count >= TBufferSize) {
// special case: write-thru, skip the copy
bytesFlushed += writeInternal(buffer, count);
count = 0;
} else if (m_bytesUsed + count < TBufferSize) {
// Write that will fit in the buffer, just copy to intermediate buffer
memcpy(m_buffer + m_bytesUsed, buffer, count);
m_bytesUsed += count;
count = 0;
} else {
// Need to write partial, then flush buffer
size_t bytesToWrite = TBufferSize - m_bytesUsed;
// Copy this block in to place
memcpy(m_buffer + m_bytesUsed, buffer, bytesToWrite);
m_bytesUsed += bytesToWrite;
// Flush to underlying
bytesFlushed += flush();
// Step the read pointer ahead
buffer += bytesToWrite;
// Decrement remaining bytes
count -= bytesToWrite;
}
}
return bytesFlushed;
}
// Flush the internal buffer to the underlying interface.
size_t flush() override {
size_t bytesToWrite = m_bytesUsed;
if (bytesToWrite > 0) {
m_bytesUsed = 0;
return writeInternal(m_buffer, bytesToWrite);
} else {
return 0;
}
}
protected:
virtual size_t writeInternal(const char* buffer, size_t count) = 0;
private:
char m_buffer[TBufferSize];
size_t m_bytesUsed = 0;
};

View File

@ -14,6 +14,7 @@ TESTS_SRC_CPP = \
tests/ignition_injection/test_fuelCut.cpp \
tests/ignition_injection/test_fuel_computer.cpp \
tests/ignition_injection/test_injector_model.cpp \
tests/util/test_buffered_writer.cpp \
tests/test_util.cpp \
tests/test_hardware_reinit.cpp \
tests/test_ion.cpp \

View File

@ -0,0 +1,85 @@
#include "buffered_writer.h"
#include <gtest/gtest.h>
#include <gmock/gmock.h>
using ::testing::_;
using ::testing::Return;
using ::testing::StrictMock;
template <int TBufferSize>
struct MockBufferedWriter : public BufferedWriter<TBufferSize>
{
MOCK_METHOD(size_t, writeInternal, (const char*, size_t), (override));
};
static const char* testBuffer = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
TEST(BufferedWriter, WriteSmall) {
// No calls to dut expected
StrictMock<MockBufferedWriter<10>> dut;
EXPECT_EQ(0, dut.write(testBuffer, 5));
}
TEST(BufferedWriter, WriteSmallFlush) {
StrictMock<MockBufferedWriter<10>> dut;
EXPECT_CALL(dut, writeInternal(_, 5)).WillOnce(Return(5));
ASSERT_EQ(0, dut.write(testBuffer, 5));
EXPECT_EQ(dut.flush(), 5);
}
TEST(BufferedWriter, WriteMultipleSmall) {
StrictMock<MockBufferedWriter<10>> dut;
{
EXPECT_CALL(dut, writeInternal(_, 10)).WillOnce(Return(10));
EXPECT_CALL(dut, writeInternal(_, 2)).WillOnce(Return(2));
}
EXPECT_EQ(0, dut.write(testBuffer, 3));
EXPECT_EQ(0, dut.write(testBuffer, 3));
EXPECT_EQ(0, dut.write(testBuffer, 3));
EXPECT_EQ(10, dut.write(testBuffer, 3)); // <- this one should trigger a flush
// Flush the remainder
EXPECT_EQ(dut.flush(), 2);
}
TEST(BufferedWriter, WriteSingleFullBufferSize) {
StrictMock<MockBufferedWriter<50>> dut;
EXPECT_CALL(dut, writeInternal(_, 50)).WillOnce(Return(50));
EXPECT_EQ(50, dut.write(testBuffer, 50));
// Nothing left to flush!
EXPECT_EQ(0, dut.flush());
}
TEST(BufferedWriter, WriteLarge) {
StrictMock<MockBufferedWriter<10>> dut;
{
EXPECT_CALL(dut, writeInternal(_, 45)).WillOnce(Return(45));
}
EXPECT_EQ(45, dut.write(testBuffer, 45));
EXPECT_EQ(0, dut.flush());
}
TEST(BufferedWriter, WriteLargeAfterSmall) {
StrictMock<MockBufferedWriter<10>> dut;
{
EXPECT_CALL(dut, writeInternal(_, 10)).WillOnce(Return(10));
EXPECT_CALL(dut, writeInternal(_, 36)).WillOnce(Return(36));
}
EXPECT_EQ(0, dut.write(testBuffer, 1));
EXPECT_EQ(46, dut.write(testBuffer, 45));
EXPECT_EQ(0, dut.flush());
}