muduo GzipFile

对 zlib 进行了简单封装,主要欣赏代码风格和规范。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#pragma once

#include "muduo/base/StringPiece.h"
#include "muduo/base/noncopyable.h"
#include <zlib.h>

namespace muduo
{

class GzipFile : noncopyable
{
public:
GzipFile(GzipFile&& rhs) noexcept // move
: file_(rhs.file_)
{
rhs.file_ = NULL;
}

~GzipFile()
{
if (file_)
{
::gzclose(file_);
}
}

GzipFile& operator=(GzipFile&& rhs) noexcept
{
swap(rhs);
return *this;
}

bool valid() const { return file_ != NULL; }
void swap(GzipFile& rhs) { std::swap(file_, rhs.file_); }
#if ZLIB_VERNUM >= 0x1240
bool setBuffer(int size) { return ::gzbuffer(file_, size) == 0; }
#endif

// return the number of uncompressed bytes actually read, 0 for eof, -1 for error
int read(void* buf, int len) { return ::gzread(file_, buf, len); }

// return the number of uncompressed bytes actually written
int write(StringPiece buf) { return ::gzwrite(file_, buf.data(), buf.size()); }

// number of uncompressed bytes
off_t tell() const { return ::gztell(file_); }

#if ZLIB_VERNUM >= 0x1240
// number of compressed bytes
off_t offset() const { return ::gzoffset(file_); }
#endif

// int flush(int f) { return ::gzflush(file_, f); }

static GzipFile openForRead(StringArg filename)
{
return GzipFile(::gzopen(filename.c_str(), "rbe"));
}

static GzipFile openForAppend(StringArg filename)
{
return GzipFile(::gzopen(filename.c_str(), "abe"));
}

static GzipFile openForWriteExclusive(StringArg filename)
{
return GzipFile(::gzopen(filename.c_str(), "wbxe"));
}

static GzipFile openForWriteTruncate(StringArg filename)
{
return GzipFile(::gzopen(filename.c_str(), "wbe"));
}

private:
explicit GzipFile(gzFile file)
: file_(file)
{
}

gzFile file_;
};

} // namespace muduo

参考资料

查看更多

muduo ProcessInfo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#ifndef MUDUO_BASE_PROCESSINFO_H
#define MUDUO_BASE_PROCESSINFO_H

#include "muduo/base/StringPiece.h"
#include "muduo/base/Types.h"
#include "muduo/base/Timestamp.h"
#include <vector>
#include <sys/types.h>

namespace muduo
{

namespace ProcessInfo
{
pid_t pid(); // 进程 pid
string pidString(); // pid字符串
uid_t uid(); // userid
string username(); // uid字符串
uid_t euid(); // 有效用户id
Timestamp startTime(); // 进程开始时间
int clockTicksPerSecond(); // 时钟频率
int pageSize(); // 内存页大小
// 是否以调试模式构建
bool isDebugBuild(); // constexpr
// 主机名
string hostname();
// 进程名
string procname();
StringPiece procname(const string& stat);

/// read /proc/self/status
string procStatus();

/// read /proc/self/stat
string procStat();

/// read /proc/self/task/tid/stat
string threadStat();

/// readlink /proc/self/exe
string exePath();

int openedFiles();
int maxOpenFiles();

struct CpuTime
{
double userSeconds;
double systemSeconds;

CpuTime() : userSeconds(0.0), systemSeconds(0.0) { }

double total() const { return userSeconds + systemSeconds; }
};
CpuTime cpuTime();

int numThreads();
std::vector<pid_t> threads();
} // namespace ProcessInfo

} // namespace muduo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
//
// Author: Shuo Chen (chenshuo at chenshuo dot com)

#include "muduo/base/ProcessInfo.h"
#include "muduo/base/CurrentThread.h"
#include "muduo/base/FileUtil.h"

#include <algorithm>

