目标:
1.string接口纯虚函数类StringInterface;
2.我的ubuntu上string实现重写(但不包括写时复制);
3.一种支持小字符串优化的实现;
4.基于StringInterface的多态测试case集合;
6.多场景性能分析。
当前时间不太够,只差不多完成了1\2,先放到博客备忘,之后补上。
string_interface.h
//#define MYCODE_TEST_MODE 1
#ifndef MYCODE_STRING_INTERFACE_H
#include <cstddef>
namespace mycode{
//缺点:用全部纯虚的interface不是好事,造成了string的各种实现的对应函数也是虚的,而实际上string的各种实现不应该有子类了,所以对于string指针或引用的函数调用运行时查虚函数表是不必要的浪费。
//优点:用interface可以使得接口统一且没有遗漏,并且通过多态进行测试也比较方便
//实现可以不继承全部接口,也可以继承,可以用一个定义开关MYCODE_TEST_MODE控制
//限定符,最好都加,1.简单的文档;2.防止错误的调用;3.编译器可能的优化;4.库可能的优化;5.编译器警告。这些里面1最重要。
//线程安全不考虑,异常安全按注释,提供基本及以上保证。
class StringInterface{
public:
static const size_t nopos = (size_t)-1;
//迭代器,假设实现全是用连续内存实现的,这样"迭代器"生成比较方便,因为迭代器兼容指针并且当作最高级的迭代器(random)
//“长度类”接口
//位置相关函数
//操作相关
//操作符重载
//std::swap也需要加特化版本
//改变类
//析构函数
//此外,拷贝构造函数、右值拷贝构造函数,左右值赋值操作符;友元函数的输入输出也应该实现;这些貌似没法纯虚了。
//除了这个VIRTUAL StringInterface substr(size_t pos,size_t len) const noexcept(false) PUREVIRTUAL;其他还是能实现。
#define MYCODE_STRING_INTERFACE \
VIRTUAL char *begin() noexcept PUREVIRTUAL; \
VIRTUAL char *end() noexcept PUREVIRTUAL; \
VIRTUAL const char *cbegin() const noexcept PUREVIRTUAL; \
VIRTUAL const char *cend() const noexcept PUREVIRTUAL; \
\
VIRTUAL size_t size() const noexcept PUREVIRTUAL; \
VIRTUAL size_t capacity() const noexcept PUREVIRTUAL; \
VIRTUAL void resize(size_t) noexcept(false) PUREVIRTUAL; \
VIRTUAL bool empty() const noexcept PUREVIRTUAL; \
VIRTUAL void reserve(size_t) noexcept(false) PUREVIRTUAL; \
VIRTUAL void shrink_to_fit() noexcept(false) PUREVIRTUAL; \
\
VIRTUAL char &operator[](size_t pos) noexcept(false) PUREVIRTUAL; \
VIRTUAL const char &operator[](size_t pos) const noexcept(false) PUREVIRTUAL; \
VIRTUAL char &back() noexcept(false) PUREVIRTUAL; \
VIRTUAL const char &back() const noexcept(false) PUREVIRTUAL; \
\
VIRTUAL size_t find_first_of(char c) const noexcept PUREVIRTUAL; \
VIRTUAL const char *c_str() const noexcept PUREVIRTUAL; \
VIRTUAL int compare(const StringInterface &si) const noexcept PUREVIRTUAL; \
VIRTUAL size_t find(const StringInterface &si) const noexcept PUREVIRTUAL; \
\
VIRTUAL bool operator==(const StringInterface &lhs) const noexcept PUREVIRTUAL; \
VIRTUAL bool operator<(const StringInterface &lhs) const noexcept PUREVIRTUAL; \
VIRTUAL bool operator>(const StringInterface &lhs) const noexcept PUREVIRTUAL; \
VIRTUAL bool operator!=(const StringInterface &lhs) const noexcept PUREVIRTUAL; \
VIRTUAL void swap(StringInterface &lhs) noexcept PUREVIRTUAL; \
\
VIRTUAL void push_back(char c) noexcept(false) PUREVIRTUAL; \
VIRTUAL void pop_back() noexcept PUREVIRTUAL; \
VIRTUAL void insert(size_t pos,char c) noexcept(false) PUREVIRTUAL; \
VIRTUAL void erase(size_t pos) noexcept(false) PUREVIRTUAL;
#ifdef MYCODE_TEST_MODE
#define VIRTUAL virtual
#define PUREVIRTUAL = 0
public:
MYCODE_STRING_INTERFACE
VIRTUAL ~StringInterface() noexcept {};
#undef VIRTUAL
#undef PUREVIRTUAL
#endif
#define VIRTUAL
#define PUREVIRTUAL
};
}
#define MYCODE_STRING_INTERFACE_H
#endif
ubuntu_string.h
#include <iostream>
#include <stdexcept>
#include "string_interface.h"
namespace mycode{
//我的ubuntu上的string类似实现
//不支持小string优化,string占用最小栈空间和写时复制
class UbuntuString : public StringInterface{
public:
UbuntuString() noexcept = default;
UbuntuString(const UbuntuString &us) noexcept(false);
UbuntuString(const char *,size_t) noexcept(false);
//按effective c++说法,这个noexcept很重要
UbuntuString(UbuntuString &&us) noexcept;
UbuntuString &operator=(const UbuntuString &lhs);
UbuntuString &operator=(UbuntuString &&lhs) noexcept;
~UbuntuString() noexcept;
//头文件慎用命名空间,cpp文件无所谓
friend std::istream& operator<<(UbuntuString &us,std::istream &is);
friend std::ostream& operator<<(std::ostream &os,const UbuntuString &us);
//公共接口
MYCODE_STRING_INTERFACE
UbuntuString substr(size_t pos,size_t len) const noexcept(false);
private:
char *_ps = NULL;
};
}
ubuntu_string.cpp
#include "ubuntu_string.h"
#include <cstddef>
#include <cstring>
//暂不实现写时复制
namespace mycode{
typedef struct{
size_t len;
size_t max;
size_t refCount;
} StringHeader;
//没有判断ps==NULL,由调用时保证
static inline StringHeader *getSH(const char *ps) noexcept {
return reinterpret_cast<StringHeader *>(reinterpret_cast<StringHeader *>(const_cast<char *>(ps)) - 1);
}
static char *newSH(const char *ps,size_t size) noexcept(false) {
char *nps = new char[size + sizeof(StringHeader) + 1]; //new失败的异常直接抛bad_allocate到外界,期望调用者能根据接口noexcept指示符自行处理,+1是要兼容c风格字符串,即c_str的返回
StringHeader *psh = getSH(nps);
psh->max = size;
psh->refCount = 1;
if(ps == NULL || size == 0)
psh->len = 0;
else{
int len = (size > getSH(ps)->len)?getSH(ps)->len:size;
memcpy(nps,ps,len);
*(nps + len + 1) = 0;
psh->len = len;
}
return nps;
}
//只增不减,除了isShrink时(一般不会调用)
static char *resizeSH(char *ps,size_t size,bool isShrink = false) noexcept(false) {
char *nps;
if(ps == NULL || getSH(ps)->max < size || isShrink){
nps = newSH(ps,size);
if(ps != NULL)
delete [] ps;
ps = nps;
}
if(getSH(ps)->len > size){
getSH(ps)->len = size;
ps[size] = 0;
}
}
//同下都是inline的好材料,但是为了隐藏实现细节还是选择放cpp里面了,不过貌似可以本编译单元inline
inline size_t UbuntuString::size() const noexcept {
if(_ps == NULL)
return 0;
return getSH(_ps)->len;
}
inline size_t UbuntuString::capacity() const noexcept {
if(_ps == NULL)
return 0;
return getSH(_ps)->max;
}
void UbuntuString::reserve(size_t size) noexcept(false) {
_ps = resizeSH(_ps,size);
}
void UbuntuString::resize(size_t size) noexcept(false) {
if(_ps == NULL || getSH(_ps)->len < size)
return;
getSH(_ps)->len = size;
_ps[size] = 0;
}
inline bool UbuntuString::empty() const noexcept {
return size() == 0;
}
void UbuntuString::shrink_to_fit() noexcept(false) {
if(empty())
return;
_ps = resizeSH(_ps,size(),true);
}
const char *UbuntuString::cbegin() const noexcept {
if(empty())
return NULL;
return _ps;
}
const char *UbuntuString::cend() const noexcept {
if(empty())
return NULL;
return _ps + size();
}
//用const版本实现非const版本,effective c++推荐
char *UbuntuString::begin() noexcept {
return const_cast<char *>(cbegin());
}
char *UbuntuString::end() noexcept {
return const_cast<char *>(cend());
}
const char &UbuntuString::operator[](size_t pos) const noexcept(false) {
if(pos >= size())
throw std::out_of_range("pos is not valid");
return _ps[pos - 1];
}
char &UbuntuString::operator[](size_t pos) noexcept(false) {
return const_cast<char &>((static_cast<const UbuntuString *>(this))->operator[](pos));
}
const char &UbuntuString::back() const noexcept(false) {
if(size() == 0)
throw std::out_of_range("string is empty");
return _ps[size() - 1];
}
char &UbuntuString::back() noexcept(false) {
return const_cast<char &>((static_cast<const UbuntuString *>(this))->back());
}
size_t UbuntuString::find_first_of(char c) const noexcept {
if(empty())
return nopos;
//可以用strchr,这里还是自己实现
char *ptemp = _ps;
while(*ptemp != 0 && *ptemp != c)
ptemp++;
if(*ptemp)
return ptemp - _ps;
return nopos;
}
UbuntuString::UbuntuString(const char *ps,size_t size) noexcept(false) {
if(ps == NULL || *ps == 0)
_ps = 0;
_ps = newSH(ps,size);
}
const char *UbuntuString::c_str() const noexcept {
return _ps;
}
UbuntuString UbuntuString::substr(size_t pos,size_t len) const noexcept(false) {
if(len == 0 || pos >= size() )
return UbuntuString();
return UbuntuString(_ps + pos,(len > (size() - pos))?(size() - pos):len);
}
//可以和任意支持c_str的StringInterface的实现比较
int UbuntuString::compare(const StringInterface &si) const noexcept {
return strcmp(_ps,si.c_str();
}
UbuntuString::UbuntuString(const UbuntuString &us) noexcept(false) {
}
}