Accelerated C++ 15 Revisiting character pictures

来源:互联网 发布:572-393的简便算法 编辑:程序博客网 时间:2024/06/05 02:36

grade.h

#ifndef GUARD_grade_h#define GUARD_grade_h// grade.h#include <vector>double median(std::vector<double>);double grade(double, double, double);double grade(double, double, const std::vector<double>&);double grade(const Student_info&);#endif

grade.cpp

// source file for the grade-ralated functons#include <vector>#include <stdexcept>#include "Student_info.h"#include "median.h"using std::vector;  using std::domain_error; using std::sort;double median(vector<double> vec) {    typedef vector<double>::size_type vec_sz;    vec_sz size = vec.size();    if (size == 0)        throw domain_error("median of an empty vector");    sort(vec.begin(), vec.end());    vec_sz mid = size / 2;    return size % 2 == 0 ? (vec[mid - 1] + vec[mid]) / 2 : vec[mid];}double grade(double midterm, double final, double homework) {    return 0.2 * midterm + 0.4 * final + 0.4 * homework;}double grade(double midterm, double final, const vector<double>& hw) {    if (hw.size() == 0)        throw domain_error("student has done no homework");    return grade(midterm, final, median(hw));}double grade(const Student_info& s) {    return grade(s.midterm, s.final, s.homework);}

Student_info.h

#ifndef GUARD_Student_info#define GUARD_Student_info// Student_info.h header file#include <iostream>#include <string>#include <vector>class Student_info{public:    std::string name() const {        return n;    }    std::istream& read(std::istream&);    double grade() const;    static bool compare(const Student_info&, const Student_info&);private:    std::string n;    double midterm, final;    std::vector<double>  homework;};#endif

Student_info.cpp

// source file for Student_info-related functions#include <vector>#include <iostream>#include "Student_info.h"#include "grade.h"using std::cout;    using std::vector;  using std::istream;double Student_info::grade() const {    return ::grade(midterm, final, homework);}bool Student_info::compare(const Student_info& x, const Student_info& y) {    return x.n < y.n;}istream& read_hw(istream& in, vector<double>& hw) {    // read and store the homework grades    cout << "Enter all your homework grades, "            "followd by end-of-file: ";    if (in) {        // get rid of previous contents        hw.clear();        // read homework grades        double x;        while (in >> x)            hw.push_back(x);        // clear the stream so that input will work for the next student        in.clear();    }    return in;}istream& Student_info::read(istream& is) {    // read and store the student's name and midterm and final exam grades    cout << "Please enter your first name, midterm and final exam grades: ";    is >> n >> midterm >> final;    read_hw(is, homework);    return is;}

Pic.h

