Evo C++ Library v0.5.1
Common Stream/String Interface

String, Stream, and StreamOut have a common formatting interface, but not a common base class.

Still, common code can use these different types via template parameters.

Common Interface

String, Stream, and StreamOut support this common interface:

Additional custom operator<<() support may be defined using global inline functions (see example below).

Formatting via Template Functions

It can be useful to write a single function that can write formatted output to any Stream or String type. Strings are not a stream type but this is possible with a template function.

#include <evo/string.h>
#include <evo/io.h>
using namespace evo;
// This works with all output stream and string types, including: Stream, StreamOut, Stream::Format, String, String::Format
template<class T>
inline void write_nums(T& out) {
// Write line with comma-separated numbers
out << 1 << ',' 2 << ',' << 20 << NL;
}
int main() {
// Write line to stdout: 1,2,20
Console& c = con();
write_nums(c.out);
// Write line to stdout via formatting object, change int formatting to 2-digit hex: 01,02,14
write_nums(Console::Format(c.out) << FmtSetInt(fHEX, 2));
// Write line to a string: 1,2,20
String str;
write_nums(str);
// Write line to string, change int formatting to 2-digit hex: 01,02,14
write_nums(String::Format(c.out) << FmtSetInt(fHEX, 2));
return 0;
}
Direct Buffer Formatting

This shows a template function that writes directly to a String or Stream buffer.

Example:

#include <evo/string.h>
#include <evo/io.h>
using namespace evo;
static Console& c = con();
// This works with all output stream and string types, including: Stream, StreamOut, Stream::Format, String, String::Format
template<class T>
inline bool write_hello(T& out) {
const typename T::Size SIZE = 5;
char* buf = out.write_out().write_direct(SIZE);
if (buf == NULL)
return false; // Error making room
// Write directly to buffer
memcpy(buf, "Hello", SIZE);
out.write_out().write_direct_finish(SIZE);
return true;
}
int main() {
// Write to String, print: Hello
String str;
write_hello(str);
c.out << str << NL;
// Reset String and write to String via a Format object, print: Hello
str.set();
{
String::Format fmt(str);
write_hello(fmt);
c.out << str << NL;
}
// Write to StreamOut, print: Hello
write_hello(c.out);
c.out << NL;
return 0;
}
Direct Buffer Formatting with Larger Data

Writing larger data sizes may require multiple passes with Stream types since they use a fixed size buffer:

#include <evo/string.h>
#include <evo/io.h>
using namespace evo;
static Console& c = con();
// This works with all output stream and string types, including: Stream, StreamOut, Stream::Format, String, String::Format
template<class T>
inline bool write_repeated_char(T& out, char ch, uint count) {
typename T::Out& outstream = out.write_out();
typename T::Out::Size available = 0;
// Make room to write directly to buffer
char* buf = outstream.write_direct_multi(available, count);
if (buf == NULL)
return false; // Stream error
// Write directly to buffer with multiple passes if needed
while (count > 0) {
memset(buf, ch, available);
buf = outstream.write_direct_flush(available, available, count);
if (buf == NULL)
return false; // Stream error
count -= available;
}
return true;
}
int main() {
// Write to String, print 10,000 occurrences of 'a'
String str;
write_repeated_char(str, 'a', 10000);
c.out << str << NL;
// Reset String and write to String via a Format object, print 10,000 occurrences of 'b'
str.set();
{
String::Format fmt(str);
write_repeated_char(fmt, 'b', 10000);
c.out << str << NL;
}
// Write to StreamOut, print 10,000 occurrences of 'c'
write_repeated_char(c.out, 'c', 10000);
c.out << NL;
return 0;
}
Custom Output Operator Overloads

This shows a custom class with a templated format() method that works with all string/stream types and defines a global string/stream output operator that uses the format() method.

#include <evo/string.h>
#include <evo/io.h>
using namespace evo;
// Custom class with a format method that works with all string/stream types
struct CustomClass {
template<class T>
void format(T& out) const {
out << "Hello";
}
};
// String/Stream formatting operator with CustomClass
template<class T>
inline T& operator<<(T& out, const CustomClass& obj) {
obj.format(out);
return out;
}
int main() {
// Create object and format it, print: Hello
CustomClass obj;
con().out << obj << NL;
return 0;
}