#include <assert.h>
#include <dirent.h>
#include <pwd.h>
#include <stdio.h> // snprintf
#include <stdlib.h>
#include <unistd.h>
#include <sys/resource.h>
#include <sys/times.h>

namespace muduo
{
namespace detail
{

// threadlocal
__thread int t_numOpenedFiles = 0;
int fdDirFilter(const struct dirent* d)
{
if (::isdigit(d->d_name[0]))
{
++t_numOpenedFiles;
}
return 0;
}

__thread std::vector<pid_t>* t_pids = NULL; // 线程id列表
int taskDirFilter(const struct dirent* d)
{
if (::isdigit(d->d_name[0]))
{
t_pids->push_back(atoi(d->d_name));
}
return 0;
}

int scanDir(const char *dirpath, int (*filter)(const struct dirent *))
{
struct dirent** namelist = NULL;
int result = ::scandir(dirpath, &namelist, filter, alphasort); // alphasort 用来排序
assert(namelist == NULL);
return result;
}

Timestamp g_startTime = Timestamp::now();
// assume those won't change during the life time of a process.
int g_clockTicks = static_cast<int>(::sysconf(_SC_CLK_TCK));
int g_pageSize = static_cast<int>(::sysconf(_SC_PAGE_SIZE));
} // namespace detail
} // namespace muduo

using namespace muduo;
using namespace muduo::detail;

pid_t ProcessInfo::pid()
{
return ::getpid();
}

string ProcessInfo::pidString()
{
char buf[32];
snprintf(buf, sizeof buf, "%d", pid());
return buf;
}

uid_t ProcessInfo::uid()
{
return ::getuid();
}

string ProcessInfo::username()
{
struct passwd pwd;
struct passwd* result = NULL;
char buf[8192];
const char* name = "unknownuser";

getpwuid_r(uid(), &pwd, buf, sizeof buf, &result); // 从密码文件中获取记录
if (result)
{
name = pwd.pw_name;
}
return name;
}

uid_t ProcessInfo::euid()
{
return ::geteuid();
}

Timestamp ProcessInfo::startTime()
{
return g_startTime;
}

int ProcessInfo::clockTicksPerSecond()
{
return g_clockTicks;
}

int ProcessInfo::pageSize()
{
return g_pageSize;
}

bool ProcessInfo::isDebugBuild()
{
#ifdef NDEBUG
return false;
#else
return true;
#endif
}

string ProcessInfo::hostname()
{
// HOST_NAME_MAX 64
// _POSIX_HOST_NAME_MAX 255
char buf[256];
if (::gethostname(buf, sizeof buf) == 0)
{
buf[sizeof(buf)-1] = '\0';
return buf;
}
else
{
return "unknownhost";
}
}

string ProcessInfo::procname()
{
return procname(procStat()).as_string();
}

StringPiece ProcessInfo::procname(const string& stat)
{
StringPiece name;
size_t lp = stat.find('(');
size_t rp = stat.rfind(')');
if (lp != string::npos && rp != string::npos && lp < rp)
{
name.set(stat.data()+lp+1, static_cast<int>(rp-lp-1));
}
return name;
}

string ProcessInfo::procStatus()
{
string result;
FileUtil::readFile("/proc/self/status", 65536, &result);
return result;
}

string ProcessInfo::procStat()
{
string result;
FileUtil::readFile("/proc/self/stat", 65536, &result);
return result;
}

string ProcessInfo::threadStat()
{
char buf[64];
snprintf(buf, sizeof buf, "/proc/self/task/%d/stat", CurrentThread::tid());
string result;
FileUtil::readFile(buf, 65536, &result);
return result;
}

string ProcessInfo::exePath()
{
string result;
char buf[1024];
ssize_t n = ::readlink("/proc/self/exe", buf, sizeof buf);
if (n > 0)
{
result.assign(buf, n);
}
return result;
}

int ProcessInfo::openedFiles()
{
t_numOpenedFiles = 0;
scanDir("/proc/self/fd", fdDirFilter);
return t_numOpenedFiles;
}