#ifndef GUARD_Pic_h#define GUARD_Pic_h#include <iostream>#include <vector>#include <string>#include <algorithm>#include "Ptr.h"// forward declarationclass Picture;class Pic_base {    friend std::ostream& operator<<(std::ostream&, const Picture&);    friend class Frame_Pic;    friend class HCat_Pic;    friend class VCat_Pic;    friend class String_Pic;    private:        // no public interface(except for the destrctor)        typedef std::vector<std::string>::size_type ht_sz;                  typedef std::string::size_type wd_sz;                                                              virtual wd_sz width() const = 0;        virtual ht_sz height() const = 0;        virtual void display(std::ostream&, ht_sz, bool) const = 0;    public:        virtual ~Pic_base() { }    protected:        static void pad(std::ostream&, wd_sz, wd_sz);};void Pic_base::pad(std::ostream& os, wd_sz beg, wd_sz end) {    while (beg != end) {        os << " ";        ++beg;    }}class Frame_Pic: public Pic_base {    friend Picture frame(const Picture&);    // no public interface    Ptr<Pic_base> p;    Frame_Pic(const Ptr<Pic_base>& pic): p(pic) { }    wd_sz width() const { return p->width() + 4; }    ht_sz height() const { return p->height() + 4; }    void display(std::ostream&, ht_sz, bool) const;};void Frame_Pic::display(std::ostream& os, ht_sz row, bool do_pad) const {    if (row >= height()) {        // out of range        if (do_pad)            pad(os, 0, width());    } else if (row == 0 || row == height() - 1) {        // top or bottom row        os << std::string(width(), '*');    } else if (row == 1 || row == height() - 2) {        // second from top or bottom row        os << "*";        pad(os, 1, width() - 1);        os << "*";    } else {        // interior row        os << "* ";        p->display(os, row - 2, true);        os << " *";    }}class VCat_Pic: public Pic_base {    friend Picture vcat(const Picture&, const Picture&);    Ptr<Pic_base> top, bottom;    VCat_Pic(const Ptr<Pic_base>& t, const Ptr<Pic_base>& b):        top(t), bottom(b) { }    wd_sz width() const {        return std::max(top->width(), bottom->width());    }    ht_sz height() const{        return top->height() + bottom->height();    }    void display(std::ostream&, ht_sz, bool) const;};void VCat_Pic::display(std::ostream& os, ht_sz row, bool do_pad) const {    wd_sz w = 0;    if (row < top->height()) {        // we are in the top subpicture        top->display(os, row, do_pad);        w = top->width();    } else if (row < height()) {        // we are in the bottom subpicture        bottom->display(os, row - top->height(), do_pad);        w = bottom->width();    }    if (do_pad)        pad(os, w, width());}class HCat_Pic: public Pic_base {    friend Picture hcat(const Picture&, const Picture&);    Ptr<Pic_base> left, right;    HCat_Pic(const Ptr<Pic_base>& l, const Ptr<Pic_base>& r):        left(l), right(r) { }    wd_sz width() const {        return left->width() + right->width();    }    ht_sz height() const {        return std::max(left->height(), right->height());    }    void display(std::ostream&, ht_sz, bool) const;};void HCat_Pic::display(std::ostream& os, ht_sz row, bool do_pad) const {    left->display(os, row, do_pad || row < right->height());    right->display(os, row, do_pad);}class String_Pic: public Pic_base {    friend class Picture;    std::vector<std::string> data;    String_Pic(const std::vector<std::string>& v): data(v) { }    wd_sz width() const;    ht_sz height() const { return data.size(); }    void display(std::ostream&, ht_sz, bool) const;};Pic_base::wd_sz String_Pic::width() const {    Pic_base::wd_sz n = 0;    for (Pic_base::ht_sz i = 0; i != data.size(); ++i)        n = std::max(n, data[i].size());    return n;}void String_Pic::display(std::ostream& os, ht_sz row, bool do_pad) const {    wd_sz start = 0;    // write the row if we're still in range    if (row < height()) {        os << data[row];        start = data[row].size();    }    // pad the output if necessary    if (do_pad)        pad(os, start, width());}class Picture {    friend std::ostream& operator<<(std::ostream&, const Picture&);    friend Picture frame(const Picture&);    friend Picture hcat(const Picture&, const Picture&);    friend Picture vcat(const Picture&, const Picture&);    public:        Picture(const std::vector<std::string>& v = std::vector<std::string>()): p(new String_Pic(v)) { }    private:        Picture(Pic_base* ptr): p(ptr) { }        Ptr<Pic_base> p;};Picture frame(const Picture& pic) {    return new Frame_Pic(pic.p);}Picture hcat(const Picture& l, const Picture& r) {    return new HCat_Pic(l.p, r.p);}Picture vcat(const Picture& t, const Picture& b) {    return new VCat_Pic(t.p, b.p);}std::ostream& operator<<(std::ostream& os, const Picture& picture) {    const Pic_base::ht_sz ht = picture.p->height();    std::endl;    for (Pic_base::ht_sz i = 0; i != ht; ++i) {        picture.p->display(os, i, false);        os << std::endl;    }    return os;}#endif

Ptr.h

#ifndef GUARD_Ptr_h#define GUARD_Ptr_h// Ptr.h#include <iostream>#include <stdexcept>template <typename T> class Ptr {    public:        // new member to copy the object conditionally when needed        void make_unique() {            if (*refptr != 1) {                --*refptr;                refptr = new size_t(1);                p = p ? p->clone() : 0;            }        }        // same as Ref_handle        Ptr(): p(0), refptr(new size_t(1)) { }        Ptr(T* t): p(t), refptr(new size_t(1)) { }        Ptr(const Ptr& h): p(h.p), refptr(h.refptr) { ++*refptr; }        Ptr& operator=(const Ptr&);        ~Ptr();        operator bool() const { return p; }        T& operator*() const;         T* operator->() const {            if (p)                return p;            throw std::runtime_error("unbound Ptr");        }    private:        T* p;        std::size_t* refptr;};template <typename T> Ptr<T>& Ptr<T>::operator=(const Ptr& rhs) {    ++*rhs.refptr;    // free the left-hand side, destroying pointers if appropriate    if (--*refptr == 0) {        delete refptr;        delete p;    }    // copy in values from the right-hand side    refptr = rhs.refptr;    p = rhs.p;    return *this;}template <typename T>T& Ptr<T>::operator*() const {    if (p)        return *p;    throw std::runtime_error("unbound Ptr");}template <typename T>Ptr<T>::~Ptr() {    if (--*refptr == 0) {        delete refptr;        delete p;    }}#endif

main.cpp

// main.cpp#include "Pic.h"// #include "median.h"// #include "grade.h"// #include "Ptr.h"#include "Student_info.h"#include <algorithm>using std::vector;  using std::string;  using std::cin;using std::cout;    using std::endl;    using std::sort;Picture histogram(const vector<Student_info>& students) {    Picture names;    Picture grades;    // for each student    for (vector<Student_info>::const_iterator it = students.begin(); it != students.end(); ++it) {        // create vertically concatenated pictures of the names and grades        names = vcat(names, vector<string>(1, it->name()));        grades = vcat(grades,                vector<string>(1, " " + string(it->grade() / 5, '=')));    }    // horizontally concatenate the name and grade pictures to combine them    return hcat(names, grades);}int main() {    vector<Student_info> students;    Student_info s;    // read the names and grades    while (s.read(cin))        students.push_back(s);    // put the students in alphabetical order    sort(students.begin(), students.end(), Student_info::compare);    // write the names and histograms    cout << frame(histogram(students)) << endl;    return 0;}