简单的string实现

最近因为某些原因,迫不得已封装了个String,实现了写时复制,自动释放等功能,贴出来分享下。

String.h

#ifndef STRING_H
#define STRING_H

class String {
private:
	struct MetaStr {
		char* str;
		unsigned refCount;
	};
	void addRefCount();
	void decRefCount();
private:
	MetaStr* mstrobj;

	void create(const char*);
	void destroy();
	void replace(const String&);
	void replace(const char*);
public:
	String();
	String(const char*);
	String(const String&);
	~String();

	String& operator=(const char*);
	String& operator=(const String&);

	void operator+=(const char*);
	void operator+=(const String&);

	String operator+(const char*);
	String operator+(const String&);

	bool operator>(const char*) const;
	bool operator>(const String&) const;

	bool operator>=(const char*) const;
	bool operator>=(const String&) const;

	bool operator<(const char*) const;
	bool operator<(const String&) const;

	bool operator<=(const char*) const;
	bool operator<=(const String&) const;

	bool operator==(const char*) const;
	bool operator==(const String&) const;

	operator const char*();

	char charAt(int);
	size_t length() const;
	bool startsWith(const char*);
	bool startsWith(const String&);
	bool endsWith(const char*);
	bool endsWith(const String&);
	String subString(int);
	String subString(int, int);

	int indexOf(char);
	int indexOf(const char*);
	int indexOf(const String&);

	//int lastIndexOf(char);
	//int lastIndexOf(const char*);
	//int lastIndexOf(const String&);

	bool isEmpty();

	String toLowerCase();
	String toUpperCase();
	const char* toCStr();
};

#endif //STRING_H

String.h

#include <string.h>
#include <stdlib.h>

#include "string.h"

// Function of MetaStr
void String::addRefCount() { ++mstrobj->refCount; }
void String::decRefCount() { --mstrobj->refCount; }

void String::create(const char* str) {
	this->mstrobj = (MetaStr*)malloc(sizeof(MetaStr));
	mstrobj->refCount = 1;
	mstrobj->str = strdup(str);
}
void String::destroy() {
	if(mstrobj == NULL) return;
	if(mstrobj->refCount == 1) {
		if(mstrobj->str != NULL) free(mstrobj->str);
		free(mstrobj);
	} else {
		decRefCount();
		this->mstrobj = NULL;
	}
}
void String::replace(const String& obj) {
	destroy();
	this->mstrobj = obj.mstrobj;
	addRefCount();
}
void String::replace(const char* str) {
	destroy();
	create(str);
}

String::String(): mstrobj(NULL) {}
String::String(const char* str) { create(str); }
String::String(const String& obj): mstrobj(NULL) { replace(obj); }
String::~String() {	destroy(); }

String& String::operator=(const char* str) { replace(str); }
String& String::operator=(const String& obj) { replace(obj); }

