“不适合人类阅读,非常水的自我笔记.”
1. Status类
首先来看一下Status内的基本介绍。Status内部含有Code枚举值,可以看到Code里面含有0-5个状态。
私有成员status_为const char *,其前4个字节代表消息长度,对应[0,3],第4个字节代表消息码,对应[4],5个字节之后代表实际的消息体,对应[5,…]。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class LEVELDB_EXPORT Status {
private:
enum Code {
kOk = 0,
kNotFound = 1,
kCorruption = 2,
kNotSupported = 3,
kInvalidArgument = 4,
kIOError = 5
};
// OK status has a null state_. Otherwise, state_ is a new[] array
// of the following form:
// state_[0..3] == length of message
// state_[4] == code
// state_[5..] == message
const char* state_;
};
说到这里,私有成员还有:code、Status构造、CopyState。
(1)code函数
1
2
3
Code code() const {
return (state_ == nullptr) ? kOk : static_cast<Code>(state_[4]);
}
code在返回的时候,根据代码可以知道,当state_ 为nullprt时,返回的是kOk状态,否则从state_中取第四个字节的Code。
(2) Status构造
在下面的构造中code被断言不为kOk,传递了两个msg,都为Slince类型。
len1表示msg的大小;len2表示msg2的大小。
size表示len1 + len2 + 2
2表示在msg与msg2中间添加一个冒号与空格(不太理解为什么要用冒号和空格隔开msg和msg2,会有什么好处嘛?如果只是为了区分msg和msg2,为什么要用两个字符呢?)。
最后拼接的结果需要给结果大小加5,5分为4 + 1,4表示前4字节是state_[0…3]大小,1表示 state__[4] 是code类型。
下面三行代码对应的是给result填充内容:
1
2
3
std::memcpy(result, &size, sizeof(size));
result[4] = static_cast<char>(code);
std::memcpy(result + 5, msg.data(), len1);
memcpy这一行,表示将size内存地址的内容拷贝到result地址中,这里刚好拷贝占据[0…3],这样就可以把前4个字节的内容填充为result的大小;
result[4]填充为code类型,这里是一个字节所以使用static_cast
最后拷贝真实的msg中的内容到5字节之后,即[5…]。
随后根据msg2的大小是否为空进行后续操作,如果不为空,则继续拷贝,首先在5 + len1的位置填充冒号,在后一位填充空格,最后把len2拷贝进去,这里result + 7 + len1表示的是:5 + len1 + 2 = 7 + len1,指向要拷贝msg2的起始位置。
最终结果就是:“sizecodemsg: msg2”。这里是size + code + msg + 冒号 + 空格 + msg2。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Status::Status(Code code, const Slice& msg, const Slice& msg2) {
assert(code != kOk);
const uint32_t len1 = static_cast<uint32_t>(msg.size());
const uint32_t len2 = static_cast<uint32_t>(msg2.size());
const uint32_t size = len1 + (len2 ? (2 + len2) : 0);
char* result = new char[size + 5];
std::memcpy(result, &size, sizeof(size));
result[4] = static_cast<char>(code);
std::memcpy(result + 5, msg.data(), len1);
if (len2) {
result[5 + len1] = ':';
result[6 + len1] = ' ';
std::memcpy(result + 7 + len1, msg2.data(), len2);
}
state_ = result;
}
这里举个简单的例子:
1
2
3
4
uint32_t sz = 65;
char* r = new char[5];
memcpy(r, &sz, sizeof(sz));
cout << r << endl; // A
例如:数字65对应的ascii为’A’,那么经过memcpy拷贝之后便是’A’。
同理我们想得到size,可以这样:
1
2
3
uint32_t size;
memcpy(&size, r, sizeof(size));
cout << size << endl; // 65
那么此时size就是65。
(3) CopyState函数
首先通过memcpy拿到state[0…3]所表示的state大小,拿到之后构造了新的result,再加上5,随后拷贝state的实际内容到5字节之后,并返回result。
1
2
3
4
5
6
7
const char* Status::CopyState(const char* state) {
uint32_t size;
std::memcpy(&size, state, sizeof(size));
char* result = new char[size + 5];
std::memcpy(result, state, size + 5);
return result;
}
2.构造析构与拷贝移动
-
构造与析构
这个很简单,就是设置nullptr与delete[]。
1 2 3
// Create a success status. Status() noexcept : state_(nullptr) {} ~Status() { delete[] state_; }
-
拷贝操作
拷贝构造与拷贝赋值
1 2
Status(const Status& rhs); Status& operator=(const Status& rhs);
拷贝构造:内部实际就是调用了CopyState函数。
1
2
3
inline Status::Status(const Status& rhs) {
state_ = (rhs.state_ == nullptr) ? nullptr : CopyState(rhs.state_);
}
拷贝赋值:判断是否是自身,不是自身删除原先的state_ ,和拷贝构造操作一样。
1
2
3
4
5
6
7
8
9
inline Status& Status::operator=(const Status& rhs) {
// The following condition catches both aliasing (when this == &rhs),
// and the common case where both rhs and *this are ok.
if (state_ != rhs.state_) {
delete[] state_;
state_ = (rhs.state_ == nullptr) ? nullptr : CopyState(rhs.state_);
}
return *this;
}
-
移动操作
1 2
Status(Status&& rhs) noexcept : state_(rhs.state_) { rhs.state_ = nullptr; } Status& operator=(Status&& rhs) noexcept;
移动构造:浅拷贝
1
Status& operator=(Status&& rhs) noexcept;
移动赋值:直接交换
1
2
3
4
inline Status& Status::operator=(Status&& rhs) noexcept {
std::swap(state_, rhs.state_);
return *this;
}
3.一些函数
Status还提供了构造出不同Status的函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Return a success status.
static Status OK() { return Status(); }
// Return error status of an appropriate type.
static Status NotFound(const Slice& msg, const Slice& msg2 = Slice()) {
return Status(kNotFound, msg, msg2);
}
static Status Corruption(const Slice& msg, const Slice& msg2 = Slice()) {
return Status(kCorruption, msg, msg2);
}
static Status NotSupported(const Slice& msg, const Slice& msg2 = Slice()) {
return Status(kNotSupported, msg, msg2);
}
static Status InvalidArgument(const Slice& msg, const Slice& msg2 = Slice()) {
return Status(kInvalidArgument, msg, msg2);
}
static Status IOError(const Slice& msg, const Slice& msg2 = Slice()) {
return Status(kIOError, msg, msg2);
}
随后也给出了判断当前返回Code是哪个enum。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Returns true iff the status indicates success.
bool ok() const { return (state_ == nullptr); }
// Returns true iff the status indicates a NotFound error.
bool IsNotFound() const { return code() == kNotFound; }
// Returns true iff the status indicates a Corruption error.
bool IsCorruption() const { return code() == kCorruption; }
// Returns true iff the status indicates an IOError.
bool IsIOError() const { return code() == kIOError; }
// Returns true iff the status indicates a NotSupportedError.
bool IsNotSupportedError() const { return code() == kNotSupported; }
// Returns true iff the status indicates an InvalidArgument.
bool IsInvalidArgument() const { return code() == kInvalidArgument; }
最后给出了ToString函数,将当前Status转换为对应的String表示的Status。
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
// Return a string representation of this status suitable for printing.
// Returns the string "OK" for success.
std::string Status::ToString() const {
if (state_ == nullptr) {
return "OK";
} else {
char tmp[30];
const char* type;
switch (code()) {
case kOk:
type = "OK";
break;
case kNotFound:
type = "NotFound: ";
break;
case kCorruption:
type = "Corruption: ";
break;
case kNotSupported:
type = "Not implemented: ";
break;
case kInvalidArgument:
type = "Invalid argument: ";
break;
case kIOError:
type = "IO error: ";
break;
default:
std::snprintf(tmp, sizeof(tmp),
"Unknown code(%d): ", static_cast<int>(code()));
type = tmp;
break;
}
std::string result(type);
uint32_t length;
std::memcpy(&length, state_, sizeof(length));
result.append(state_ + 5, length);
return result;
}
4.测试
下面是测试函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <cstring>
#include <cassert>
#include "leveldb/status.h"
using namespace std;
using namespace leveldb;
int main() {
uint32_t sz = 65;
char* r = new char[5];
memcpy(r, &sz, sizeof(sz));
cout << r << endl; // A uint32_t size;
memcpy(&size, r, sizeof(size));
cout << size << endl; // 65
delete [] r;
Status status = Status::NotFound("custom NotFound status message");
Status status2 = std::move(status);
assert(status2.IsNotFound() == true);
assert(status2.IsIOError() == false);
assert("NotFound: custom NotFound status message" == status2.ToString());
return 0;
}