#pragma once
#include "fwd.h"
#include "labeled.h"
#include <util/generic/noncopyable.h>
#include <util/generic/string.h>
#include <util/generic/strbuf.h>
#include <util/generic/typetraits.h>
#include <type_traits>
/**
* @addtogroup Streams_Base
* @{
*/
/**
* Abstract output stream.
*/
class IOutputStream: public TNonCopyable {
public:
/**
* Data block for output.
*/
struct TPart {
inline TPart(const void* Buf, size_t Len) noexcept
: buf(Buf)
, len(Len)
{
}
inline TPart(const TStringBuf s) noexcept
: buf(s.data())
, len(s.size())
{
}
inline TPart() noexcept
: buf(nullptr)
, len(0)
{
}
inline ~TPart() = default;
static inline TPart CrLf() noexcept {
return TPart("\r\n", 2);
}
const void* buf;
size_t len;
};
IOutputStream() noexcept;
virtual ~IOutputStream();
IOutputStream(IOutputStream&&) noexcept {
}
IOutputStream& operator=(IOutputStream&&) noexcept {
return *this;
}
/**
* Writes into this stream.
*
* @param buf Data to write.
* @param len Number of bytes to write.
*/
inline void Write(const void* buf, size_t len) {
if (len) {
DoWrite(buf, len);
}
}
/**
* Writes a string into this stream.
*
* @param st String to write.
*/
inline void Write(const TStringBuf st) {
Write(st.data(), st.size());
}
/**
* Writes several data blocks into this stream.
*
* @param parts Pointer to the start of the data blocks
* array.
* @param count Number of data blocks to write.
*/
inline void Write(const TPart* parts, size_t count) {
if (count > 1) {
DoWriteV(parts, count);
} else if (count) {
DoWrite(parts->buf, parts->len);
}
}
/**
* Writes a single character into this stream.
*
* @param ch Character to write.
*/
inline void Write(char ch) {
DoWriteC(ch);
}
/**
* Flushes this stream's buffer, if any.
*
* Note that this can also be done with a `Flush` manipulator:
* @code
* stream << "some string" << Flush;
* @endcode
*/
inline void Flush() {
DoFlush();
}
/**
* Flushes and closes this stream. No more data can be written into a stream
* once it's closed.
*/
inline void Finish() {
DoFinish();
}
protected:
/**
* Writes into this stream.
*
* @param buf Data to write.
* @param len Number of bytes to write.
* @throws yexception If IO error occurs.
*/
virtual void DoWrite(const void* buf, size_t len) = 0;
/**
* Writes several data blocks into this stream.
*
* @param parts Pointer to the start of the data blocks
* array.
* @param count Number of data blocks to write.
* @throws yexception If IO error occurs.
*/
virtual void DoWriteV(const TPart* parts, size_t count);
/**
* Writes a single character into this stream. Can be overridden with a faster implementation.
*
* @param ch Character to write.
*/
virtual void DoWriteC(char ch);
/**
* Flushes this stream's buffer, if any.
*
* @throws yexception If IO error occurs.
*/
virtual void DoFlush();
/**
* Flushes and closes this stream. No more data can be written into a stream
* once it's closed.
*
* @throws yexception If IO error occurs.
*/
virtual void DoFinish();
};
/**
* `operator<<` for `IOutputStream` by default delegates to this function.
*
* Note that while `operator<<` uses overloading (and thus argument-dependent
* lookup), `Out` uses template specializations. This makes it possible to
* have a single `Out` declaration, and then just provide specializations in
* cpp files, letting the linker figure everything else out. This approach
* reduces compilation times.
*
* However, if the flexibility of overload resolution is needed, then one should
* just overload `operator<<`.
*
* @param out Output stream to write into.
* @param value Value to write.
*/
template <class T>
void Out(IOutputStream& out, typename TTypeTraits<T>::TFuncParam value);
#define Y_DECLARE_OUT_SPEC(MODIF, T, stream, value) \
template <> \
MODIF void Out<T>(IOutputStream & stream, TTypeTraits<T>::TFuncParam value)
template <>
inline void Out<const char*>(IOutputStream& o, const char* t) {
if (t) {
o.Write(t);
} else {
o.Write("(null)");
}
}
template <>
void Out<const wchar16*>(IOutputStream& o, const wchar16* w);
template <>
void Out<const wchar32*>(IOutputStream& o, const wchar32* w);
static inline IOutputStream& operator<<(IOutputStream& o, TStreamManipulator m) {
m(o);
return o;
}
static inline IOutputStream& operator<<(IOutputStream& o, const char* t) {
Out<const char*>(o, t);
return o;
}
static inline IOutputStream& operator<<(IOutputStream& o, char* t) {
Out<const char*>(o, t);
return o;
}
template <class T>
static inline std::enable_if_t<std::is_scalar<T>::value, IOutputStream&> operator<<(IOutputStream& o, T t) {
Out<T>(o, t);
return o;
}
template <class T>
static inline std::enable_if_t<!std::is_scalar<T>::value, IOutputStream&> operator<<(IOutputStream& o, const T& t) {
Out<T>(o, t);
return o;
}
static inline IOutputStream& operator<<(IOutputStream& o, const wchar16* t) {
Out<const wchar16*>(o, t);
return o;
}
static inline IOutputStream& operator<<(IOutputStream& o, wchar16* t) {
Out<const wchar16*>(o, t);
return o;
}
static inline IOutputStream& operator<<(IOutputStream& o, const wchar32* t) {
Out<const wchar32*>(o, t);
return o;
}
static inline IOutputStream& operator<<(IOutputStream& o, wchar32* t) {
Out<const wchar32*>(o, t);
return o;
}
namespace NPrivate {
IOutputStream& StdOutStream() noexcept;
IOutputStream& StdErrStream() noexcept;
}
/**
* Standard output stream.
*/
#define Cout (::NPrivate::StdOutStream())
/**
* Standard error stream.
*/
#define Cerr (::NPrivate::StdErrStream())
/**
* Standard log stream.
*/
#define Clog Cerr
/**
* End-of-line output manipulator, basically the same as `std::endl`.
*/
static inline void Endl(IOutputStream& o) {
(o << '\n').Flush();
}
/**
* Flushing stream manipulator, basically the same as `std::flush`.
*/
static inline void Flush(IOutputStream& o) {
o.Flush();
}
/*
* Also see format.h for additional manipulators.
*/
#include "debug.h"
void RedirectStdioToAndroidLog(bool redirect);
/** @} */