/*
struct rlimit {
  rlim_t rlim_cur; // 软上限
  rlim_t rlim_max; // 硬上限
};
*/

int ProcessInfo::maxOpenFiles()
{
struct rlimit rl;
if (::getrlimit(RLIMIT_NOFILE, &rl))
{
return openedFiles();
}
else
{
return static_cast<int>(rl.rlim_cur);
}
}

ProcessInfo::CpuTime ProcessInfo::cpuTime()
{
ProcessInfo::CpuTime t;
struct tms tms;
if (::times(&tms) >= 0)
{
const double hz = static_cast<double>(clockTicksPerSecond());
t.userSeconds = static_cast<double>(tms.tms_utime) / hz;
t.systemSeconds = static_cast<double>(tms.tms_stime) / hz;
}
return t;
}

int ProcessInfo::numThreads()
{
int result = 0;
string status = procStatus();
size_t pos = status.find("Threads:");
if (pos != string::npos)
{
result = ::atoi(status.c_str() + pos + 8);
}
return result;
}

std::vector<pid_t> ProcessInfo::threads()
{
std::vector<pid_t> result;
t_pids = &result;
scanDir("/proc/self/task", taskDirFilter);
t_pids = NULL;
std::sort(result.begin(), result.end());
return result;
}

参考资料

查看更多

muduo atomic

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#ifndef MUDUO_BASE_ATOMIC_H
#define MUDUO_BASE_ATOMIC_H

#include "muduo/base/noncopyable.h"

#include <stdint.h>

namespace muduo
{

namespace detail
{
template<typename T>
class AtomicIntegerT : noncopyable
{
public:
AtomicIntegerT()
: value_(0)
{
}

// uncomment if you need copying and assignment
//
// AtomicIntegerT(const AtomicIntegerT& that)
// : value_(that.get())
// {}
//
// AtomicIntegerT& operator=(const AtomicIntegerT& that)
// {
// getAndSet(that.get());
// return *this;
// }

T get()
{
// in gcc >= 4.7: __atomic_load_n(&value_, __ATOMIC_SEQ_CST)
// 实现原子操作
return __sync_val_compare_and_swap(&value_, 0, 0);
}

T getAndAdd(T x)
{
// in gcc >= 4.7: __atomic_fetch_add(&value_, x, __ATOMIC_SEQ_CST)
return __sync_fetch_and_add(&value_, x);
}

T addAndGet(T x)
{
return getAndAdd(x) + x;
}

T incrementAndGet()
{
return addAndGet(1);
}

T decrementAndGet()
{
return addAndGet(-1);
}

void add(T x)
{
getAndAdd(x);
}

void increment()
{
incrementAndGet();
}

void decrement()
{
decrementAndGet();
}

T getAndSet(T newValue)
{
// in gcc >= 4.7: __atomic_exchange_n(&value_, newValue, __ATOMIC_SEQ_CST)
// 实现原子操作
return __sync_lock_test_and_set(&value_, newValue);
}

private:
volatile T value_; // 直接在内存占用进行存取
};
} // namespace detail

typedef detail::AtomicIntegerT<int32_t> AtomicInt32;
typedef detail::AtomicIntegerT<int64_t> AtomicInt64;

} // namespace muduo

#endif // MUDUO_BASE_ATOMIC_H

参考资料

查看更多

muduo date

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#ifndef MUDUO_BASE_DATE_H
#define MUDUO_BASE_DATE_H

#include "muduo/base/copyable.h"
#include "muduo/base/Types.h"

struct tm;