void String::operator+=(const char* str) {
	int len = length() + strlen(str) + 1;
	char* temp = (char*)malloc(len);
	*temp = '\0';
	strcat(temp, mstrobj->str);
	strcat(temp, str);

	destroy();

	this->mstrobj = (MetaStr*)malloc(sizeof(MetaStr));
	mstrobj->str = temp;
	mstrobj->refCount = 1;
}
void String::operator+=(const String& obj) {
	int len = length() + obj.length() + 1;
	char* temp = (char*)malloc(len);
	*temp = '\0';
	strcat(temp, mstrobj->str);
	strcat(temp, obj.mstrobj->str);

	destroy();

	this->mstrobj = (MetaStr*)malloc(sizeof(MetaStr));
	mstrobj->str = temp;
	mstrobj->refCount = 1;
}
String String::operator+(const char* str) {
	int len = length() + strlen(str) + 1;
	char* temp = (char*)malloc(len);
	*temp = '\0';
	strcat(temp, mstrobj->str);
	strcat(temp, str);

	String res;
	res.mstrobj = (MetaStr*)malloc(sizeof(MetaStr));
	res.mstrobj->str = temp;
	res.mstrobj->refCount = 1;

	return res;
}
String String::operator+(const String& obj) {
	int len = length() + obj.length() + 1;
	char* temp = (char*)malloc(len);
	*temp = '\0';
	strcat(temp, mstrobj->str);
	strcat(temp, obj.mstrobj->str);

	String res;
	res.mstrobj = (MetaStr*)malloc(sizeof(MetaStr));
	res.mstrobj->str = temp;
	res.mstrobj->refCount = 1;

	return res;
}
bool String::operator>(const char* str) const {
	return strcmp(mstrobj->str, str) > 0;
}
bool String::operator>(const String& obj) const {
	return strcmp(mstrobj->str, obj.mstrobj->str) > 0;
}
bool String::operator>=(const char* str) const {
	return strcmp(mstrobj->str, str) >= 0;
}
bool String::operator>=(const String& obj) const {
	return strcmp(mstrobj->str, obj.mstrobj->str) >= 0;
}
bool String::operator<(const char* str) const {
	return strcmp(mstrobj->str, str) < 0;
}
bool String::operator<(const String& obj) const {
	return strcmp(mstrobj->str, obj.mstrobj->str) < 0;
}
bool String::operator<=(const char* str) const {
	return strcmp(mstrobj->str, str) <= 0;
}
bool String::operator<=(const String& obj) const {
	return strcmp(mstrobj->str, obj.mstrobj->str) <= 0;
}
bool String::operator==(const char* str) const {
	return strcmp(mstrobj->str, str) == 0;
}
bool String::operator==(const String& obj) const {
	return strcmp(mstrobj->str, obj.mstrobj->str) == 0;
}
String::operator const char*() {
	return mstrobj->str;
}

String String::subString(int begin) {
	//TODO: add exception
	return mstrobj->str + begin;
}
String String::subString(int begin, int len) {
	//TODO: add exception
	String res;
	// need one byte to store the '\0'
	res.mstrobj = (MetaStr*)malloc(sizeof(MetaStr));
	res.mstrobj->str = (char*)malloc(len + 1);
	res.mstrobj->refCount = 1;
	strncpy(res.mstrobj->str, mstrobj->str + begin, len);
	res.mstrobj->str[len] = '\0';
	return res;
}

char String::charAt(int index) {
	//TODO: add exception
	return mstrobj->str[index];
}
size_t String::length() const {
	return strlen(mstrobj->str);
}

bool String::startsWith(const char* str) {
	int len = strlen(str);
	if(len > length())
		return false;
	if(strncmp(mstrobj->str, str, len) == 0)
		return true;
	else
		return false;
}
bool String::startsWith(const String& obj) {
	int len = obj.length();
	if(len > length())
		return false;
	if(strncmp(mstrobj->str, obj.mstrobj->str, len)== 0)
		return true;
	else
		return false;
}

bool String::endsWith(const char* str) {
	int len = strlen(str);
	int localLen = length();
	if(len > localLen)
		return false;
	if(strncmp(mstrobj->str + localLen - len, str, len) == 0)
		return true;
	else
		return false;
}
bool String::endsWith(const String& obj) {
	int len = obj.length();
	int localLen = length();
	if(len > localLen)
		return false;
	if(strncmp(mstrobj->str + localLen - len, obj.mstrobj->str, len) == 0)
		return true;
	else
		return false;
}

bool String::isEmpty() {
	//TODO: add exception
	return length() == 0;
}
String String::toLowerCase() {
	int len = length();
	String res;
	res.mstrobj = (MetaStr*)malloc(sizeof(MetaStr));
	res.mstrobj->str = (char*)malloc(len + 1);
	res.mstrobj->refCount = 1;
	int offset = 'A' - 'a';
	for(char* ps = mstrobj->str, *pd = res.mstrobj->str; *ps != '\0'; ++ps, ++ pd) {
		if(*ps >= 'A' && *ps <= 'Z')
			*pd = *ps - offset;
		else
			*pd = *ps;
	}
	res.mstrobj->str[len] = '\0';

	return res;
}
String String::toUpperCase() {
	int len = length();
	String res;
	res.mstrobj = (MetaStr*)malloc(sizeof(MetaStr));
	res.mstrobj->str = (char*)malloc(len + 1);
	res.mstrobj->refCount = 1;
	int offset = 'A' - 'a';
	for(char* ps = mstrobj->str, *pd = res.mstrobj->str; *ps != '\0'; ++ps, ++ pd) {
		if(*ps >= 'a' && *ps <= 'z')
			*pd = *ps + offset;
		else
			*pd = *ps;
	}
	res.mstrobj->str[len] = '\0';

	return res;

}

