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;
}
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