namespace muduo
{

///
/// Date in Gregorian calendar.
///
/// This class is immutable.
/// It's recommended to pass it by value, since it's passed in register on x64.
///
class Date : public muduo::copyable
// public boost::less_than_comparable<Date>,
// public boost::equality_comparable<Date>
{
public:

struct YearMonthDay
{
int year; // [1900..2500]
int month; // [1..12]
int day; // [1..31]
};

static const int kDaysPerWeek = 7;
static const int kJulianDayOf1970_01_01;

///
/// Constucts an invalid Date.
///
Date()
: julianDayNumber_(0)
{}

///
/// Constucts a yyyy-mm-dd Date.
///
/// 1 <= month <= 12
Date(int year, int month, int day);

///
/// Constucts a Date from Julian Day Number.
///
explicit Date(int julianDayNum)
: julianDayNumber_(julianDayNum)
{}

///
/// Constucts a Date from struct tm
///
explicit Date(const struct tm&);

// default copy/assignment/dtor are Okay

void swap(Date& that)
{
std::swap(julianDayNumber_, that.julianDayNumber_);
}

bool valid() const { return julianDayNumber_ > 0; }

///
/// Converts to yyyy-mm-dd format.
///
string toIsoString() const;

struct YearMonthDay yearMonthDay() const;

int year() const
{
return yearMonthDay().year;
}

int month() const
{
return yearMonthDay().month;
}

int day() const
{
return yearMonthDay().day;
}

// [0, 1, ..., 6] => [Sunday, Monday, ..., Saturday ]
int weekDay() const
{
return (julianDayNumber_+1) % kDaysPerWeek;
}

int julianDayNumber() const { return julianDayNumber_; }

private:
int julianDayNumber_;
};

inline bool operator<(Date x, Date y)
{
return x.julianDayNumber() < y.julianDayNumber();
}

inline bool operator==(Date x, Date y)
{
return x.julianDayNumber() == y.julianDayNumber();
}

} // namespace muduo

#endif // MUDUO_BASE_DATE_H
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
namespace muduo
{
namespace detail
{

char require_32_bit_integer_at_least[sizeof(int) >= sizeof(int32_t) ? 1 : -1];

// algorithm and explanation see:
// http://www.faqs.org/faqs/calendars/faq/part2/
// http://blog.csdn.net/Solstice

int getJulianDayNumber(int year, int month, int day)
{
(void) require_32_bit_integer_at_least; // no warning please
int a = (14 - month) / 12;
int y = year + 4800 - a;
int m = month + 12 * a - 3;
return day + (153*m + 2) / 5 + y*365 + y/4 - y/100 + y/400 - 32045;
}

struct Date::YearMonthDay getYearMonthDay(int julianDayNumber)
{
int a = julianDayNumber + 32044;
int b = (4 * a + 3) / 146097;
int c = a - ((b * 146097) / 4);
int d = (4 * c + 3) / 1461;
int e = c - ((1461 * d) / 4);
int m = (5 * e + 2) / 153;
Date::YearMonthDay ymd;
ymd.day = e - ((153 * m + 2) / 5) + 1;
ymd.month = m + 3 - 12 * (m / 10);
ymd.year = b * 100 + d - 4800 + (m / 10);
return ymd;
}
} // namespace detail
const int Date::kJulianDayOf1970_01_01 = detail::getJulianDayNumber(1970, 1, 1);
} // namespace muduo

using namespace muduo;
using namespace muduo::detail;

Date::Date(int y, int m, int d)
: julianDayNumber_(getJulianDayNumber(y, m, d))
{
}

Date::Date(const struct tm& t)
: julianDayNumber_(getJulianDayNumber(
t.tm_year+1900,
t.tm_mon+1,
t.tm_mday))
{
}

string Date::toIsoString() const
{
char buf[32];
YearMonthDay ymd(yearMonthDay());
snprintf(buf, sizeof buf, "%4d-%02d-%02d", ymd.year, ymd.month, ymd.day);
return buf;
}

Date::YearMonthDay Date::yearMonthDay() const
{
return getYearMonthDay(julianDayNumber_);
}

参考资料

查看更多

muduo FileUtil

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#ifndef MUDUO_BASE_FILEUTIL_H
#define MUDUO_BASE_FILEUTIL_H

