#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
#include <string>
#include <set>
#include <map>
#include <stdexcept>
#include <iterator>
#include <algorithm>
#include <numeric>
using namespace::std;
class TextQuery {
public:
typedef std::vector<std::string>::size_type line_no;
void read_file(std::ifstream &is)
{store_file(is); build_map();}
std::set<line_no> run_query(const std::string&) const;
std::string text_line(line_no) const;
line_no size() const { return lines_of_text.size(); }
private:
void store_file(std::ifstream &is);
void build_map();
std::vector<std::string> lines_of_text;
std::map< std::string, std::set<line_no> > word_map;
};
void TextQuery::store_file(std::ifstream &is)
{
is.clear();
string line;
while(getline(is, line))
{
lines_of_text.push_back(line);
}
is.close();
is.clear();
}
void TextQuery::build_map()
{
string s;
for(TextQuery::line_no num = 1; num < lines_of_text.size(); ++num)
{
istringstream iss(lines_of_text[num]);
while(iss >> s)
{
word_map[s].insert(num);
}
}
}
std::string TextQuery::text_line(TextQuery::line_no ln) const
{
if(ln < lines_of_text.size())
{
return lines_of_text[ln];
}
throw std::out_of_range("line number out of range");
}
std::set<TextQuery::line_no> TextQuery::run_query(const std::string& word) const
{
std::map<std::string, std::set<TextQuery::line_no> >::const_iterator iter = word_map.find(word);
if(iter != word_map.end())
{
return iter->second;
}
else
{
return std::set<TextQuery::line_no>();
}
}
class Query_base {
friend class Query;
protected:
typedef TextQuery::line_no line_no;
virtual ~Query_base() {}
private:
virtual set<line_no>
eval(const TextQuery&) const = 0;
virtual ostream& display(ostream& = cout) const = 0;
};
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&);
Query(const Query &c);
~Query() { decr_use(); }
Query& operator=(const Query&);
set<TextQuery::line_no>
eval(const TextQuery &t) const { return q->eval(t); }
ostream &display(ostream &os) const
{ return q->display(os); }
private:
Query(Query_base *query): q(query), use(new size_t(1)) { }
Query_base *q;
size_t *use;
void decr_use()
{ if (--*use == 0) { delete q; delete use; } }
};
inline ostream& operator<<(ostream& os, const Query &q)
{
return q.display(os);
}
class WordQuery : public Query_base {
friend class Query;
WordQuery(const string &s): query_word(s) { }
set<line_no> eval(const TextQuery &t) const
{ return t.run_query(query_word); }
ostream& display(ostream &os) const
{ return os << query_word; }
string query_word;
};
inline Query::Query(const string& s): q(new WordQuery(s)), use(new size_t(1)) { }
inline Query::Query(const Query &c): q(c.q), use(c.use){ ++*use; }
inline Query& Query::operator=(const Query &c)
{
++*c.use;
decr_use();
this->q = c.q;
this->use = c.use;
return *this;
}
class NotQuery: public Query_base {
friend Query operator~(const Query &);
NotQuery(Query q): query(q) { }
set<line_no> eval(const TextQuery&) const;
ostream& display(ostream &os) const
{ return os << "~(" << query << ")"; }
const Query query;
};
class BinaryQuery: public Query_base {
protected:
BinaryQuery(Query left, Query right, string op):
lhs(left), rhs(right), oper(op) { }
ostream& display(ostream &os) const
{ return os << "(" << lhs << " " << oper << " "
<< rhs << ")"; }
const Query lhs, rhs;
const string oper;
};
class AndQuery: public BinaryQuery {
friend Query operator&(const Query&, const Query&);
AndQuery(Query left, Query right):
BinaryQuery(left, right, "&") { }
set<line_no> eval(const TextQuery&) const;
};
class OrQuery: public BinaryQuery {
friend Query operator|(const Query&, const Query&);
OrQuery(Query left, Query right):
BinaryQuery(left, right, "|") { }
set<line_no> eval(const TextQuery&) const;
};
set<TextQuery::line_no>
OrQuery::eval(const TextQuery& file) const
{
set<line_no> right = rhs.eval(file), left = lhs.eval(file);
/*
std::set<TextQuery::line_no>::iterator iter = left.begin();
cout << "left element occurs " << left.size() << " times" << endl;
while(iter != left.end())
{
cout << "\t(line " << *iter << "):\t" << file.text_line(*iter) << endl;
++iter;
}
iter = right.begin();
cout << "right element occurs " << right.size() << " times" << endl;
while(iter != right.end())
{
cout << "\t(line " << *iter << "):\t" << file.text_line(*iter) << endl;
++iter;
}
*/
left.insert(right.begin(), right.end());
return left;
}
set<TextQuery::line_no>
AndQuery::eval(const TextQuery& file) const
{
set<line_no> left = lhs.eval(file), right = rhs.eval(file);
set<line_no> ret_lines;
/*
std::set<TextQuery::line_no>::iterator iter = left.begin();
cout << "left element occurs " << left.size() << " times" << endl;
while(iter != left.end())
{
cout << "\t(line " << *iter << "):\t" << file.text_line(*iter) << endl;
++iter;
}
iter = right.begin();
cout << "right element occurs " << right.size() << " times" << endl;
while(iter != right.end())
{
cout << "\t(line " << *iter << "):\t" << file.text_line(*iter) << endl;
++iter;
}
*/
set_intersection(left.begin(), left.end(),
right.begin(), right.end(),
inserter(ret_lines, ret_lines.begin()));
return ret_lines;
}
set<TextQuery::line_no>
NotQuery::eval(const TextQuery& file) const
{
set<TextQuery::line_no> has_val = query.eval(file);
set<line_no> ret_lines;
for(TextQuery::line_no n = 0; n != file.size(); ++n)
{
if(has_val.find(n) == has_val.end())
ret_lines.insert(n);
return ret_lines;
}
}
inline Query operator&(const Query &lhs, const Query &rhs)
{
return new AndQuery(lhs, rhs);
}
inline Query operator|(const Query &lhs, const Query &rhs)
{
return new OrQuery(lhs, rhs);
}
inline Query operator~(const Query &oper)
{
return new NotQuery(oper);
}
int main(void)
{
Query q = Query("class") & Query("Query") | Query("inline");
TextQuery tq;
ifstream ifs(__FILE__);
tq.read_file(ifs);
cout << q << endl;
set<TextQuery::line_no> rs = q.eval(tq);
std::set<TextQuery::line_no>::iterator iter = rs.begin();
cout << "element occurs " << rs.size() << " times" << endl;
while(iter != rs.end())
{
cout << "\t(line " << *iter << "):\t" << tq.text_line(*iter) << endl;
++iter;
}
return 0;
}
15_41習題答案
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.