blob: bd817704bc32b9f94743da50ecb76da9f90a34f5 [file] [log] [blame]
// SPDX-License-Identifier: Apache-2.0
// Copyright Network Geographics 2014
/** @file
Errata implementation.
*/
#include <iostream>
#include <sstream>
#include <algorithm>
#include <memory.h>
#include "swoc/Errata.h"
#include "swoc/bwf_ex.h"
using swoc::MemArena;
using std::string_view;
using namespace std::literals;
using namespace swoc::literals;
namespace swoc { inline namespace SWOC_VERSION_NS {
/** List of sinks for abandoned erratum.
*/
namespace {
std::vector<Errata::Sink::Handle> Sink_List;
}
std::string_view const Errata::DEFAULT_GLUE{"\n", 1};
/** This is the implementation class for Errata.
It holds the actual messages and is treated as a passive data object with nice constructors.
*/
string_view
Errata::Data::localize(string_view src) {
auto span = _arena.alloc(src.size());
memcpy(span.data(), src.data(), src.size());
return span.view();
}
/* ----------------------------------------------------------------------- */
// methods for Errata
Errata::~Errata() {
this->release();
}
void
Errata::release() {
if (_data) {
if (--(_data->_ref_count) == 0) {
if (!_data->empty()) {
for (auto& f : Sink_List) {
(*f)(*this);
}
}
_data->~Data();
}
_data = nullptr;
}
}
const Errata::Data *
Errata::data() {
if (!_data) {
MemArena arena{512};
_data = arena.make<Data>(std::move(arena));
++(_data->_ref_count);
}
return _data;
}
Errata::Data *
Errata::writeable_data() {
if (!_data) {
this->data(); // force data existence, must be unique.
} else if (_data->_ref_count > 1) {
// Pondering this, there's really no good use case for shared write access to an Errata.
// The shared_ptr is used only to make function returns efficient. Explicit copying is
// easy using @c note.
throw std::runtime_error("Shared write to Errata");
};
return _data;
}
Errata::iterator
Errata::begin() {
return _data ? _data->_notes.begin() : iterator();
}
Errata::const_iterator
Errata::begin() const {
return _data ? _data->_notes.begin() : const_iterator();
}
Errata::iterator
Errata::end() {
return _data ? _data->_notes.end() : iterator();
}
Errata::const_iterator
Errata::end() const {
return _data ? _data->_notes.end() : const_iterator();
}
Severity
Errata::severity() const {
return _data ? _data->_severity : DEFAULT_SEVERITY;
}
Errata&
Errata::note(Severity severity, std::string_view text) {
auto d = this->writeable_data();
Annotation *n = d->_arena.make<Annotation>(severity, d->localize(text));
d->_notes.prepend(n);
_data->_severity = std::max(_data->_severity, severity);
return *this;
}
Errata&
Errata::note_localized(Severity severity, std::string_view const& text) {
auto d = this->writeable_data();
Annotation *n = d->_arena.make<Annotation>(severity, text);
n->_level = d->_level;
d->_notes.prepend(n);
_data->_severity = std::max(_data->_severity, severity);
return *this;
}
MemSpan<char>
Errata::alloc(size_t n) {
return this->writeable_data()->_arena.alloc(n).rebind<char>();
}
Errata&
Errata::note(const self_type& that) {
for (auto const& m : that) {
this->note(m._severity, m._text);
}
return *this;
}
Errata&
Errata::clear() {
if (_data) {
_data->_notes.clear(); // Prevent sink processing.
this->release();
}
return *this;
}
void
Errata::register_sink(Sink::Handle const& s) {
Sink_List.push_back(s);
}
std::ostream&
Errata::write(std::ostream& out) const {
string_view lead;
for (auto& m : *this) {
out << lead << " [" << static_cast<int>(m._severity) << "]: " << m._text << std::endl;
if (0 == lead.size()) {
lead = " "_sv;
}
}
return out;
}
BufferWriter&
bwformat(BufferWriter& bw, bwf::Spec const& spec, Errata::Severity level) {
static constexpr std::string_view name[9] = {"DIAG", "DEBUG", "INFO", "NOTE", "WARNING", "ERROR"
, "FATAL", "ALERT", "EMERGENCY"};
return bwformat(bw, spec, name[static_cast<int>(level)]);
}
BufferWriter&
bwformat(BufferWriter& bw, bwf::Spec const&, Errata const& errata) {
for (auto& m : errata) {
bw.print("{}[{}] {}\n", swoc::bwf::Pattern{int(m.level()), " "}, m.severity(), m.text());
}
return bw;
}
std::ostream&
operator<<(std::ostream& os, Errata const& err) {
return err.write(os);
}
}} // namespace swoc