#include "muduo/base/noncopyable.h"
#include "muduo/base/StringPiece.h"
#include <sys/types.h> // for off_t

namespace muduo
{
namespace FileUtil
{

// read small file < 64KB
class ReadSmallFile : noncopyable
{
public:
ReadSmallFile(StringArg filename);
~ReadSmallFile();

// return errno
template<typename String>
int readToString(int maxSize,
String* content,
int64_t* fileSize,
int64_t* modifyTime,
int64_t* createTime);

/// Read at maxium kBufferSize into buf_
// return errno
int readToBuffer(int* size);

const char* buffer() const { return buf_; }

static const int kBufferSize = 64*1024;

private:
int fd_;
int err_;
char buf_[kBufferSize];
};

// read the file content, returns errno if error happens.
template<typename String>
int readFile(StringArg filename,
int maxSize,
String* content,
int64_t* fileSize = NULL,
int64_t* modifyTime = NULL,
int64_t* createTime = NULL)
{
ReadSmallFile file(filename);
return file.readToString(maxSize, content, fileSize, modifyTime, createTime);
}

// not thread safe
class AppendFile : noncopyable
{
public:
explicit AppendFile(StringArg filename);

~AppendFile();

void append(const char* logline, size_t len);

void flush();

off_t writtenBytes() const { return writtenBytes_; }

private:

size_t write(const char* logline, size_t len);

FILE* fp_;
char buffer_[64*1024];
off_t writtenBytes_;
};

} // namespace FileUtil
} // namespace muduo

#endif // MUDUO_BASE_FILEUTIL_H

AppendFile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
FileUtil::AppendFile::AppendFile(StringArg filename)
: fp_(::fopen(filename.c_str(), "ae")), // 'e' for O_CLOEXEC 'a' 表示追加
writtenBytes_(0)
{
assert(fp_);
::setbuffer(fp_, buffer_, sizeof buffer_);
// posix_fadvise POSIX_FADV_DONTNEED ?
}

FileUtil::AppendFile::~AppendFile()
{
::fclose(fp_);
}

void FileUtil::AppendFile::append(const char* logline, const size_t len)
{
// 写入文件
size_t n = write(logline, len);
size_t remain = len - n;
while (remain > 0)
{
size_t x = write(logline + n, remain);
// 写入失败
if (x == 0)
{
int err = ferror(fp_);
if (err)
{
fprintf(stderr, "AppendFile::append() failed %s\n", strerror_tl(err));
}
break;
}
// 继续写入
n += x;
remain = len - n; // remain -= x
}
// 更新已经写入的总字节数
writtenBytes_ += len;
}

// 刷新文件流
void FileUtil::AppendFile::flush()
{
::fflush(fp_);
}

size_t FileUtil::AppendFile::write(const char* logline, size_t len)
{
// #undef fwrite_unlocked
// 写文件的不加锁版本,线程不安全
return ::fwrite_unlocked(logline, 1, len, fp_);
}

ReadSmallFile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
FileUtil::ReadSmallFile::ReadSmallFile(StringArg filename)
: fd_(::open(filename.c_str(), O_RDONLY | O_CLOEXEC)), // 只读 打开文件并记录文件描述符
err_(0)
{
// 清空缓冲区
buf_[0] = '\0';
if (fd_ < 0)
{
err_ = errno;
}
}

FileUtil::ReadSmallFile::~ReadSmallFile()
{
if (fd_ >= 0)
{
::close(fd_); // FIXME: check EINTR
}
}

