/*
* Copyright ©2026 Naomi Alterman. All rights reserved. Permission is
* hereby granted to students registered for University of Washington
* CSE 333 for use solely during Spring Quarter 2026 for purposes of
* the course. No other use, copying, distribution, or modification
* is permitted without prior written consent. Copyrights for
* third-party components of this work must be honored. Instructors
* interested in reusing these course materials should contact the
* author.
*/
#include <cstdlib> // for EXIT_FAILURE, EXIT_SUCCESS
#include <iostream> // for std::{err, cin, cout, endl}
#include <fstream> // for std::ifstream
#include <string> // for std::string
#include <map> // for std::map
using std::cout;
using std::cerr;
using std::endl;
using std::ifstream;
using std::string;
using std::map;
// Notes:
// This version of the ifstream constructor opens the file and leaves
// the file in a good state if success, otherwise the stream returns
// false if tested. We do not need to explicitly close the file since
// that is done by the ifstream destructor.
// When using a map, if m[key] is referenced and no <key, value> pair
// exists in the map, an entry is created using default initialization
// for the value, which is 0 for integers.
// Read the next type "T" thing from input stream "in". Sets the output
// parameter and returns true on success. Returns false when a value
// can't be read from the ifstream.
template <typename T> bool ReadValue(ifstream& in, T* const out);
// Read the text file given as the program argument and print a sorted
// list of words found in it and how often each word occurs.
int main(int argc, char** argv) {
// check that an argument is supplied
if (argc != 2) {
cerr << "Usage: ./ex8 filename" << endl;
return EXIT_FAILURE;
}
// Create stream and open for reading. Exit if there is a failure.
ifstream infile(argv[1], ifstream::in);
if (!infile) {
cerr << "Unable to open file: " << argv[1] << endl;
return EXIT_FAILURE;
}
// read words from file and count number of occurrences of each
string word;
map<string, size_t> freq; // map of <word, #occurrences> pairs
while (ReadValue<string>(infile, &word)) {
++freq[word];
}
// if input failed for some reason other than eof, report error
if (!infile.eof()) {
cerr << "Error reading file: " << argv[1] << endl;
return EXIT_FAILURE;
}
// print words and frequencies in sorted order
for (const auto& w : freq) {
cout << w.first << " " << w.second << endl;
}
return EXIT_SUCCESS;
}
// ReadValue implementation
template <typename T> bool ReadValue(ifstream& in, T* const output) {
T next;
// Try do to the conversion; check on in.fail() afterwards.
in >> next;
if (in.fail()) {
return false;
}
*output = next;
return true;
}