#ifndef UTIL_FAKE_OSTREAM_H #define UTIL_FAKE_OSTREAM_H #include "float_to_string.hh" #include "integer_to_string.hh" #include "string_piece.hh" #include #include #include namespace util { /* Like std::ostream but without being incredibly slow. * Supports most of the built-in types except for long double. * * The FakeOStream class is intended to be inherited from. The inherting class * should provide: * public: * Derived &flush(); * Derived &write(const void *data, std::size_t length); * * private: or protected: * friend class FakeOStream; * char *Ensure(std::size_t amount); * void AdvanceTo(char *to); * * The Ensure function makes enough space for an in-place write and returns * where to write. The AdvanceTo function happens after the write, saying how * much was actually written. * * Precondition: * amount <= kToStringMaxBytes for in-place writes. */ template class FakeOStream { public: FakeOStream() {} // This also covers std::string and char* Derived &operator<<(StringPiece str) { return C().write(str.data(), str.size()); } // Handle integers by size and signedness. private: template struct EnableIfKludge { typedef Derived type; }; template ::is_signed, bool IsInteger = std::numeric_limits::is_integer> struct Coerce {}; template struct Coerce { typedef uint16_t To; }; template struct Coerce { typedef uint32_t To; }; template struct Coerce { typedef uint64_t To; }; template struct Coerce { typedef int16_t To; }; template struct Coerce { typedef int32_t To; }; template struct Coerce { typedef int64_t To; }; public: template typename EnableIfKludge::To>::type &operator<<(const From value) { return CallToString(static_cast::To>(value)); } // Character types that get copied as bytes instead of displayed as integers. Derived &operator<<(char val) { return put(val); } Derived &operator<<(signed char val) { return put(static_cast(val)); } Derived &operator<<(unsigned char val) { return put(static_cast(val)); } Derived &operator<<(bool val) { return put(val + '0'); } // enums will fall back to int but are not caught by the template. Derived &operator<<(int val) { return CallToString(static_cast::To>(val)); } Derived &operator<<(float val) { return CallToString(val); } Derived &operator<<(double val) { return CallToString(val); } // This is here to catch all the other pointer types. Derived &operator<<(const void *value) { return CallToString(value); } // This is here because the above line also catches const char*. Derived &operator<<(const char *value) { return *this << StringPiece(value); } Derived &operator<<(char *value) { return *this << StringPiece(value); } Derived &put(char val) { char *c = C().Ensure(1); *c = val; C().AdvanceTo(++c); return C(); } char widen(char val) const { return val; } private: // References to derived class for convenience. Derived &C() { return *static_cast(this); } const Derived &C() const { return *static_cast(this); } // This is separate to prevent an infinite loop if the compiler considers // types the same (i.e. gcc std::size_t and uint64_t or uint32_t). template Derived &CallToString(const T value) { C().AdvanceTo(ToString(value, C().Ensure(ToStringBuf::kBytes))); return C(); } }; } // namespace #endif // UTIL_FAKE_OSTREAM_H