// return errno
template<typename String>
int FileUtil::ReadSmallFile::readToString(int maxSize,
String* content,
int64_t* fileSize,
int64_t* modifyTime,
int64_t* createTime)
{
// 判断是否占 8 位
static_assert(sizeof(off_t) == 8, "_FILE_OFFSET_BITS = 64");
assert(content != NULL);
int err = err_;
if (fd_ >= 0)
{
content->clear();

if (fileSize)
{
// 获取文件信息
struct stat statbuf;
if (::fstat(fd_, &statbuf) == 0)
{ // 是否是常规文件
if (S_ISREG(statbuf.st_mode))
{
// 获得文件大小
*fileSize = statbuf.st_size;
// 申请空间
content->reserve(static_cast<int>(std::min(implicit_cast<int64_t>(maxSize), *fileSize)));
}
else if (S_ISDIR(statbuf.st_mode)) // 是目录
{
err = EISDIR;
}
if (modifyTime) // 更新时间
{
*modifyTime = statbuf.st_mtime;
}
if (createTime) // 创建时间
{
*createTime = statbuf.st_ctime;
}
}
else
{
err = errno;
}
}

while (content->size() < implicit_cast<size_t>(maxSize))
{
// 要读的字节数
size_t toRead = std::min(implicit_cast<size_t>(maxSize) - content->size(), sizeof(buf_));
ssize_t n = ::read(fd_, buf_, toRead);
if (n > 0)
{
content->append(buf_, n);
}
else
{
if (n < 0)
{
err = errno;
}
break;
}
}
}
return err;
}


// 将文件内容读入缓冲区, 将文件大小赋值给 size
int FileUtil::ReadSmallFile::readToBuffer(int* size)
{
int err = err_;
if (fd_ >= 0)
{
//pread() reads up to count bytes from file descriptor fd at offset offset (from the start of the
//file) into the buffer starting at buf. The file offset is not changed.
ssize_t n = ::pread(fd_, buf_, sizeof(buf_)-1, 0);
if (n >= 0)
{
if (size)
{
*size = static_cast<int>(n);
}
buf_[n] = '\0';
}
else
{
err = errno;
}
}
return err;
}

template int FileUtil::readFile(StringArg filename,
int maxSize,
string* content,
int64_t*, int64_t*, int64_t*);

template int FileUtil::ReadSmallFile::readToString(
int maxSize,
string* content,
int64_t*, int64_t*, int64_t*);

参考资料

查看更多

muduo CurrentThread

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#ifndef MUDUO_BASE_CURRENTTHREAD_H
#define MUDUO_BASE_CURRENTTHREAD_H

#include "muduo/base/Types.h"

namespace muduo
{
namespace CurrentThread
{
// internal
// 使用 __thread 修饰变量 使得每一个线程都有一份独立实体,各个线程的值互不干扰
extern __thread int t_cachedTid; // 当前线程id
extern __thread char t_tidString[32]; // 当前线程id
extern __thread int t_tidStringLength; // char 的大小
extern __thread const char* t_threadName; // 线程名字

void cacheTid();

inline int tid()
{
if (__builtin_expect(t_cachedTid == 0, 0))
{
cacheTid();
}
return t_cachedTid;
}

inline const char* tidString() // for logging
{
return t_tidString;
}

inline int tidStringLength() // for logging
{
return t_tidStringLength;
}

inline const char* name()
{
return t_threadName;
}

bool isMainThread();

void sleepUsec(int64_t usec); // for testing

string stackTrace(bool demangle);
} // namespace CurrentThread
} // namespace muduo

