Exercise 17.4:
/*****************************************************
* IDE: VS2010
* FILE: find_book.cpp
*****************************************************/
#include
using std::tuple; using std::make_tuple;
using std::get;
#include
using std::vector;
#include
using std::string;
#include
using std::equal_range; using std::sort;
#include
using std::accumulate;
#include
using std::istream; using std::ostream;
using std::cin; using std::cout; using std::endl;
#include
using std::ifstream;
#include "Sales_data.h"
// matches has three members: an index of a store
// and iterators into that store's vector
typedef tuple::size_type, \
vector::const_iterator, \
vector::const_iterator> matches;
// files holds the transactions for every store
// find_book returns a vector with an entry for each store that sold the given book
vector find_book(const vector> &files, const string &book)
{
vector ret; // initially empty
// for each store find the range of matching books, if any
for (auto it = files.cbegin(); it != files.cend(); ++it)
{
// find the range of Sales_data that have the same ISBN
auto found = equal_range(it->cbegin(), it->cend(), book, compare_isbn);
if (found.first != found.second) // this store has sales
{
ret.push_back(make_tuple(it - files.cbegin() + 1, found.first, found.second));
}
}
return ret; // empty if no matches found
}
void report_results(istream &in, ostream &os,
const vector> &files)
{
string s; // book to look for
while (in >> s)
{
vector trans = find_book(files, s);
if (trans.empty())
{
cout << s << " not found in any stores" << endl;
continue; // get the next book to look for
}
for (vector::iterator store = trans.begin(); \
store != trans.end(); ++store) // find every store with a sale
{
// get returns the specified member from the tuple in store
os << "store " << get<0>(*store) << " sales: " \
<< accumulate(get<1>(*store), get<2>(*store), Sales_data(s))
<< endl;
}
}
}
vector build_store(const string &s)
{
Sales_data item;
vector ret;
ifstream is(s);
while (is >> item)
{
ret.push_back(item);
}
sort(ret.begin(), ret.end(), compare_isbn);
return ret;
}
int main()
{
string stores[] = {"./data/store1", "./data/store2", "./data/store3", "./data/store4"};
// each element in files holds the transactions for a particular store
vector> files;
for (int cnt = 0; cnt != 4; ++cnt)
{
files.push_back(build_store(stores[cnt]));
}
report_results(cin, cout, files);
return 0;
}
/*****************************************************
* IDE: VS2010
* FILE: Sales_data.h
*****************************************************/
#ifndef SALES_DATA_H
#define SALES_DATA_H
#include
#include
class Sales_data
{
friend std::ostream &operator<<(std::ostream &os, const Sales_data &item);
friend std::istream &operator>>(std::istream &is, Sales_data &item);
friend bool operator==(const Sales_data &lhs, const Sales_data &rhs);
friend bool operator!=(const Sales_data &lhs, const Sales_data &rhs);
friend Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs);
public:
// constructors
Sales_data() : units_sold(0), revenue(0.0) { }
Sales_data(const std::string &s) :
book_no(s), units_sold(0), revenue(0.0) { }
Sales_data(const std::string &s, unsigned int n, double price) :
book_no(s), units_sold(n), revenue(price * n) { }
std::string isbn() const { return book_no; }
Sales_data &operator+=(const Sales_data &rhs);
private:
std::string book_no;
unsigned int units_sold;
double revenue;
// utility function
double avg_price() const;
};
// non-member Sales_data operations
inline bool compare_isbn(const Sales_data &lhs, const Sales_data &rhs)
{
return lhs.isbn() < rhs.isbn();
}
#endif
/*****************************************************
* IDE: VS2010
* FILE: Sales_data.cpp
*****************************************************/
#include "Sales_data.h"
#include
using std::string;
#include
using std::istream; using std::ostream;
//// utility function
double Sales_data::avg_price() const
{
if (units_sold)
{
return revenue / units_sold;
}
else
{
return 0;
}
}
//// non-member Sales_data operations
ostream &operator<<(ostream &os, const Sales_data &item)
{
os << item.isbn() << " " << item.units_sold << " "
<< item.revenue << " " << item.avg_price();
return os;
}
istream &operator>>(istream &is, Sales_data &item)
{
double price; // no need to initialize; we'll read into price before we use it
is >> item.book_no >> item.units_sold >> price;
if (is) // check that the inputs succeeded
{
item.revenue = item.units_sold * price;
}
else // input failed: give the object the default state
{
item = Sales_data();
}
return is;
}
bool operator==(const Sales_data &lhs, const Sales_data &rhs)
{
return lhs.isbn() == rhs.isbn() &&
lhs.units_sold == rhs.units_sold &&
lhs.revenue == rhs.revenue;
}
bool operator!=(const Sales_data &lhs, const Sales_data &rhs)
{
return !(lhs == rhs);
}
// member binary operator: left-hand operand is bound to the implicit this pointer
// assumes that both objects refer to the same book
Sales_data &Sales_data::operator+=(const Sales_data &rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
// assume that both objects refer to the same book
Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs)
{
Sales_data sum = lhs; // copy data
sum += rhs;
return sum;
}