Toponaming/Base: Add ASCII stream output class (#13209)

* Toponaming/Base: Add ASCII stream output class

* Remove the ref from std::string

* Update based on review comments
This commit is contained in:
Chris Hennes
2024-04-15 10:58:11 -05:00
committed by GitHub
parent 4b968a607d
commit 0056038ff4
3 changed files with 219 additions and 0 deletions

View File

@@ -256,6 +256,97 @@ private:
std::ostringstream _ss;
};
/**
* The TextOutputStream class provides writing of ASCII data to an ostream, with custom handling
* for std::string to make it easier to write a single multi-line (or multi-word) string. This is
* designed for easy compatibility with the LinkStage3 implementation of the OutputStream class,
* used to store StringHashers for the toponaming mitigation technique.
*/
class BaseExport TextOutputStream: public Stream
{
public:
/** Constructor
* @param rout: upstream output
*/
explicit TextOutputStream(std::ostream& rout)
: _out(rout)
{}
TextOutputStream(const TextOutputStream&) = delete;
TextOutputStream(const TextOutputStream&&) noexcept = delete;
void operator=(const TextOutputStream&) = delete;
void operator=(const TextOutputStream&&) = delete;
~TextOutputStream() override = default;
template<typename T>
TextOutputStream& operator<<(T object)
{
_out << object << '\n';
return *this;
}
TextOutputStream& operator<<(const char* object)
{
std::string_view str(object);
// Count the lines so that we can deal with potential EOL conversions by external software
uint32_t lineCount = 0;
for (const auto character : str) {
if (character == '\n') {
++lineCount;
}
}
// Stores the line count followed by a colon as the delimiter. We don't use
// whitespace because the input stream may also start with whitespace.
_out << lineCount << ':';
// Store the text, and normalize the end of line to a single '\n'.
bool foundSlashR = false;
for (const auto character : str) {
if (character == '\r') {
foundSlashR = true;
continue;
}
if (foundSlashR) {
if (character != '\n') {
// We allow '\r' if it is not at the end of a line
_out.put('\r');
}
foundSlashR = false; // Reset for next time
}
_out.put(character);
}
// Add an extra newline as the delimiter for the following data.
_out.put('\n');
return *this;
}
TextOutputStream& operator<<(const std::string& object)
{
return (*this) << object.c_str();
}
TextOutputStream& operator<<(char object)
{
_out.put(object);
return *this;
}
explicit operator bool() const
{
// test if _Ipfx succeeded
return !_out.eof();
}
private:
std::ostream& _out;
};
// ----------------------------------------------------------------------------
/**