diff --git a/course02/homework02/danielellis/Buffer.h b/course02/homework02/danielellis/Buffer.h new file mode 100644 index 0000000..c2e5992 --- /dev/null +++ b/course02/homework02/danielellis/Buffer.h @@ -0,0 +1,79 @@ +#pragma once + +#include +#include +#include +#include + +struct WindowConfig +{ + std::chrono::seconds mDuration = std::chrono::seconds(10); + int mMaxNumMessages = 5; +}; + +template +struct TimestampedMessage +{ + std::chrono::time_point mTimestamp; + Message mMessage; +}; + +template +class Buffer +{ +public: + using value_type = Message; + + Buffer(const WindowConfig& conf); + void TryToAddMessage(const Message& message); + std::vector DumpMessages() const; + +private: + bool CanAddMessage(std::chrono::time_point currentTime) const; + + WindowConfig mWindowConfig; + std::deque > mTimestampedMessages; +}; + +template +Buffer::Buffer(const WindowConfig& conf) : + mWindowConfig(conf) +{ + if (conf.mMaxNumMessages <= 0) + throw std::runtime_error("Invalid configuration: max number of messages per time window must be positive!"); +} + +template +bool Buffer::CanAddMessage(std::chrono::time_point currentTime) const +{ + if (mTimestampedMessages.size() >= mWindowConfig.mMaxNumMessages) + { + auto timestampAtStartOfWindow = mTimestampedMessages[ + mTimestampedMessages.size() - mWindowConfig.mMaxNumMessages].mTimestamp; + return (timestampAtStartOfWindow < currentTime - mWindowConfig.mDuration); + } + return true; +} + +template +void Buffer::TryToAddMessage(const Message& message) +{ + auto currentTime = std::chrono::steady_clock::now(); + if (CanAddMessage(currentTime)) + { + TimestampedMessage tsMsg; + tsMsg.mMessage = message; + tsMsg.mTimestamp = currentTime; + mTimestampedMessages.push_back(tsMsg); + } +} + +template +std::vector Buffer::DumpMessages() const +{ + std::vector result; + for (auto tsMsg : mTimestampedMessages) + result.push_back(tsMsg.mMessage); + + return result; +} diff --git a/course02/homework02/danielellis/CMakeLists.txt b/course02/homework02/danielellis/CMakeLists.txt new file mode 100644 index 0000000..5547dd1 --- /dev/null +++ b/course02/homework02/danielellis/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 2.8) + +set(sources + main.cc + SlidingWindow.h + Buffer.h +) + +add_executable(main ${sources}) diff --git a/course02/homework02/danielellis/SlidingWindow.h b/course02/homework02/danielellis/SlidingWindow.h new file mode 100644 index 0000000..cbb78c2 --- /dev/null +++ b/course02/homework02/danielellis/SlidingWindow.h @@ -0,0 +1,51 @@ +#pragma once + +#include +#include +#include +#include + +#include "Buffer.h" + +template +class SlidingWindow +{ +public: + using value_type = Message; + + SlidingWindow(const WindowConfig& conf); + void Send(int clientId, const Message& message); + std::vector DumpMessages(int clientId) const; + +private: + WindowConfig mWindowConfig; + std::map > mClientBuffers; +}; + +template +SlidingWindow::SlidingWindow(const WindowConfig& conf) : + mWindowConfig(conf) +{ + if (conf.mMaxNumMessages <= 0) + throw std::runtime_error("Invalid configuration: max number of messages per time window must be positive!"); +} + +template +void SlidingWindow::Send(int clientId, const Message& message) +{ + if (mClientBuffers.count(clientId) == 0) + mClientBuffers.insert(std::pair >(clientId, Buffer(mWindowConfig))); + + Buffer& buffer = mClientBuffers.at(clientId); + buffer.TryToAddMessage(message); +} + +template +std::vector SlidingWindow::DumpMessages(int clientId) const +{ + auto buffer = mClientBuffers.find(clientId); + if (buffer != mClientBuffers.end()) + return buffer->second.DumpMessages(); + else + return std::vector(); +} diff --git a/course02/homework02/danielellis/main.cc b/course02/homework02/danielellis/main.cc new file mode 100644 index 0000000..5dff452 --- /dev/null +++ b/course02/homework02/danielellis/main.cc @@ -0,0 +1,84 @@ +#include "SlidingWindow.h" +#include "Buffer.h" + +#include + +void TestDroppedLastMessage() +{ + WindowConfig conf; + auto slidingWindow = SlidingWindow(conf); + for (int i = 1; i < 7; ++i) + slidingWindow.Send(1, i); + + auto messageDump = slidingWindow.DumpMessages(1); + assert(messageDump.size() == 5); + int i = 1; + for (auto msg : messageDump) + { + assert(msg == i); + ++i; + } +} + +void TestMultipleClients() +{ + WindowConfig conf; + conf.mMaxNumMessages = 8; + auto slidingWindow = SlidingWindow(conf); + for (int i = 1; i < 7; ++i) + slidingWindow.Send(1, i); + + for (int i = 1; i < 15; ++i) + slidingWindow.Send(2, i); + + auto messageDump = slidingWindow.DumpMessages(1); + assert(messageDump.size() == 6); + int i = 1; + for (auto msg : messageDump) + { + assert(msg == i); + ++i; + } + + messageDump = slidingWindow.DumpMessages(2); + assert(messageDump.size() == 8); + i = 1; + for (auto msg : messageDump) + { + assert(msg == i); + ++i; + } +} + +void TestDumpQuietClient() +{ + WindowConfig conf; + auto slidingWindow = SlidingWindow(conf); + auto dump = slidingWindow.DumpMessages(1); + assert(dump.size() == 0); +} + +void TestNegativeNumMessagesInWindowConf() +{ + WindowConfig conf; + conf.mMaxNumMessages = -5; + bool failed = true; + try + { + auto slidingWindow = SlidingWindow(conf); + } + catch (std::exception e) + { + failed = false; + } + assert(!failed); +} + +int main() +{ + TestDroppedLastMessage(); + TestMultipleClients(); + TestDumpQuietClient(); + TestNegativeNumMessagesInWindowConf(); + return 0; +}