/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: RingBuffer.cpp Date: 2022-1-24 Author: Reece ***/ #include #include "RingBuffer.hpp" namespace Aurora::Logging::Sinks { RingBufferSink::RingBufferSink(AuUInt32 count) : maxCount_(count) { } bool RingBufferSink::Init() { this->logMutex_ = AuThreadPrimitives::MutexUnique(); this->logBuffer_.reserve(maxCount_); return static_cast(this->logMutex_); } void RingBufferSink::OnMessageBlocking(AuUInt8 level, const ConsoleMessage &msg) {} bool RingBufferSink::OnMessageNonblocking(AuUInt8 level, const ConsoleMessage &msg) { bool drop {}; TryAddMsg(level, msg, drop); return false; } bool RingBufferSink::TryAddMsg(AuUInt8 level, const ConsoleMessage &msg, bool &drop) { AU_LOCK_GUARD(this->logMutex_); try { auto nextIndex = this->index_++; if (this->logBuffer_.size() < this->maxCount_) { if (nextIndex >= this->logBuffer_.size()) { return AuTryInsert(this->logBuffer_, msg); } } this->logBuffer_[nextIndex % this->logBuffer_.size()] = msg; } catch (...) { return false; } return true; } void RingBufferSink::SaveToPath(const AuString &path, bool binary) { auto file = AuIOFS::OpenWriteUnique(path); if (!file) { return; } for (const auto &message : Export()) { if (binary) { AuByteBuffer buffer; message.Write(buffer); file->Write(AuMemoryViewRead(buffer)); } else { file->Write(message.ToPersistentString()); file->Write(AuLocale::NewLine()); } } } AuList RingBufferSink::Export() { AU_LOCK_GUARD(this->logMutex_); AuList messages; auto nextIndex = this->index_; if (nextIndex >= this->logBuffer_.size()) { auto nextIndex = (this->index_ + 1) % this->logBuffer_.size(); for (AU_ITERATE_N_TO_X(i, nextIndex, this->logBuffer_.size())) { messages.push_back(this->logBuffer_[i]); } for (AU_ITERATE_N_TO_X(i, 0, nextIndex)) { messages.push_back(this->logBuffer_[i]); } } else { for (AU_ITERATE_N_TO_X(i, 0, this->logBuffer_.size())) { messages.push_back(this->logBuffer_[i]); } } return messages; } void RingBufferSink::OnFlush() { } IBasicSinkRB *NewRingBufferNew(AuUInt32 maxLogEntries) { try { auto logger = _new RingBufferSink(maxLogEntries); if (!logger) { return nullptr; } if (!logger->Init()) { return nullptr; } return logger; } catch (...) { return {}; } } void NewRingBufferRelease(IBasicSink *logger) { AuSafeDelete(logger); } }