#include #include #include #include #include #include #include #include #include class Plot { public: virtual ~Plot() = default; virtual void print(std::ostream& os) const = 0; virtual std::size_t get_width() const = 0; }; template class Function_Plot : public Plot { public: Function_Plot(Function const& func, unsigned lower = 0, unsigned upper = 10) : func { func }, lower { lower }, upper { upper } { } void print(std::ostream& os) const override { os << std::setfill(' ') << std::right; for (unsigned i { lower }; i <= upper; ++i) { unsigned current { func(i) }; os << std::setw(current + 1) << "+" << std::endl; } } std::size_t get_width() const override { std::size_t width { 0 }; for (unsigned i { lower }; i <= upper; ++i) { unsigned current { func(i) + 1 }; if (current > width) width = current; } return width; } private: Function func; unsigned lower; unsigned upper; }; class Bar_Plot : public Plot { public: Bar_Plot(std::initializer_list> values) : data { std::begin(values), std::end(values) } { } void print(std::ostream& os) const override { std::size_t size { 0 }; for (auto&& [label, value] : data) { if (label.size() > size) size = label.size(); } os << std::setfill(' ') << std::left; for (auto&& [label, value] : data) { os << std::setw(size) << label << " " << std::string(value, '=') << std::endl; } } std::size_t get_width() const override { std::size_t bar_width { 0 }; std::size_t label_width { 0 }; for (auto&& [label, value] : data) { if (label.size() > label_width) label_width = label.size(); if (value > bar_width) bar_width = value; } return label_width + 1 + bar_width; } protected: std::vector> data; }; class Gallery : public Plot { public: Gallery(std::initializer_list plots) : plots { std::begin(plots), std::end(plots) } { } ~Gallery() { for (Plot* plot : plots) { delete plot; } } void print(std::ostream& os) const override { std::vector streams; std::vector widths; for (Plot* plot : plots) { std::ostringstream oss; plot->print(oss); streams.emplace_back(oss.str()); widths.push_back(plot->get_width()); } os << std::setfill(' ') << std::left; bool processing { true }; while (processing) { processing = false; for (std::size_t i { 0 }; i < streams.size(); ++i) { std::string line { }; if (std::getline(streams[i], line)) processing = true; os << std::setw(widths[i]) << line << " | "; } os << std::endl; } } std::size_t get_width() const override { std::size_t width { 0 }; for (Plot* plot : plots) { width += plot->get_width(); } return width; } private: std::vector plots; }; /* Expected output: C++ Books ============= Python Books ===== C# Books === Java Books == Theoretical Books =========== Apples ======= | + | Oranges === | + | Bananas =========== | + | Pears ===== | + | | + | | + | | + | | + | | + | | + | | + | | | + + + + + + + + + + + + + + + + + + + + + */ int main() { std::vector plots { new Bar_Plot { { "C++ Books", 13 }, { "Python Books", 5 }, { "C# Books", 3 }, { "Java Books", 2 }, { "Theoretical Books", 11 } }, new Gallery { new Bar_Plot { { "Apples", 7 }, { "Oranges", 3 }, { "Bananas", 11 }, { "Pears", 5 } }, new Function_Plot { [](unsigned x) { x -= 5; return x * x; } }, }, new Function_Plot { [](unsigned x) -> unsigned { return (10.0*(std::sin(3.1415926535 * x / 10) + 1.0)); }, 0, 20 } }; for (auto plot : plots) { plot->print(std::cout); std::cout << std::endl; delete plot; } }