1. 简介
该StringPiece是PCRE的实现,是对字符串的一个proxy类而已(即设计模式中的代理模式)。
2. 背景
很多时候,当传入一个字符串到函数时,往往只是读取字符串时
若使用std::string,当实参为const char *时,会分配内存并拷贝该字符串以生成一个std::string
当一个函数接受一个const std::string,而在该函数内部,又需要传递该值到另一个函数,则又需要重新生成一个std::string
3. 目的
当某个接口参数是接受字符串类型时,为了减少不必要的开销
该类型可以接受const char *,std::string,减少冗余代码编写
4. 要点
① 成员变量
const char* ptr_;
int length_;
通过保存字符串指针和长度,来避免不必要的复制;
开销很低,只需要sizeof(const char*) + sizeof(int)字节;
内部的ptr_ 这块内存不归他所有,要确保在StringPiece生命期内,该数据可用
② 构造函数
StringPiece()
: ptr_(NULL), length_(0) { }
StringPiece(const char* str)
: ptr_(str), length_(static_cast<int>(strlen(ptr_))) { }
StringPiece(const unsigned char* str)
: ptr_(reinterpret_cast<const char*>(str)),
length_(static_cast<int>(strlen(ptr_))) { }
StringPiece(const string& str)
: ptr_(str.data()), length_(static_cast<int>(str.size())) { }
StringPiece(const char* offset, int len)
: ptr_(offset), length_(len) { }
参数都是字符串且都是const类型,只用于提取,而不用于修改
③ 字符串比较
bool operator==(const StringPiece& x) const
{
return ((length_ == x.length_) &&
(memcmp(ptr_, x.ptr_, length_) == 0));
}
bool operator!=(const StringPiece& x) const
{
return !(*this == x);
}
#define STRINGPIECE_BINARY_PREDICATE(cmp,auxcmp) \
bool operator cmp (const StringPiece& x) const { \
int r = memcmp(ptr_, x.ptr_, length_ < x.length_ ? length_ : x.length_); \
return ((r auxcmp 0) || ((r == 0) && (length_ cmp x.length_))); \
}
STRINGPIECE_BINARY_PREDICATE(<, <);
STRINGPIECE_BINARY_PREDICATE(<=, <);
STRINGPIECE_BINARY_PREDICATE(>=, >);
STRINGPIECE_BINARY_PREDICATE(>, >);
#undef STRINGPIECE_BINARY_PREDICATE
以<为例,宏展开后代码如下
bool operator < (const StringPiece& x) const { \
int r = memcmp(ptr_, x.ptr_, length_ < x.length_ ? length_ : x.length_); \
return ((r < 0) || ((r == 0) && (length_ < x.length_))); \
}
比较”abcd” < “abcdefg”, 返回的结果为true
比较”abcdx” < “abcdefg”, 返回结果为false
④ 操作
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;
}
void set(const char* str)
{
ptr_ = str;
length_ = static_cast<int>(strlen(str));
}
void set(const void* buffer, int len)
{
ptr_ = reinterpret_cast<const char*>(buffer);
length_ = len;
}
char operator[](int i) const
{
return ptr_[i];
}
void remove_prefix(int n)
{
ptr_ += n;
length_ -= n;
}
void remove_suffix(int n)
{
length_ -= n;
}
int compare(const StringPiece& x) const
{
int r = memcmp(ptr_, x.ptr_, length_ < x.length_ ? length_ : x.length_);
if (r == 0) {
if (length_ < x.length_) r = -1;
else if (length_ > x.length_) r = +1;
}
return r;
}
string as_string() const
{
return string(data(), size());
}
void CopyToString(string* target) const
{
target->assign(ptr_, length_);
}
// Does "this" start with "x"
bool starts_with(const StringPiece& x) const
{
return ((length_ >= x.length_) && (memcmp(ptr_, x.ptr_, x.length_) == 0));
}
⑤ Traits
由于StringPiece只持有目标指针,所以是POD类型,并且拥有平凡构造函数,所以可以定义如下的type traits以指示STL采用更为高效的算法实现。
#ifdef HAVE_TYPE_TRAITS
// This makes vector<StringPiece> really fast for some STL implementations
template<> struct __type_traits<StringPiece> {
typedef __true_type has_trivial_default_constructor;
typedef __true_type has_trivial_copy_constructor;
typedef __true_type has_trivial_assignment_operator;
typedef __true_type has_trivial_destructor;
typedef __true_type is_POD_type;
};
#endif
⑥ 输出
// allow StringPiece to be logged
std::ostream& operator<<(std::ostream& o, const StringPiece& piece);
重载<<方便打印和日志输出
5. 源码
6. 参考
http://qianchenglong.github.io/2016/05/28/C++-StringPiece/
https://blog.csdn.net/q5707802/article/details/78420629
POD类型参考https://zhuanlan.zhihu.com/p/45545035