#endif // MUDUO_BASE_CURRENTTHREAD_H
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
namespace muduo
{
namespace CurrentThread
{
__thread int t_cachedTid = 0;
__thread char t_tidString[32];
__thread int t_tidStringLength = 6;
__thread const char* t_threadName = "unknown";
static_assert(std::is_same<int, pid_t>::value, "pid_t should be int");

string stackTrace(bool demangle)
{
string stack;
const int max_frames = 200;
void* frame[max_frames];
int nptrs = ::backtrace(frame, max_frames);
char** strings = ::backtrace_symbols(frame, nptrs);
if (strings)
{
size_t len = 256;
char* demangled = demangle ? static_cast<char*>(::malloc(len)) : nullptr;
for (int i = 1; i < nptrs; ++i) // skipping the 0-th, which is this function
{
if (demangle)
{
// https://panthema.net/2008/0901-stacktrace-demangled/
// bin/exception_test(_ZN3Bar4testEv+0x79) [0x401909]
char* left_par = nullptr;
char* plus = nullptr;
for (char* p = strings[i]; *p; ++p)
{
if (*p == '(')
left_par = p;
else if (*p == '+')
plus = p;
}

if (left_par && plus)
{
*plus = '\0';
int status = 0;
char* ret = abi::__cxa_demangle(left_par+1, demangled, &len, &status);
*plus = '+';
if (status == 0)
{
demangled = ret; // ret could be realloc()
stack.append(strings[i], left_par+1);
stack.append(demangled);
stack.append(plus);
stack.push_back('\n');
continue;
}
}
}
// Fallback to mangled names
stack.append(strings[i]);
stack.push_back('\n');
}
free(demangled);
free(strings);
}
return stack;
}

} // namespace CurrentThread
} // namespace muduo

参考资料

查看更多

muduo exception

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#ifndef MUDUO_BASE_EXCEPTION_H
#define MUDUO_BASE_EXCEPTION_H

#include "muduo/base/Types.h"
#include <exception>

namespace muduo
{

class Exception : public std::exception
{
public:
Exception(string what);
~Exception() noexcept override = default;

// default copy-ctor and operator= are okay.

const char* what() const noexcept override
{
return message_.c_str();
}

const char* stackTrace() const noexcept
{
return stack_.c_str();
}

private:
string message_;
string stack_;
};

} // namespace muduo

#endif // MUDUO_BASE_EXCEPTION_H
1
2
3
4
5
6
7
8
9
10
11
12
13
#include "muduo/base/Exception.h"
#include "muduo/base/CurrentThread.h"

namespace muduo
{

Exception::Exception(string msg)
: message_(std::move(msg)),
stack_(CurrentThread::stackTrace(/*demangle=*/false))
{
}

} // namespace muduo

参考资料

查看更多

muduo Timestamp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
class Timestamp : public muduo::copyable,
public boost::equality_comparable<Timestamp>,
public boost::less_than_comparable<Timestamp>
{
public:
///
/// Constucts an invalid Timestamp.
///
Timestamp()
: microSecondsSinceEpoch_(0)
{
}

///
/// Constucts a Timestamp at specific time
///
/// @param microSecondsSinceEpoch
explicit Timestamp(int64_t microSecondsSinceEpochArg)
: microSecondsSinceEpoch_(microSecondsSinceEpochArg)
{
}

void swap(Timestamp& that)
{
std::swap(microSecondsSinceEpoch_, that.microSecondsSinceEpoch_);
}

// default copy/assignment/dtor are Okay

string toString() const;
string toFormattedString(bool showMicroseconds = true) const;

bool valid() const { return microSecondsSinceEpoch_ > 0; }

// for internal usage.
int64_t microSecondsSinceEpoch() const { return microSecondsSinceEpoch_; }
time_t secondsSinceEpoch() const
{ return static_cast<time_t>(microSecondsSinceEpoch_ / kMicroSecondsPerSecond); }

///
/// Get time of now.
///
static Timestamp now();
static Timestamp invalid()
{
return Timestamp();
}

static Timestamp fromUnixTime(time_t t)
{
return fromUnixTime(t, 0);
}

static Timestamp fromUnixTime(time_t t, int microseconds)
{
return Timestamp(static_cast<int64_t>(t) * kMicroSecondsPerSecond + microseconds);
}

static const int kMicroSecondsPerSecond = 1000 * 1000;

private:
int64_t microSecondsSinceEpoch_;
};

inline bool operator<(Timestamp lhs, Timestamp rhs)
{
return lhs.microSecondsSinceEpoch() < rhs.microSecondsSinceEpoch();
}

