Golang源码阅读
总览
src/cmd/dist/buf.c该文件提供两个数据结构:Buf、Vec,分别用来取代char*和char**的相关操作。Buf和Vec这两个数据结构非常简单易懂,其他C语言项目如有需要,可以比较方便的拿过去使用,因此记录在此。src/lib9/cleanname.cUnix下的路径压缩功能cmd/dist/windows.cwindows平台相关的一些功能函数src/unicode/utf8/utf8.goutf8编码问题src/io/pipe.go进程内的单工管道src/net/pipe.go进程内的双工管道
1. src/cmd/dist/buf.c
Buf定义
// A Buf is a byte buffer, like Go's []byte.
typedef struct Buf Buf;
struct Buf
{
char *p;
int len;
int cap;
};
对Buf结构相关的一些操作
void binit(Buf *b)初始化一个Bufvoid breset(Buf *b)重置Buf,使之长度为0。类似于C++中的std::string::clear(),其数据内存不释放,但数据长度字段设为0void bfree(Buf *b)释放掉Buf内部的内存,并调用binit初始化这个Bufvoid bgrow(Buf *b, int n)增长Buf内部的内存,确保至少还能容纳n字节数据void bwrite(Buf *b, void *v, int n)将从v地址开始的n字节数据追加写入Buf中。类似于C++中的std::string::append(v,n)void bwritestr(Buf *b, char *p)将字符串p追加写入Buf中,会自动调用strlen(p)计算p的长度。类似于C++中的std::string::append(p)char* bstr(Buf *b)返回一个NUL结束的字符串指针,该指针指向Buf内部,外部调用者不能释放该指针。类似于C++中的std::string::c_str()char* btake(Buf *b)返回一个NUL结束的字符串指针,外部调用者需要自己释放该指针。void bwriteb(Buf *dst, Buf *src)将Bufsrc追加到dst中,src保持不变。类似于C++中的std::string::append(s)bool bequal(Buf *s, Buf *t)判断两个Buf是否相等。类似于C++中的std::string::compare(s) == 0void bsubst(Buf *b, char *x, char *y)使用子串y替换掉Buf中所有的x
Vec定义
// A Vec is a string vector, like Go's []string.
typedef struct Vec Vec;
struct Vec
{
char **p;
int len;
int cap;
};
对Vec结构相关的一些操作
void vinit(Vec *b)初始化一个Vecvoid vreset(Vec *b)重置Vec,使之长度为0。其数据内存全部释放void vfree(Vec *b)释放掉Vec内部的内存,并调用vinit初始化这个Vecvoid vgrow(Vec *b, int n)增长Vec内部的内存,确保至少还能容纳n字节数据。内部实现时为了效率考虑,第一次内存分配时确保至少分配64字节。void vcopy(Vec *dst, char **src, int srclen)将长度为srclen的字符串数组挨个复制添加到Vec中。void vadd(Vec *v, char *p)将字符串p拷贝一份添加到Vec中。void vaddn(Vec *b, char *p, int n)将长度为n的字符串p拷贝一份并添加到Vec中。void vuniq(Vec *v)对Vec排序,然后去掉重复的元素void splitlines(Vec *v, char *p)将字符串p按照\n(如果前面有\r会自动trim掉)分割为多段添加到Vec中。void splitfields(Vec *v, char *p)将字符串p按照空格('\n'、'\t'、'\r'、' ')分割为多段添加到Vec中。
2. src/lib9/cleanname.c
char* cleanname(char *name) 该函数在原地(in place)实现了Unix下的路径压缩功能,能够处理多个 / . ..等等组合路径问题。
3. cmd/dist/windows.c
Rune定义typedef unsigned short Runestatic int encoderune(char *buf, Rune r)将Rune转换utf8格式编码存储到buf中。Unicode/UTF8编码相关可以参考:http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.htmlstatic int decoderune(Rune *r, char *sbuf)将utf8编码的数据转换到Rune中
4. src/unicode/utf8/utf8.go
func EncodeRune(p []byte, r rune)int 将Rune转换为utf8格式编码存储到字节数组p中。func DecodeRune(p []byte) (r rune, size int)将字节数组p中的第一个utf8编码转换为Rune
5. src/io/pipe.go 进程内的单工管道
该管道是单工的,一端只能写,另一端只能读。这里提供了两个接口PipeReader和PipeWriter,其底层使用的pipe结构体定义如下:
// A pipe is the shared pipe structure underlying PipeReader and PipeWriter.
type pipe struct {
rl sync.Mutex // 读锁,每次只允许一个消费者(reader)
wl sync.Mutex // 写锁,每次只允许一个生产者(writer)
l sync.Mutex // 整体锁,保护下面所有的成员变量
data []byte // data remaining in pending write
rwait sync.Cond // waiting reader
wwait sync.Cond // waiting writer
rerr error // if reader closed, error to give writes
werr error // if writer closed, error to give reads
}
实现时,使用一个公共的字节缓冲区,通过读锁、写锁和整体锁这三把锁对这个缓冲区做好保护,实现在进程内的不同goroutine直接传递数据。
6. src/net/pipe.go 进程内的双工管道
使用 io.PipeReader和io.PipeWriter组合实现的双工管道,并且实现了net.Conn接口,其底层使用的pipe结构体定义如下:
type pipe struct {
*io.PipeReader
*io.PipeWriter
}