const char* String::toCStr() {
	return mstrobj->str;
}

int String::indexOf(char ch) {
	char* p = strchr(mstrobj->str, ch);
	if(p != NULL)
		return p - mstrobj->str;
	else
		return -1;
}
int String::indexOf(const char* str) {
	char* p = strstr(mstrobj->str, str);
	if(p != NULL)
		return p - mstrobj->str;
	else
		return -1;

}
int String::indexOf(const String& obj) {
	char* p = strstr(mstrobj->str, obj.mstrobj->str);
	if(p != NULL)
		return p - mstrobj->str;
	else
		return -1;
}

//int String::lastIndexOf(char ch) {
//	char* p = strrchr(mstrobj->str, ch);
//	if(p != NULL)
//		return p - mstrobj->str;
//	else
//		return -1;
//}
//int String::lastIndexOf(const char* str) {
//
//}
//int String::lastIndexOf(const String& obj) {
//
//}

单元测试

#include <gtest/gtest.h>
#include "string.h"

TEST(String, testConstructor) {
	String str1 = "test";
	String str2 = str1;
	ASSERT_EQ(str1, str2);
	ASSERT_EQ(str1, "test");
}
TEST(String, testAssign) {
	String str1 = "proto";
	str1 = "codesun";
	ASSERT_EQ(str1, "codesun");
	String str2 = "proto";
	str1 = str2;
	ASSERT_EQ(str1, "proto");
}
TEST(String, testAppend) {
	String str1 = "code";
	String str2;
	str2= str1 + "sun";
	String str3 = "sun";
	String str4 = str1 + str3;
	ASSERT_TRUE(str2=="codesun");
	ASSERT_TRUE(str4=="codesun");
	ASSERT_EQ(str2, str4);
}
TEST(String, testAppendAssign) {
	String str1 = "code";
	String str2 = "sun";
	str1 += str2;
	ASSERT_EQ(str1, "codesun");
	str1 += "hello";
	ASSERT_EQ(str1, "codesunhello");
}
TEST(String, testBiggerThen) {
	String str1 = "code";
	String str2 = "sun";
	ASSERT_FALSE(str1 > str2);
	ASSERT_FALSE(str1 > "sun");
	String str3 = "code";
	ASSERT_FALSE(str1 > str3);
	ASSERT_FALSE(str1 > "code");
	String str4 = "ab";
	ASSERT_TRUE(str1 > str4);
	ASSERT_TRUE(str1 > "ab");
}
TEST(String, testBiggerOrEqualThen) {
	String str1 = "code";
	String str2 = "sun";
	ASSERT_FALSE(str1 >= str2);
	ASSERT_FALSE(str1 >= "sun");
	String str3 = "code";
	ASSERT_TRUE(str1 >= str3);
	ASSERT_TRUE(str1 >= "code");
	String str4 = "ab";
	ASSERT_TRUE(str1 >= str4);
	ASSERT_TRUE(str1 >= "ab");
}
TEST(String, testSmallerThen) {
	String str1 = "code";
	String str2 = "sun";
	ASSERT_TRUE(str1 < str2);
	ASSERT_TRUE(str1 < "sun");
	String str3 = "code";
	ASSERT_FALSE(str1 < str3);
	ASSERT_FALSE(str1 < "code");
	String str4 = "ab";
	ASSERT_FALSE(str1 < str4);
	ASSERT_FALSE(str1 < "ab");
}
TEST(String, testSmallerOrEqualThen) {
	String str1 = "code";
	String str2 = "sun";
	ASSERT_TRUE(str1 <= str2);
	ASSERT_TRUE(str1 <= "sun");
	String str3 = "code";
	ASSERT_TRUE(str1 <= str3);
	ASSERT_TRUE(str1 <= "code");
	String str4 = "ab";
	ASSERT_FALSE(str1 <= str4);
	ASSERT_FALSE(str1 <= "ab");
}
TEST(String, testEqual) {
	String str1 = "code";
	String str2 = "sun";
	String str3 = "code";
	ASSERT_TRUE(str1 == str3);
	ASSERT_TRUE(str1 == "code");
	ASSERT_FALSE(str1 == str2);
	ASSERT_FALSE(str1 == "sun");
}
TEST(String, testConvert) {
	String str1 = "codesun";
	ASSERT_STREQ(str1, "codesun");
	ASSERT_STREQ(str1.operator const char*(), "codesun");
}
TEST(String, testCharAt) {
	String str = "codesun";
	ASSERT_EQ(str.charAt(0), 'c');
	ASSERT_EQ(str.charAt(2), 'd');
	ASSERT_EQ(str.charAt(4), 's');
	ASSERT_EQ(str.charAt(6), 'n');
	ASSERT_EQ(str.charAt(7), '\0');
}
TEST(String, testLength) {
	String str = "codesun";
	ASSERT_EQ(str.length(), 7);
}
TEST(String, testStartsWith) {
	String str = "codesun";
	String str1 = "code";
	String str2 = "sun";
	String str3 = "codesun";
	String str4 = "codesunh";
	ASSERT_TRUE(str.startsWith(str1));
	ASSERT_TRUE(str.startsWith("code"));
	ASSERT_TRUE(str.startsWith(str3));
	ASSERT_TRUE(str.startsWith("codesun"));
	ASSERT_FALSE(str.startsWith(str2));
	ASSERT_FALSE(str.startsWith("sun"));
	ASSERT_FALSE(str.startsWith(str4));
	ASSERT_FALSE(str.startsWith("codesunh"));
}
TEST(String, testEndsWith) {
	String str = "codesun";
	String str1 = "code";
	String str2 = "sun";
	String str3 = "codesun";
	String str4 = "hcodesun";
	ASSERT_TRUE(str.endsWith(str2));
	ASSERT_TRUE(str.endsWith("sun"));
	ASSERT_TRUE(str.endsWith(str3));
	ASSERT_TRUE(str.endsWith("codesun"));
	ASSERT_FALSE(str.endsWith(str1));
	ASSERT_FALSE(str.endsWith("code"));
	ASSERT_FALSE(str.endsWith(str4));
	ASSERT_FALSE(str.endsWith("hcodesun"));
}
TEST(String, testSubString) {
	String str = "codesun";
	ASSERT_STREQ(str.subString(2), "desun");
	ASSERT_STREQ(str.subString(4, 3), "sun");
}
TEST(String, testIndexOf) {
	String str = "codesun";
	ASSERT_EQ(str.indexOf('s'), 4);
	ASSERT_EQ(str.indexOf('x'), -1);
	ASSERT_EQ(str.indexOf("sun"), 4);
	ASSERT_EQ(str.indexOf("xun"), -1);
	String str1 = "sun";
	String str2 = "xun";
	ASSERT_EQ(str.indexOf(str1), 4);
	ASSERT_EQ(str.indexOf(str2), -1);
}
TEST(String, testIsEmpty) {
	String str = "";
	ASSERT_TRUE(str.isEmpty());
	str = "codeusn";
	ASSERT_FALSE(str.isEmpty());
}
TEST(String, testToLowerCase) {
	String str = "CoDe@SuN-HeLlO";
	ASSERT_STREQ(str.toLowerCase(), "code@sun-hello");
}
TEST(String, testToUpperCase) {
	String str = "CoDe@SuN-HeLlO";
	ASSERT_STREQ(str.toUpperCase(), "CODE@SUN-HELLO");
}
TEST(String, testToCStr) {
	String str1 = "codesun";
	ASSERT_STREQ(str1.toCStr(), "codesun");
}


转载于:https://my.oschina.net/codeaxe/blog/284402

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值