13.5 String的实现以及章节总结
String class:String.h#include <iostream>#include <memory>#include <string>class String {public:String();String(const char *);String(const String &);Str...
·
String class:
String.h
#pragma once
#include <iostream>
#include <memory>
#include <string>
class String {
public:
String();
String(const char *);
String(const String &);
String(const std::string &);
String(String &&) noexcept;
String &operator=(String &&) noexcept;
~String();
String &operator=(const String &);
char &operator[](const size_t n);
const char &operator[](const size_t n) const;
std::string to_string() const;
friend std::ostream &operator<<(std::ostream &os, String s);
friend bool operator==(const String &, const String &);
private:
std::pair<char *, char *>
alloc_n_copy(char *, char *);
void free();
static std::allocator<char> alloc;
char *beg;
char *end;
size_t length;
};
String.cpp
#include <cstring>
#include "String.h"
std::allocator<char> String::alloc = std::allocator<char>();
String::String()
: beg(nullptr), end(nullptr), length(0) {}
String::String(const char *ptr) {
std::cout << "Const char constructor execute" << std::endl;
length = strlen(ptr);
beg = alloc.allocate(length);
end = std::uninitialized_copy(ptr, ptr + length, beg);
}
String::String(const std::string &s) {
std::cout << "Const string constructor execute" << std::endl;
length = s.size();
beg = alloc.allocate(length);
end = std::uninitialized_copy(s.begin(), s.end(), beg);
}
String::String(const String &s) {
std::cout << "Copy constructor execute" << std::endl;
beg = alloc.allocate(s.length);
end = std::uninitialized_copy(s.beg, s.end, beg);
}
std::pair<char *, char *>
String::alloc_n_copy(char *beg, char *end) {
auto newBeg = alloc.allocate(end - beg);
return{ newBeg, std::uninitialized_copy(beg, end, newBeg) };
}
String &String::operator=(const String &s) {
auto newStr = alloc_n_copy(s.beg, s.end);
free();
beg = newStr.first;
end = newStr.second;
length = s.length;
return *this;
}
String::String(String &&s) noexcept : beg(s.beg), end(s.end), length(s.length) {
std::cout << "Move constructor execute" << std::endl;
s.beg = s.end = nullptr;
s.length = 0;
}
String &String::operator=(String &&s) noexcept {
if (this != &s) {
beg = s.beg;
end = s.end;
length = s.length;
s.beg = s.end = nullptr;
s.length = 0;
}
return *this;
}
char &String::operator[](const size_t n) {
return beg[n];
}
const char &operator[](const size_t n) const {
return beg[n];
}
void String::free() {
while (beg >= end) {
alloc.destroy(end--);
}
alloc.deallocate(beg, length);
}
String::~String() {
free();
}
std::string String::to_string() const {
std::string s(beg);
return s;
}
bool operator==(const String &lhs, const String &rhs) {
bool equal = true;
if (lhs.length != rhs.length) {
equal = false;
} else {
for (size_t i = 0; i < length; i++) {
if (lhs.beg[i] != rhs.beg[i]) {
equal = false;
break;
}
}
}
return equal;
}
std::ostream &operator<<(std::ostream &os, String s) {
std::string str(s.beg);
os << str;
return os;
}
StrVec class:
StrVec.h
#pragma once
#include "String.h"
#include <memory>
class StrVec
{
public:
StrVec();
StrVec(const StrVec &);
StrVec(const std::initializer_list<String> &);
StrVec &operator=(const StrVec &);
StrVec &operator=(const std::initializer_list<String> &);
~StrVec();
void push_back(const String &s);
size_t size() const;
size_t capacity() const;
String *begin() const;
String *end() const;
void reserve(size_t n);
void resize(size_t n, const String &s = String());
bool empty() {return size();}
void pop_back();
String &front();
String &back();
const String &operator[](const size_t) const;
String &operator[](const size_t);
friend bool operator==(const StrVec &, const StrVec &);
private:
void check_volume();
void reallocate();
void free();
std::pair<String *, String *>
alloc_n_copy(const String *, const String *);
String *elements;
String *first_free;
String *cap;
static std::allocator<String> alloc;
};
StrVec.cpp
#include <vector>
#include "StrVec.h"
std::allocator<String> StrVec::alloc = std::allocator<String>();
StrVec::StrVec()
: elements(nullptr), first_free(nullptr), cap(nullptr) {}
StrVec::StrVec(const StrVec &s) {
auto newBegin = alloc_n_copy(s.begin(), s.end());
elements = newBegin.first;
cap = first_free = newBegin.second;
}
StrVec::StrVec(std::initializer_list<String> &li) {
std::vector<String> tmp(li);
size_t size = li.size();
elements = alloc.allocate(size);
first_free = elements;
for (size_t i = 0; i < size; ++i) {
alloc.construct(first_free++, tmp[i]);
}
cap = elements + size;
}
StrVec &StrVec::operator=(const StrVec &rhs) {
auto newBegin = alloc_n_copy(rhs.begin(), rhs.end());
free();
elements = newBegin.first;
cap = first_free = newBegin.second;
return *this;
}
StrVec &StrVec::operator=(const std::initializer_list<String> &li) {
auto newBeg = alloc_n_copy(li.begin(), li.end());
free();
elements = newBegin.first;
cap = first_free = newBegin.second;
return *this;
}
StrVec::~StrVec() {
free();
}
std::pair<String *, String *>
StrVec::alloc_n_copy(const String *b, const String *e) {
auto newMem = alloc.allocate(e - b);
return{ newMem, std::uninitialized_copy(b, e, newMem) };
}
void StrVec::reallocate() {
size_t newSize = size() ? 2 * size() : 1;
auto newBegin = alloc.allocate(newSize);
auto newPos = newBegin;
auto oldBegin = elements;
for (size_t i = 0; i < size(); ++i) {
alloc.construct(newPos++, std::move(*oldBegin++));
}
free();
elements = newBegin;
first_free = newPos;
cap = newBegin + newSize;
}
size_t StrVec::size() const {
return first_free - elements;
}
size_t StrVec::capacity() const {
return cap - elements;
}
void StrVec::push_back(const String &s) {
check_volume();
alloc.construct(first_free++, s);
}
String *StrVec::begin() const {
return elements;
}
String *StrVec::end() const {
return first_free;
}
void StrVec::check_volume() {
if (size() == capacity()) reallocate();
}
void StrVec::free() {
if (elements) {
for (auto p = first_free; p != elements;) {
alloc.destroy(--p);
}
alloc.deallocate(elements, cap - elements);
}
}
void StrVec::reserve(size_t n) {
if (n > size()) {
String *newBegin = alloc.allocate(n);
String *new_first_free = std::uninitialized_copy(begin(), end(), newBegin);
free();
first_free = new_first_free;
elements = newBegin;
cap = newBegin + n;
}
}
void StrVec::resize(size_t n, const String &s) {
String *newBegin = alloc.allocate(n);
String *new_first_free = nullptr;
if (n > size()) {
auto p = std::uninitialized_copy(begin(), end(), newBegin);
for (size_t i = 0; i < n - size(); ++i) {
alloc.construct(p++, s);
}
new_first_free = p;
} else {
new_first_free = std::uninitialized_copy(begin(), begin() + n, newBegin);
}
first_free = new_first_free;
elements = newBegin;
cap = newBegin + n;
}
void StrVec::pop_back() {
alloc.destroy(--first_free);
}
String & StrVec::front() {
return *begin();
}
String & StrVec::back() {
return *end();
}
String &StrVec::operator[](const size_t n) {
return element[n];
}
const String &StrVec::operator[](const size_t n) const {
return element[n];
}
bool operator==(const StrVec &lhs, const StrVec &rhs) {
bool equal = true;
if (lhs.size() != rhs.size()) {
equal = false;
} else {
for (size_t i = 0; i < lhs.size(); ++i) {
if (lhs[i] != rhs[i]) {
equal = false;
break;
}
}
return equal;
}
StrBlob class:
StrBlob.h
#pragma once
#include <iostream>
#include <vector>
#include <string>
#include <memory>
#include "StrVec.h"
class StrBlobPtr;
class StrBlob {
friend class StrBlobPtr;
public:
typedef std::vector<String>::size_type size_type;
StrBlob();
StrBlob(std::initializer_list<String> il);
size_type size() { return data->size(); }
const size_type size() const { return data->size(); }
bool empty() { return data->empty(); }
void push_back(const String &s) { data->push_back(s); }
void pop_back();
String& front();
const String& front() const;
String& back();
const String& back() const;
StrBlobPtr begin(); // 不建议将实现写在此处,会造成"incomplete type is not allowed" error
StrBlobPtr end();
StrBlobPtr off(size_t);
String &operator[](const size_t n);
const String &operator[](const size_t n) const;
friend bool operator==(const StrBlob &, const StrBlob &);
private:
std::shared_ptr<StrVec> data;
void check(size_type i, const String &msg) const;
};
StrBlob.cpp
#include <stdexcept> // out_of_range
#include "StrBlob.h"
#include "StrBlobPtr.h"
#include "StrVec.h"
StrBlob::StrBlob() {
data = std::make_shared<StrVec>();
}
StrBlob::StrBlob(std::initializer_list<String> il) {
data = std::make_shared<StrVec>(il);
}
void StrBlob::check(size_type i, const String &msg) const {
if (i >= data->size()) {
std::string message = msg.to_string();
throw std::out_of_range(message);
}
}
void StrBlob::pop_back() {
check(0, "pop_back on empty StrBlob");
data->pop_back();
}
String& StrBlob::front() {
check(0, "front on empty StrBlob");
return data->front();
}
const String& StrBlob::front() const {
check(0, "front on empty StrBlob");
return data->front();
}
String& StrBlob::back() {
check(0, "back on empty StrBlob");
return data->back();
}
const String& StrBlob::back() const {
check(0, "back on empty StrBlob");
return data->back();
}
StrBlobPtr StrBlob::begin() { return StrBlobPtr(*this); }
StrBlobPtr StrBlob::end() { return StrBlobPtr(*this, data->size()); }
StrBlobPtr StrBlob::off(size_t i) { return StrBlobPtr(*this, i); }
String &StrBlob::operator[](const size_t n) {
return data[n];
}
const String &StrBlob::operator[](const size_t n) const {
return data[n];
}
bool operator==(const StrBlob &lhs, const StrBlob &rhs) {
return *lhs.data == *rhs.data;
}
StrBlobPtr class
StrBlobPtr.h
#pragma once
#include <memory>
#include <vector>
#include "StrBlob.h" // 有#program once的存在,不用担心重复定义的问题
#include "StrVec.h"
class StrBlobPtr
{
public:
StrBlobPtr():curr{0}{}
StrBlobPtr(StrBlob &a, size_t sz = 0)
: wptr(a.data), curr(sz){}
~StrBlobPtr() {};
String &deref() const;
StrBlobPtr &incr();
String &operator[](const size_t n);
const String &operator[](const size_t n) const;
StrBlobPtr &operator++();
StrBlobPtr &operator++(int);
StrBlobPtr &operator--();
StrBlobPtr &operator--(int);
StrBlobPtr &operator+(size_t n);
StrBlobPtr &operator-(size_t n);
String &operator*();
Stirng *operator->();
friend bool operator==(const StrBlobPtr &lhs, const StrBlobPtr &rhs);
private:
std::shared_ptr<StrVec> check(std::size_t, const String&) const;
std::weak_ptr<StrVec> wptr;
std::size_t curr;
};
StrBlobPtr.cpp
#include "StrBlobPtr.h"
#include <exception>
String & StrBlobPtr::deref() const {
auto p = check(curr, "Dereference past the end");
return (*p)[curr];
}
StrBlobPtr & StrBlobPtr::incr() {
check(curr, "Increment past the end");
++curr;
return *this;
}
std::shared_ptr<StrVec> StrBlobPtr::check(std::size_t sz, const String &msg) const {
auto p = wptr.lock();
if (p) {
if (p->size() > sz) {
return p;
}
else {
std::string message = msg.to_string();
throw std::out_of_range(message);
}
}
else {
throw std::runtime_error("unbound StrBlobPtr");
}
return p;
}
String &StrBlobPtr::operator[](const size_t n) {
return wptr[n];
}
const String &StrBlobPtr::operator[](const size_t n) const {
return wptr[n];
}
StrBlobPtr &StrBlobPtr::operator++() {
check(curr, "pass the end");
++curr;
return *this;
}
StrBlobPtr &StrBlobPtr::operator++(int) {
StrBlobPtr ret(*this);
++(*this);
return ret;
}
StrBlobPtr &StrBlobPtr::operator--() {
check(curr - 1, "pass the begin");
--curr;
return *this;
}
StrBlobPtr &StrBlobPtr::operator--(int) {
StrBlobPtr ret(*this);
--*this;
return ret;
}
StrBlobPtr &StrBlobPtr::operator+(size_t n) {
check(curr + n, "pass the end");
curr += n;
return *this;
}
StrBlobPtr &StrBlobPtr::operator-(size_t n) {
check(curr - n, "pass the begin");
curr -= n;
return *this;
}
String &StrBlobPtr::operator*() {
auto p = check(curr, "pass the end");
return (*p)[curr];
}
Stirng *StrBlobPtr::operator->() {
return &(*p)[curr];
}
bool operator==(const StrBlobPtr &lhs, const StrBlobPtr &rhs) {
auto lp = lhs.wptr.lock(), rp = rhs.wptr.lock();
if (lp == rp) {
return (!lp || lhs.curr == rhs.curr);
}
else {
return false;
}
}
TextQuery class:
TextQuery.h
#pragma once
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <memory>
#include "QueryResult.h"
#include "StrBlob.h"
using namespace std;
class QueryResult;
class TextQuery {
public:
using line_no = vector<string>::size_type;
TextQuery(ifstream &f);
QueryResult query(const string &s) const;
private:
map<string, shared_ptr<set<line_no>>> m_vm;
StrBlob m_text;
};
TextQuery.cpp
#include <sstream>
#include "TextQuery.h"
TextQuery::TextQuery(ifstream &f)
:m_text() {
string tmp;
line_no pos = 1;
while (getline(f, tmp)) {
m_text.push_back(tmp);
stringstream line(tmp);
string word;
while (line >> word) {
auto &lines = m_vm[word];
if (!lines) {
lines.reset(new set<line_no>);
}
lines->insert(pos);
}
++pos;
}
}
QueryResult TextQuery::query(const string &s) const {
shared_ptr<set<line_no>> nodata(new set<line_no>());
auto itr = m_vm.find(s);
if (itr == m_vm.end()) {
return QueryResult(s, m_text, nodata);
} else {
return QueryResult(s, m_text, itr->second);
}
}
QueryResult class:
QueryResult.h
#pragma once
#include <iostream>
#include <string>
#include <map>
#include <set>
#include <vector>
#include <memory>
#include "StrBlob.h"
#include "StrVec.h"
using namespace std;
class QueryResult {
friend ostream& print(std::ostream&, QueryResult&);
public:
using line_no = vector<string>::size_type;
QueryResult(const string target, StrBlob text, shared_ptr<set<line_no>> lines);
set<line_no>::iterator begin();
set<line_no>::iterator end();
StrBlob get_file();
private:
string m_target;
StrBlob m_text;
shared_ptr<set<line_no>> m_lines;
};
QueryResult.cpp
#include "QueryResult.h"
#include "StrBlobPtr.h"
ostream& print(std::ostream &os, QueryResult &r) {
os << "The word: " << r.m_target << endl;
os << "Occur at line: " << endl;
for (const auto i:*(r.m_lines)) {
os << i << " with string: " << r.m_text.off(i - 1).deref() << endl;
cout << "=======================================================================" << endl;
}
return os;
}
QueryResult::QueryResult(const string target, StrBlob text, shared_ptr<set<line_no>> lines)
: m_target(target), m_text(text), m_lines(lines) {}
set<QueryResult::line_no>::iterator QueryResult::begin() {
return m_lines->begin();
}
set<QueryResult::line_no>::iterator QueryResult::end() {
return m_lines->begin();
}
StrBlob QueryResult::get_file() {
return m_text;
}
main.cpp
#include <iostream>
#include <fstream>
#include <string>
#include "TextQuery.h"
#include "QueryResult.h"
using namespace std;
int main() {
ifstream f("test.txt");
if (f) {
string target;
TextQuery t(f);
cout << "Please enter the target" << endl;
while (cin >> target) {
QueryResult q = t.query(target);
print(cout, q);
}
}
else {
cout << "Cannot open file" << endl;
exit(1);
}
return 0;
}
更多推荐
所有评论(0)