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[]的基本操作就可以了。

 

posted @ 2020-08-23 23:26  WoodInEast  阅读(247)  评论(0编辑  收藏  举报