inline bool operator==(Timestamp lhs, Timestamp rhs)
{
return lhs.microSecondsSinceEpoch() == rhs.microSecondsSinceEpoch();
}

///
/// Gets time difference of two timestamps, result in seconds.
///
/// @param high, low
/// @return (high-low) in seconds
/// @c double has 52-bit precision, enough for one-microsecond
/// resolution for next 100 years.
inline double timeDifference(Timestamp high, Timestamp low)
{
int64_t diff = high.microSecondsSinceEpoch() - low.microSecondsSinceEpoch();
return static_cast<double>(diff) / Timestamp::kMicroSecondsPerSecond;
}

///
/// Add @c seconds to given timestamp.
///
/// @return timestamp+seconds as Timestamp
///
inline Timestamp addTime(Timestamp timestamp, double seconds)
{
int64_t delta = static_cast<int64_t>(seconds * Timestamp::kMicroSecondsPerSecond);
return Timestamp(timestamp.microSecondsSinceEpoch() + delta);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
string Timestamp::toString() const
{
char buf[32] = {0};
int64_t seconds = microSecondsSinceEpoch_ / kMicroSecondsPerSecond;
int64_t microseconds = microSecondsSinceEpoch_ % kMicroSecondsPerSecond;
snprintf(buf, sizeof(buf), "%" PRId64 ".%06" PRId64 "", seconds, microseconds);
return buf;
}

string Timestamp::toFormattedString(bool showMicroseconds) const
{
char buf[64] = {0};
time_t seconds = static_cast<time_t>(microSecondsSinceEpoch_ / kMicroSecondsPerSecond);
struct tm tm_time;
gmtime_r(&seconds, &tm_time);

if (showMicroseconds)
{
int microseconds = static_cast<int>(microSecondsSinceEpoch_ % kMicroSecondsPerSecond);
snprintf(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d.%06d",
tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday,
tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec,
microseconds);
}
else
{
snprintf(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d",
tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday,
tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec);
}
return buf;
}

Timestamp Timestamp::now()
{
struct timeval tv;
gettimeofday(&tv, NULL);
int64_t seconds = tv.tv_sec;
return Timestamp(seconds * kMicroSecondsPerSecond + tv.tv_usec);
}

参考资料

查看更多

leetcode148排序链表

O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。

不能用递归法来解,所以按照链表长度从 1 到 len,倍增进行合并。需要依次合并长度为 1,2,4…..len的链表。

主要需要将链表分割成一个个长度为 size 的小段,并且将长度为 size 的小段进行合并。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
// cut n个节点,然后返回剩下的链表的头节点
ListNode* cut(ListNode* head, int n) {
ListNode* node = head;
while(--n && node) node = node->next;
if(node == NULL) return NULL;
ListNode* next = node->next;
node->next = NULL;
return next;
}

ListNode* merge(ListNode* l1, ListNode* l2) {
ListNode* dummy = new ListNode(0);
ListNode* node = dummy;
while(l1 && l2) {
if(l1->val < l2-> val) {
node->next = l1;
l1 = l1->next;
} else {
node->next = l2;
l2 = l2->next;
}
node = node->next;
}
if(l1) node->next = l1;
else node->next = l2;
return dummy->next;
}
ListNode* sortList(ListNode* head) {
if(head == NULL || head->next == NULL) return head;
int len = 0;
ListNode* node = head;
while(node) {
len++;
node = node->next;
}
ListNode* dummy = new ListNode(0);
dummy->next = head;
for(int sz = 1; sz < len; sz*=2) {
ListNode* cur = dummy->next; // 待分割链表的第一个节点 tail为已经合并好的链表的最后一个节点
ListNode* tail = dummy;
while(cur) {
ListNode* left = cur;
ListNode* right = cut(left, sz);
cur = cut(right, sz);
tail->next = merge(left, right);
while(tail->next) tail = tail->next;
}
}

return dummy->next;
}
};

参考资料

查看更多