aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/client/input.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'client/input.hpp')
-rw-r--r--client/input.hpp139
1 files changed, 139 insertions, 0 deletions
diff --git a/client/input.hpp b/client/input.hpp
new file mode 100644
index 0000000..077d5c7
--- /dev/null
+++ b/client/input.hpp
@@ -0,0 +1,139 @@
+#pragma once
+
+#include "error.hpp"
+
+#include <exception>
+#include <fstream>
+#include <functional>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace math::client::input {
+
+class Error : public client::Error {
+public:
+ explicit Error(const std::string& what)
+ : client::Error{"input error: " + what} {
+ }
+};
+
+class Reader {
+public:
+ using InputHandler = std::function<bool (const std::string&)>;
+
+ virtual ~Reader() = default;
+
+ virtual bool for_each_input(const InputHandler& process) const = 0;
+};
+
+using ReaderPtr = std::unique_ptr<input::Reader>;
+
+class FileReader : public Reader {
+public:
+ explicit FileReader(const std::string& path)
+ : m_path{path}
+ { }
+
+ bool for_each_input(const InputHandler& process) const override {
+ return enum_lines(process);
+ }
+
+private:
+ bool enum_lines(const InputHandler& process) const {
+ std::ifstream ifs;
+ ifs.exceptions(std::ifstream::badbit);
+
+ try {
+ ifs.open(m_path);
+ if (!ifs.is_open()) {
+ throw Error{"couldn't open file: " + m_path};
+ }
+
+ for (std::string line; std::getline(ifs, line);) {
+ if (!process(line)) {
+ return false;
+ }
+ }
+ } catch (const std::exception& e) {
+ throw Error{e.what()};
+ }
+
+ return true;
+ }
+
+ const std::string m_path;
+};
+
+class MultiFileReader : public Reader {
+public:
+ explicit MultiFileReader(const std::vector<std::string>& paths)
+ : m_paths{paths}
+ { }
+
+ bool for_each_input(const InputHandler& process) const override {
+ for (const auto& path : m_paths) {
+ const FileReader reader{path};
+ if (!reader.for_each_input(process)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+private:
+ const std::vector<std::string> m_paths;
+};
+
+inline input::ReaderPtr make_file_reader(const std::string& path) {
+ return std::make_unique<input::FileReader>(path);
+}
+
+inline input::ReaderPtr make_file_reader(const std::vector<std::string>& paths) {
+ return std::make_unique<input::MultiFileReader>(paths);
+}
+
+class StringReader : public Reader {
+public:
+ explicit StringReader(const std::string& input)
+ : m_input{input}
+ { }
+
+ bool for_each_input(const InputHandler& process) const override {
+ return process(m_input);
+ }
+
+private:
+ const std::string m_input;
+};
+
+inline input::ReaderPtr make_string_reader(const std::string& input) {
+ return std::make_unique<input::StringReader>(input);
+}
+
+class ConsoleReader : public Reader {
+public:
+ ConsoleReader() = default;
+
+ bool for_each_input(const InputHandler& process) const override {
+ std::string line;
+ while (read_line(line)) {
+ if (!process(line)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+private:
+ static bool read_line(std::string& dest) {
+ return static_cast<bool>(std::getline(std::cin, dest));
+ }
+};
+
+inline input::ReaderPtr make_console_reader() {
+ return std::make_unique<input::ConsoleReader>();
+}
+
+}