#include #include #include #include #include #include #include #include #include using namespace std; //All of classes are pointer class QueryResult { friend ostream& print (ostream&, const QueryResult&); public: using line_no = vector ::size_type; set ::iterator begin() const { return lines->begin (); } set ::iterator end() const { return lines->end (); } shared_ptr > get_file()const { return file; } QueryResult (string s, shared_ptr > p, shared_ptr > f) :sought (s), lines (p), file (f) {} private: string sought; //we want share the data in the file & line_no //so we defind these as smart pointer shared_ptr > file; shared_ptr > lines; }; ostream& print (ostream& os, const QueryResult& query) { os << query.sought << " occurs " << query.lines->size () << " " << ((query.lines->size () > 1) ? "times" : "time") << endl; for (auto num : *query.lines) os << "\t(line" << num + 1 << ")" << *(query.file->begin () + num) << endl; return os; } class TextQuery { public: using line_no = vector ::size_type; //store the input file TextQuery (ifstream&); QueryResult query (const string&)const; private: shared_ptr >file; //each word corresponds to a collection store it's line_no map >>word_map; }; TextQuery::TextQuery (ifstream& is) :file (new vector ) { string text; while (getline (is, text)) { file->push_back (text); //current line_no int n = file->size () - 1; istringstream line (text); string word; while (line >> word) { //lines is shared_ptr auto &lines = word_map[word]; //create a new set store the line_no of the new word if (!lines) lines.reset (new set ); //store the line_no lines->insert (n); } } } QueryResult TextQuery::query (const string& s)const { //if not exist, return empty shared_ptr static shared_ptr >nodata (new set ); auto loc = word_map.find (s); return ((loc == word_map.end ()) ? QueryResult (s, nodata, file) : QueryResult (s, loc->second, file)); } //the root of the query system adapt other class class Query_base { friend class Query; protected: using line_no = TextQuery::line_no; virtual ~Query_base () = default; private: //eval return the QueryResult corresponded to current Query virtual QueryResult eval (const TextQuery&)const = 0; //rep turn the query to string virtual string rep ()const = 0; }; //the interface to hide the query system class Query { friend Query operator~(const Query&); friend Query operator|(const Query&, const Query&); friend Query operator&(const Query&, const Query&); public: Query (const string&); QueryResult eval (const TextQuery &tq) const { return q->eval (tq); } string rep ()const { return q->rep (); } private: //clare as private means to prevent user defind a new Query_base casually Query (shared_ptr query):q(query) {} shared_ptr q; }; ostream &operator<<(ostream os, const Query &query) { return os << query.rep(); } //query a word class WordQuery:public Query_base { friend class Query; WordQuery (const string &s) :query_word (s) {} QueryResult eval (const TextQuery &tq)const override { return tq.query (query_word);} string rep ()const override { return query_word; } string query_word; }; inline Query::Query (const string &s):q (new WordQuery(s)){}; //accept a Query, execute the operator~ class NotQuery :public Query_base { friend Query operator~(const Query &); NotQuery (const Query &q) :query (q) {} string rep ()const override { return "~(" + query.rep () + ")"; } QueryResult eval (const TextQuery &tq)const override; Query query; }; inline Query operator~(const Query &q) { return shared_ptr (new NotQuery (q)); } //BinaryQuery is also an virtual class class BinaryQuery:public Query_base { protected: BinaryQuery (const Query &l, const Query &r, const string &s) :lhs (l), rhs (r), opSym (s) {} string rep ()const override { return "(" + lhs.rep () + " " + opSym + " " + rhs.rep () + ")"; } Query lhs, rhs; //name of the operator string opSym; }; class AndQuery :public BinaryQuery { friend Query operator&(const Query &, const Query &); AndQuery (const Query &left, const Query &right) :BinaryQuery (left, right, "&") {} QueryResult eval (const TextQuery &)const override; }; inline Query operator&(const Query &lhs, const Query &rhs) { return shared_ptr (new AndQuery (lhs, rhs)); } class OrQuery :public BinaryQuery { friend Query operator|(const Query &, const Query &); OrQuery (const Query &left, const Query &right) :BinaryQuery (left, right, "|") {} QueryResult eval (const TextQuery &)const override; }; inline Query operator|(const Query &lhs, const Query &rhs) { return shared_ptr (new OrQuery (lhs, rhs)); } //return the union of the rhs & lhs'query result QueryResult OrQuery::eval (const TextQuery &text)const { auto right = rhs.eval (text), left = lhs.eval (text); //insert the left auto ret_lines = make_shared > (left.begin (), left.end ()); //insert the right ret_lines->insert (right.begin (), right.end ()); //left & right point to the same file return QueryResult (rep (), ret_lines, left.get_file ()); } //return the intersection of the rhs & lhs's query result QueryResult AndQuery::eval (const TextQuery &text)const { auto right = rhs.eval (text), left = lhs.eval (text); auto ret_lines = make_shared > (); //STL set_intersection(first_range, second_range, dest_place) set_intersection (right.begin (), right.end (), left.begin (), left.end (), inserter (*ret_lines, ret_lines->begin ())); return QueryResult (rep (), ret_lines, left.get_file ()); } QueryResult NotQuery::eval (const TextQuery &text)const { auto result = query.eval (text); auto ret_lines = make_shared > (); auto begin = result.begin (), end = result.end (); auto sz = result.get_file ()->size (); for (size_t n = 0; n < sz; ++n) { //before we process all of the lines in result //we must check if current line exist if (begin == end || *begin != n) ret_lines->insert (n); //what we need is the word not in the query result else ++begin; } return QueryResult (rep (), ret_lines, result.get_file ()); } void RunTextQueryTest (ifstream &infile) { TextQuery tq (infile); while (true) { cout << "enter something or press Ctrl+Z to exit\n"; cout << "Excuting Query for: "; string input; if (!(cin >> input))break; print (cout, tq.query(input)); } } int main (int argc, char *argv[]) { std::ios::sync_with_stdio (false); ifstream in; in.open (argv[1]); TextQuery tq (in); auto q = Query("Your") & Query("is") | Query("of"); print (cout, q.eval (tq)); return 0; }