muduo源码解析10-logstream类
FixedBuffer和logstream
class FixedBuffer:noncopyable { }; class logstream:noncopyable { };
先说一下包含的头文件有一个StringPiece.h
个人感觉这个stringpiece没有必要实现啊,直接用std::string就好了
内部实现的操作,基本上std::string都能完成.后面有关stringpiece我都直接放弃了
const char* data() const { return ptr_; }
int size() const { return length_; }
bool empty() const { return length_ == 0; }
const char* begin() const { return ptr_; }
const char* end() const { return ptr_ + length_; }
void clear() { ptr_ = NULL; length_ = 0; }
void set(const char* buffer, int len) { ptr_ = buffer; length_ = len; }
下面是作者原话:
A string like object that points into another piece of memory.
Useful for providing an interface that allows clients to easily
pass in either a "const char*" or a "string".
Arghh! I wish C++ literals were automatically of type "string".
FixedBuffer作用:
FixedBuffer类:实现了对于一块字符数组的管理
成员变量:
用char m_data[SIZE]保存数据
用char* m_cur记录当前操作的那个元素的指针,默认指向最后一个字符的下一个位置.
字符数组示意图 SIZE=8
m_data:['1']['2']['3']['4']['\0']['\0']['\0']['\0']
m_cur:4 end:8
因此
length() = 4 =m_cur-m_data
sizeof m_data == 8 ==SIZE
end() == m_data+ sizeof m_data
avail() == end()-m_cur
FixedBuffer成员变量:
private: void (*m_cookie)(); //一个函数指针,暂时未知作用 char m_data[SIZE]; //最重要的成员,字符数组 char* m_cur; //便于操作字符数组的指针
FixedBuffer成员函数:
public: FixedBuffer():m_cur(m_data) { setCookie(cookieStart); } ~FixedBuffer() { setCookie(cookieEnd); } //拷贝一段字符放到字符数组m_data中 void append(const char* buf,size_t len) { //只有当剩余元素够用时才进行拷贝 if(implicit_cast<size_t>(avail())>len) { memcpy(m_cur,buf,len); m_cur+=len; } } //返回内部字符串 const char* data() const{return m_data;} //得到内部字符串的大小,也就是m_data数据长度 int length() const{return static_cast<int>(m_cur-m_data);} //返回m_cur指针 char* current(){return m_cur;} //得到字符数组剩余可用字符 int avail() const{return static_cast<int>(end()-m_cur);} //更改m_cur位置 void add(size_t len){m_cur+=len;} //让m_cur回到初始m_data位置 void reset(){m_cur=m_data;} //清空内部字符数组 void bzero(){memZero(m_data,sizeof(m_data));} //为了GDB使用,返回m_data到m_cur之间的数据 const char* debugString() { m_cur='\0'; return m_data; } void setCookie(void (*cookie)()){m_cookie=cookie;} //为了单元测试使用 string toString() const{return string(m_data,length());} //StringPiece已放弃使用 //StringPiece toStringPiece() const; private: const char* end() const{return m_data+sizeof(m_data);} //都暂时没有实现,以后会实现 static void cookieStart(){} static void cookieEnd(){}
需要注意一下,源码中作者提供了两个FixedBuffer大小
const int kSmallBuffer=4000;
const int kLargeBuffer=4000*1000;
template class FixedBuffer<kSmallBuffer>;
template class FixedBuffer<kLargeBuffer>;
logstream作用:
logstream 类:
数据成员只有一个,就是上面的FixedBuffer<4000>;
成员函数:
基本上就是重载了一大堆<<操作符,可以实现把各种基本的数据类型保存到内部m_buffer中
logstream成员变量:
private: typedef detail::FixedBuffer<detail::kSmallBuffer> Buffer; Buffer m_buffer;//内部数据成员,类型是FixedBuffer<4000>
logstream成员函数:
typedef logstream self; //省字数 public: //Buffer类型其实就是一个FixedBuffer,大小为4000的类型 typedef detail::FixedBuffer<detail::kSmallBuffer> Buffer; //重载了一堆<<操作符,可以实现针对各种基本/常用数据类型的logstream << 操作 //很多<<重载的实现都依赖于formatInteger函数 self& operator<<(bool v) { m_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<<(char v) { m_buffer.append(&v,1); return *this; } self& operator<<(const char* str) { if(str) m_buffer.append(str,strlen(str)); else m_buffer.append("(null)",6); return *this; } self& operator<<(const unsigned char* str) { *this<<reinterpret_cast<const char*>(str); return *this; } self& operator<<(const string& v) { m_buffer.append(v.data(),v.size()); return *this; } //self& operator<<(const StringPiece& v);废弃掉不用 self& operator<<(const Buffer& v) { m_buffer.append(v.data(),v.length()); return *this; } //一些基本操作,添加数据,返回FixedBuffer<4000>,重置m_buffer void append(const char* data,int len); const Buffer& buffer() const{return m_buffer;} void resetBuffer(){m_buffer.reset();} private: //用于静态编译时的一些断言 void staticCheck(); //很重要的一个函数,用于实现向m_buffer中append各种类型 template<typename T> void formatInteger(T);
测试:
#include"base/logstream.h" #include<iostream> using namespace std; namespace mymuduo{ namespace currentthread { void cacheTid() { } } } int main() { //内部数据(字符数组)大小只有4000 mymuduo::logstream ls; bool b=false; short s=23; int i=133; unsigned long ul=10000000; double d=3.123456; string str("nmsl"); mymuduo::logstream::Buffer buffer; buffer.append("nmsl2",5); ls<<b<<" "<<s<<" "<<i<<" "<<ul<<" " <<d<<" "<<str.data()<<" "<<buffer; std::cout<<ls.buffer().data()<<std::endl; }
打印结果:
0 23 133 10000000 3.123456 nmsl nmsl2
只要明白了logstream内部是如何存储数据的,就不难理解logstream的实现了,logstream就是封装了一堆
<<操作符,用于保存不同数据类型的数据。
内部存储数据通过FixedBuufer<4000>来实现,而FixedBuufer<4000>又是通过char data[4000]来实现的,
因此只需要搞明白对char[]的基本操作就可以了。