#ifndef MUDUO_BASE_LOGSTREAM_H
#define MUDUO_BASE_LOGSTREAM_H
#include <muduo/base/StringPiece.h>
#include <muduo/base/Types.h>
#include <assert.h>
#include <string.h> // memcpy
#ifndef MUDUO_STD_STRING
#include <string>
#endif
namespace muduo
{
namespace detail
{
const int kSmallBuffer = 4000;
const int kLargeBuffer = 4000*1000;
template<int SIZE>
class FixedBuffer : noncopyable//logstream的缓冲区类型
{
public:
FixedBuffer()
: cur_(data_)
{
setCookie(cookieStart);//wow!看不懂,是指buffer的外边缘吗?
}
~FixedBuffer()
{
setCookie(cookieEnd);
}
void append(const char* /*restrict*/ buf, size_t len)
{
// FIXME: append partially
if (implicit_cast<size_t>(avail()) > len)
{
memcpy(cur_, buf, len);
cur_ += len;
}
}
const char* data() const { return data_; }//返回缓冲区指针
int length() const { return static_cast<int>(cur_ - data_); }//已使用的缓冲区大小
// write to data_ directly
char* current() { return cur_; }
int avail() const { return static_cast<int>(end() - cur_); }//可用大小
void add(size_t len) { cur_ += len; }
void reset() { cur_ = data_; }
void bzero() { ::bzero(data_, sizeof data_); }
// for used by GDB
const char* debugString();
void setCookie(void (*cookie)()) { cookie_ = cookie; }
// for used by unit test
string toString() const { return string(data_, length()); }
StringPiece toStringPiece() const { return StringPiece(data_, length()); }
private:
const char* end() const { return data_ + sizeof data_; }
// Must be outline function for cookies.
static void cookieStart();
static void cookieEnd();
void (*cookie_)();
char data_[SIZE];
char* cur_;//缓冲区指针
};
}
class LogStream : noncopyable//以字符串格式写到流
{
typedef LogStream self;
public:
typedef detail::FixedBuffer<detail::kSmallBuffer> Buffer;
self& operator<<(bool v)
{
buffer_.append(v ? "1" : "0", 1);
return *this;
}
self& operator<<(short);
self& operator<<(unsigned short);
self& operator<<(int);
self& operator<<(unsigned int);
self& operator<<(long);
self& operator<<(unsigned long);
self& operator<<(long long);
self& operator<<(unsigned long long);
self& operator<<(const void*);
self& operator<<(float v)
{
*this << static_cast<double>(v);
return *this;
}
self& operator<<(double);
// self& operator<<(long double);
self& operator<<(char v)
{
buffer_.append(&v, 1);
return *this;
}
// self& operator<<(signed char);
// self& operator<<(unsigned char);
self& operator<<(const char* str)
{
if (str)
{
buffer_.append(str, strlen(str));
}
else
{
buffer_.append("(null)", 6);//?
}
return *this;
}
self& operator<<(const unsigned char* str)
{
return operator<<(reinterpret_cast<const char*>(str));
}
self& operator<<(const string& v)
{
buffer_.append(v.c_str(), v.size());
return *this;
}
#ifndef MUDUO_STD_STRING
self& operator<<(const std::string& v)
{
buffer_.append(v.c_str(), v.size());
return *this;
}
#endif
self& operator<<(const StringPiece& v)
{
buffer_.append(v.data(), v.size());
return *this;
}
self& operator<<(const Buffer& v)
{
*this << v.toStringPiece();
return *this;
}
void append(const char* data, int len) { buffer_.append(data, len); }
const Buffer& buffer() const { return buffer_; }
void resetBuffer() { buffer_.reset(); }
private:
void staticCheck();
template<typename T>
void formatInteger(T);
Buffer buffer_;
static const int kMaxNumericSize = 32;
};
//简简单单打印多好。
class Fmt // : noncopyable
{
public:
template<typename T>
Fmt(const char* fmt, T val);
const char* data() const { return buf_; }
int length() const { return length_; }
private:
char buf_[32];
int length_;
};
inline LogStream& operator<<(LogStream& s, const Fmt& fmt)
{
s.append(fmt.data(), fmt.length());
return s;
}
}
#endif // MUDUO_BASE_LOGSTREAM_H
#include <muduo/base/LogStream.h>
#include <algorithm>
#include <limits>
#include <type_traits>
#include <assert.h>
#include <string.h>
#include <stdint.h>
#include <stdio.h>
using namespace muduo;
using namespace muduo::detail;
#if defined(__clang__)
#pragma clang diagnostic ignored "-Wtautological-compare"
#else
#pragma GCC diagnostic ignored "-Wtype-limits"
#endif
namespace muduo
{
namespace detail
{
const char digits[] = "9876543210123456789";
const char* zero = digits + 9;
static_assert(sizeof(digits) == 20, "wrong number of digits");
const char digitsHex[] = "0123456789ABCDEF";
static_assert(sizeof digitsHex == 17, "wrong number of digitsHex");
// Efficient Integer to String Conversions, by Matthew Wilson.
template<typename T>
size_t convert(char buf[], T value)
{
T i = value;
char* p = buf;
do//比如-123456
{
int lsd = static_cast<int>(i % 10);//-6
i /= 10;//-12345
*p++ = zero[lsd];//直接处理负数zero[-6]=6,还可以这样。。
} while (i != 0);
if (value < 0)
{
*p++ = '-';//尾巴上添加负号
}
*p = '\0';//654321-/0
std::reverse(buf, p);//-123456/0
return p - buf;//len.coocoocoocoococococool
}
size_t convertHex(char buf[], uintptr_t value)
{
uintptr_t i = value;
char* p = buf;
do
{
int lsd = static_cast<int>(i % 16);
i /= 16;
*p++ = digitsHex[lsd];
} while (i != 0);
*p = '\0';
std::reverse(buf, p);
return p - buf;
}
template class FixedBuffer<kSmallBuffer>;
template class FixedBuffer<kLargeBuffer>;
}
}
template<int SIZE>
const char* FixedBuffer<SIZE>::debugString()
{
*cur_ = '\0';
return data_;
}
template<int SIZE>
void FixedBuffer<SIZE>::cookieStart()
{
}
template<int SIZE>
void FixedBuffer<SIZE>::cookieEnd()
{
}
//暂时不知道是做啥用的,确保kMaxNumericSize大于所要转换的类型的字节长度?
void LogStream::staticCheck()
{
static_assert(kMaxNumericSize - 10 > std::numeric_limits<double>::digits10,
"kMaxNumericSize is large enough");
static_assert(kMaxNumericSize - 10 > std::numeric_limits<long double>::digits10,
"kMaxNumericSize is large enough");
static_assert(kMaxNumericSize - 10 > std::numeric_limits<long>::digits10,
"kMaxNumericSize is large enough");
static_assert(kMaxNumericSize - 10 > std::numeric_limits<long long>::digits10,
"kMaxNumericSize is large enough");
}
template<typename T>
void LogStream::formatInteger(T v)
{
if (buffer_.avail() >= kMaxNumericSize)
{
size_t len = convert(buffer_.current(), v);
buffer_.add(len);
}
}
LogStream& LogStream::operator<<(short v)
{
*this << static_cast<int>(v);
return *this;
}
LogStream& LogStream::operator<<(unsigned short v)
{
*this << static_cast<unsigned int>(v);
return *this;
}
LogStream& LogStream::operator<<(int v)
{
formatInteger(v);
return *this;
}
LogStream& LogStream::operator<<(unsigned int v)
{
formatInteger(v);
return *this;
}
LogStream& LogStream::operator<<(long v)
{
formatInteger(v);
return *this;
}
LogStream& LogStream::operator<<(unsigned long v)
{
formatInteger(v);
return *this;
}
LogStream& LogStream::operator<<(long long v)
{
formatInteger(v);
return *this;
}
LogStream& LogStream::operator<<(unsigned long long v)
{
formatInteger(v);
return *this;
}
LogStream& LogStream::operator<<(const void* p)
{
uintptr_t v = reinterpret_cast<uintptr_t>(p);
if (buffer_.avail() >= kMaxNumericSize)
{
char* buf = buffer_.current();
buf[0] = '0';
buf[1] = 'x';
size_t len = convertHex(buf+2, v);
buffer_.add(len+2);
}
return *this;
}
// FIXME: replace this with Grisu3 by Florian Loitsch.
LogStream& LogStream::operator<<(double v)
{
if (buffer_.avail() >= kMaxNumericSize)
{
int len = snprintf(buffer_.current(), kMaxNumericSize, "%.12g", v);
buffer_.add(len);
}
return *this;
}
template<typename T>
Fmt::Fmt(const char* fmt, T val)//使用方法如os << muduo::Fmt("%4.2f", 1.2);
{
static_assert(std::is_arithmetic<T>::value == true, "Must be arithmetic type");
length_ = snprintf(buf_, sizeof buf_, fmt, val);
assert(static_cast<size_t>(length_) < sizeof buf_);
}
// Explicit instantiations
template Fmt::Fmt(const char* fmt, char);
template Fmt::Fmt(const char* fmt, short);
template Fmt::Fmt(const char* fmt, unsigned short);
template Fmt::Fmt(const char* fmt, int);
template Fmt::Fmt(const char* fmt, unsigned int);
template Fmt::Fmt(const char* fmt, long);
template Fmt::Fmt(const char* fmt, unsigned long);
template Fmt::Fmt(const char* fmt, long long);
template Fmt::Fmt(const char* fmt, unsigned long long);
template Fmt::Fmt(const char* fmt, float);
template Fmt::Fmt(const char* fmt, double);