From 980f14686383e43160ef873ab00a380780b850fb Mon Sep 17 00:00:00 2001 From: Miroslaw Opoka Date: Fri, 5 Apr 2024 01:02:09 +0200 Subject: [PATCH] removed namespace --- TODO | 1 - src/Currency_Value.hpp | 23 ++- src/Data_Loader.cpp | 135 +++++++++-------- src/Data_Loader.hpp | 30 ++-- src/Log.cpp | 95 ++++++------ src/Log.hpp | 77 +++++----- src/Main_Fetcher.cpp | 22 +-- src/Main_Server.cpp | 36 ++--- src/Rates.cpp | 31 ++-- src/Rates.hpp | 95 ++++++------ src/Record.cpp | 65 ++++----- src/Record.hpp | 49 +++---- src/Server.cpp | 36 ++--- src/Server.hpp | 44 +++--- src/Server_Impl.cpp | 291 ++++++++++++++++++------------------- src/Server_Impl.hpp | 73 +++++----- src/Time_Point.cpp | 49 +++---- src/Time_Point.hpp | 37 +++-- src/Urls.hpp | 11 +- src/Utils.cpp | 31 ++-- src/Utils.hpp | 17 +-- src/Version_Info.cpp.in | 2 +- src/Version_Info.hpp | 4 +- tests/Rates_Tests.cpp | 2 - tests/Record_Tests.cpp | 2 - tests/Time_Point_Tests.cpp | 2 - tests/Utils_Tests.cpp | 10 +- 27 files changed, 603 insertions(+), 667 deletions(-) diff --git a/TODO b/TODO index 1dd28d5..d1bc35a 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,2 @@ - examples of configuration (nginx, cron) - make cross compilation work again -- consider removing ECB namespace diff --git a/src/Currency_Value.hpp b/src/Currency_Value.hpp index 98a11cb..ff0c5d2 100644 --- a/src/Currency_Value.hpp +++ b/src/Currency_Value.hpp @@ -2,18 +2,15 @@ #include -namespace ECB +// Represents a currency and its value. +struct Currency_Value { - // Represents a currency and its value. - struct Currency_Value - { - std::string currency; - double value{}; + std::string currency; + double value{}; - bool operator==(const Currency_Value &other) const - { - static constexpr double EPSILON = 0.001; - return currency == other.currency && (std::abs(value - other.value) <= EPSILON); - } - }; -} // namespace ECB + bool operator==(const Currency_Value &other) const + { + static constexpr double EPSILON = 0.001; + return currency == other.currency && (std::abs(value - other.value) <= EPSILON); + } +}; diff --git a/src/Data_Loader.cpp b/src/Data_Loader.cpp index 5b93750..521d6d4 100644 --- a/src/Data_Loader.cpp +++ b/src/Data_Loader.cpp @@ -7,98 +7,95 @@ #include #include -namespace ECB +std::vector Data_Loader::load_from_file(const std::string &file_name) { - std::vector Data_Loader::load_from_file(const std::string &file_name) + try { - try - { - std::ifstream file(file_name); - std::string content(std::istreambuf_iterator{file}, {}); - file.close(); + std::ifstream file(file_name); + std::string content(std::istreambuf_iterator{file}, {}); + file.close(); - return load_from_xml_string(content); - } - catch (...) - { - Log::error("Error loading from a file '{}'\n", file_name); - } - return {}; + return load_from_xml_string(content); } + catch (...) + { + Log::error("Error loading from a file '{}'\n", file_name); + } + return {}; +} - std::vector Data_Loader::load_from_url(const std::string &url, std::string_view save_to_file) +std::vector Data_Loader::load_from_url(const std::string &url, std::string_view save_to_file) +{ + try { - try - { - auto r = cpr::Get(cpr::Url{url}, cpr::VerifySsl{false}); + auto r = cpr::Get(cpr::Url{url}, cpr::VerifySsl{false}); - if (r.status_code == 200) - { - if (!save_to_file.empty()) - { - std::ofstream file(save_to_file.data()); - file << r.text; - file.close(); - } - return load_from_xml_string(r.text); - } - else + if (r.status_code == 200) + { + if (!save_to_file.empty()) { - Log::error("Failed getting data from url '{}', status code = {}\n", url, r.status_code); + std::ofstream file(save_to_file.data()); + file << r.text; + file.close(); } + return load_from_xml_string(r.text); } - catch (...) + else { - Log::error("Error loading from url '{}'\n", url); + Log::error("Failed getting data from url '{}', status code = {}\n", url, r.status_code); } - return {}; } - - std::vector Data_Loader::load_from_xml_string(const std::string &data) + catch (...) { - std::vector records; + Log::error("Error loading from url '{}'\n", url); + } + return {}; +} - pugi::xml_document doc; +std::vector Data_Loader::load_from_xml_string(const std::string &data) +{ + std::vector records; - // std::cout << "Parsing historical data from file '" << file_name << "'... " << std::flush; - // auto time_start = std::chrono::steady_clock::now(); - // auto parse_result = doc.load_file(file_name.c_str()); - auto parse_result = doc.load_string(data.c_str()); - // auto time_end = std::chrono::steady_clock::now(); - // auto parse_duration = std::chrono::duration(time_end - time_start); - // std::cout << "done (time: " << parse_duration.count() << "). Result: " << parse_result.description() << - // std::endl; + pugi::xml_document doc; - if (!parse_result) - { - Log::error("Error parsing xml: {}\n", parse_result.description()); - return records; - } + // std::cout << "Parsing historical data from file '" << file_name << "'... " << std::flush; + // auto time_start = std::chrono::steady_clock::now(); + // auto parse_result = doc.load_file(file_name.c_str()); + auto parse_result = doc.load_string(data.c_str()); + // auto time_end = std::chrono::steady_clock::now(); + // auto parse_duration = std::chrono::duration(time_end - time_start); + // std::cout << "done (time: " << parse_duration.count() << "). Result: " << parse_result.description() << + // std::endl; - auto root = doc.first_child(); // "gesmes:Envelope" is the name - auto cube = root.child("Cube"); // root of all currency data + if (!parse_result) + { + Log::error("Error parsing xml: {}\n", parse_result.description()); + return records; + } - static const std::string BASE{"EUR"}; - for (const auto &day_node: cube.children()) // each child is also "Cube" - { - std::string time = day_node.attribute("time").as_string(); + auto root = doc.first_child(); // "gesmes:Envelope" is the name + auto cube = root.child("Cube"); // root of all currency data - Time_Point tp{time}; - std::vector rates; + static const std::string BASE{"EUR"}; + for (const auto &day_node: cube.children()) // each child is also "Cube" + { + std::string time = day_node.attribute("time").as_string(); + + Time_Point tp{time}; + std::vector rates; - for (const auto &symbol_node: day_node.children()) + for (const auto &symbol_node: day_node.children()) + { + if (strcmp(symbol_node.name(), "Cube") == 0) { - if (strcmp(symbol_node.name(), "Cube") == 0) - { - const Currency_Value cv{symbol_node.attribute("currency").as_string(), - symbol_node.attribute("rate").as_double()}; - rates.emplace_back(cv); - } + const Currency_Value cv{symbol_node.attribute("currency").as_string(), + symbol_node.attribute("rate").as_double()}; + rates.emplace_back(cv); } - - records.emplace_back(tp, BASE, rates); } - return records; + records.emplace_back(tp, BASE, rates); } -}; // namespace ECB + + return records; +} diff --git a/src/Data_Loader.hpp b/src/Data_Loader.hpp index 535f1f2..75f3236 100644 --- a/src/Data_Loader.hpp +++ b/src/Data_Loader.hpp @@ -4,24 +4,20 @@ #include -namespace ECB +class Data_Loader { - class Data_Loader - { - public: - Data_Loader() = delete; +public: + Data_Loader() = delete; - // Load data from a file and return a vector of records. - // Returns an empty vector if the data could not be loaded. - static std::vector load_from_file(const std::string &file_name); + // Load data from a file and return a vector of records. + // Returns an empty vector if the data could not be loaded. + static std::vector load_from_file(const std::string &file_name); - // Load data from a url and return a vector of records. - // Returns an empty vector if the data could not be loaded. - static std::vector load_from_url(const std::string &url, std::string_view save_to_file = ""); + // Load data from a url and return a vector of records. + // Returns an empty vector if the data could not be loaded. + static std::vector load_from_url(const std::string &url, std::string_view save_to_file = ""); - private: - // Load data from a string and return a vector of records. - static std::vector load_from_xml_string(const std::string &data); - }; - -} // namespace ECB +private: + // Load data from a string and return a vector of records. + static std::vector load_from_xml_string(const std::string &data); +}; diff --git a/src/Log.cpp b/src/Log.cpp index 14dbed0..09fe8f7 100644 --- a/src/Log.cpp +++ b/src/Log.cpp @@ -3,60 +3,57 @@ #include "spdlog/sinks/basic_file_sink.h" #include "spdlog/sinks/stdout_color_sinks.h" -namespace ECB -{ - // static members - std::shared_ptr Log::logger_ = nullptr; +// static members +std::shared_ptr Log::logger_ = nullptr; - void Log::init(const std::string &logFile) - { - std::vector sinks; +void Log::init(const std::string &logFile) +{ + std::vector sinks; - auto consoleLogger = std::make_shared(); - // timestamp with ms, colored log level, message - consoleLogger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%^%l%$] %v"); - sinks.push_back(consoleLogger); + auto consoleLogger = std::make_shared(); + // timestamp with ms, colored log level, message + consoleLogger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%^%l%$] %v"); + sinks.push_back(consoleLogger); - if (!logFile.empty()) + if (!logFile.empty()) + { + constexpr bool TRUNCATE = true; + try { - constexpr bool TRUNCATE = true; - try - { - auto fileLogger = std::make_shared(logFile, TRUNCATE); - // timestamp with ms, log level, message - fileLogger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] %v"); - sinks.push_back(fileLogger); - } - catch (const spdlog::spdlog_ex &ex) - { - spdlog::error("Failed to create file logger: {}", ex.what()); - } + auto fileLogger = std::make_shared(logFile, TRUNCATE); + // timestamp with ms, log level, message + fileLogger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] %v"); + sinks.push_back(fileLogger); + } + catch (const spdlog::spdlog_ex &ex) + { + spdlog::error("Failed to create file logger: {}", ex.what()); } - - logger_ = std::make_shared("logger", sinks.begin(), sinks.end()); - spdlog::register_logger(logger_); } - void Log::setLevel(const std::string &level) - { - constexpr auto DEFAULT_LEVEL = spdlog::level::info; - spdlog::level::level_enum finalLevel = DEFAULT_LEVEL; - - if (level == "off") - finalLevel = spdlog::level::off; - else if (level == "error") - finalLevel = spdlog::level::err; - else if (level == "warning") - finalLevel = spdlog::level::warn; - else if (level == "info") - finalLevel = spdlog::level::info; - - setLevel(finalLevel); - } + logger_ = std::make_shared("logger", sinks.begin(), sinks.end()); + spdlog::register_logger(logger_); +} - void Log::setLevel(spdlog::level::level_enum level) - { - if (logger_ != nullptr) - logger_->set_level(level); - } -} // namespace ECB +void Log::setLevel(const std::string &level) +{ + constexpr auto DEFAULT_LEVEL = spdlog::level::info; + spdlog::level::level_enum finalLevel = DEFAULT_LEVEL; + + if (level == "off") + finalLevel = spdlog::level::off; + else if (level == "error") + finalLevel = spdlog::level::err; + else if (level == "warning") + finalLevel = spdlog::level::warn; + else if (level == "info") + finalLevel = spdlog::level::info; + + setLevel(finalLevel); +} + +void Log::setLevel(spdlog::level::level_enum level) +{ + if (logger_ != nullptr) + logger_->set_level(level); +} diff --git a/src/Log.hpp b/src/Log.hpp index 1f5da35..e9e944c 100644 --- a/src/Log.hpp +++ b/src/Log.hpp @@ -2,45 +2,42 @@ #include "spdlog/spdlog.h" -namespace ECB +class Log { - class Log +public: + Log() = delete; + + static void init(const std::string &logFile = ""); + + static void setLevel(const std::string &level); + static void setLevel(spdlog::level::level_enum level); + + // convenient aliases + template + static void info(const char *format, Args... args) + { + log(spdlog::level::level_enum::info, format, args...); + } + + template + static void warn(const char *format, Args... args) { - public: - Log() = delete; - - static void init(const std::string &logFile = ""); - - static void setLevel(const std::string &level); - static void setLevel(spdlog::level::level_enum level); - - // convenient aliases - template - static void info(const char *format, Args... args) - { - log(spdlog::level::level_enum::info, format, args...); - } - - template - static void warn(const char *format, Args... args) - { - log(spdlog::level::level_enum::warn, format, args...); - } - - template - static void error(const char *format, Args... args) - { - log(spdlog::level::level_enum::err, format, args...); - } - - private: - template - static void log(spdlog::level::level_enum level, const char *format, Args... args) - { - if (logger_ != nullptr) - logger_->log(level, format, args...); - } - - static std::shared_ptr logger_; - }; -} // namespace ECB + log(spdlog::level::level_enum::warn, format, args...); + } + + template + static void error(const char *format, Args... args) + { + log(spdlog::level::level_enum::err, format, args...); + } + +private: + template + static void log(spdlog::level::level_enum level, const char *format, Args... args) + { + if (logger_ != nullptr) + logger_->log(level, format, args...); + } + + static std::shared_ptr logger_; +}; diff --git a/src/Main_Fetcher.cpp b/src/Main_Fetcher.cpp index 410c2ae..71480ca 100644 --- a/src/Main_Fetcher.cpp +++ b/src/Main_Fetcher.cpp @@ -18,11 +18,11 @@ int main(int argc, char *argv[]) return param == "hist" || param == "daily"; // NOLINT }); - options.add_optional("hist_url", "URL to get historical data", ECB::ECB_URL_HIST, [](const std::string ¶m) { + options.add_optional("hist_url", "URL to get historical data", ECB_URL_HIST, [](const std::string ¶m) { return !param.empty(); // valid data is not empty }); - options.add_optional("daily_url", "URL to get daily data", ECB::ECB_URL_DAILY, [](const std::string ¶m) { + options.add_optional("daily_url", "URL to get daily data", ECB_URL_DAILY, [](const std::string ¶m) { return !param.empty(); // valid data is not empty }); @@ -46,8 +46,8 @@ int main(int argc, char *argv[]) if (!parse_result || show_help) { cout << "ECB data fetcher" << endl; - cout << " Version: " << ECB::Version_Info::HASH << endl; - cout << " Date : " << ECB::Version_Info::DATE << endl; + cout << " Version: " << Version_Info::HASH << endl; + cout << " Date : " << Version_Info::DATE << endl; cout << endl; cout << "Usage: " << argv[0] << " [options]" << endl; cout << options.get_possible_options() << endl; @@ -55,28 +55,28 @@ int main(int argc, char *argv[]) return -1; } - ECB::Log::init(options.as_string("log_file")); - ECB::Log::setLevel(options.as_string("log_level")); + Log::init(options.as_string("log_file")); + Log::setLevel(options.as_string("log_level")); const bool hist_mode = (options.as_string("mode") == "hist"); const std::string &url = (hist_mode) ? options.as_string("hist_url") : options.as_string("daily_url"); const std::string &save_to_file = options.as_string("save_file"); - ECB::Log::info("Getting {} data{}", hist_mode ? "historical" : "daily", - !save_to_file.empty() ? std::string(" and saving to ") + save_to_file : ""); + Log::info("Getting {} data{}", hist_mode ? "historical" : "daily", + !save_to_file.empty() ? std::string(" and saving to ") + save_to_file : ""); - const auto records = ECB::Data_Loader::load_from_url(url, save_to_file); + const auto records = Data_Loader::load_from_url(url, save_to_file); if (records.empty()) { - ECB::Log::error("Failed to load data from url: {}\n", url); + Log::error("Failed to load data from url: {}\n", url); return -1; } for (const auto &record: records) cout << record.as_string_without_base() << endl; - ECB::Log::info("Got {} records", records.size()); + Log::info("Got {} records", records.size()); return 0; } diff --git a/src/Main_Server.cpp b/src/Main_Server.cpp index fbe7aba..88bb848 100644 --- a/src/Main_Server.cpp +++ b/src/Main_Server.cpp @@ -26,10 +26,10 @@ int main(int argc, char *argv[]) options.add_optional("xml_file", "Load data from a file at start", "", [](const std::string &value) { return !value.empty(); }); - options.add_optional("xml_url", "Load data from a url at start (used if no file was specified)", ECB::ECB_URL_HIST, + options.add_optional("xml_url", "Load data from a url at start (used if no file was specified)", ECB_URL_HIST, [](const std::string &value) { return !value.empty(); }); - options.add_optional("signal_xml_url", "On signal load more data from this url", ECB::ECB_URL_DAILY, + options.add_optional("signal_xml_url", "On signal load more data from this url", ECB_URL_DAILY, [](const std::string &value) { return !value.empty(); }); options.add_mandatory("port", "HTTP port to listen on", [](const std::string &value) { @@ -61,8 +61,8 @@ int main(int argc, char *argv[]) if (!parse_result || show_help) { cout << "ECB Exchange Rates Server" << endl; - cout << " Version: " << ECB::Version_Info::HASH << endl; - cout << " Date : " << ECB::Version_Info::DATE << endl; + cout << " Version: " << Version_Info::HASH << endl; + cout << " Date : " << Version_Info::DATE << endl; cout << endl; cout << "Usage: " << argv[0] << " [options]" << endl; cout << options.get_possible_options() << endl; @@ -70,14 +70,14 @@ int main(int argc, char *argv[]) return -1; } - ECB::Log::init(options.as_string("log_file")); - ECB::Log::setLevel(options.as_string("log_level")); + Log::init(options.as_string("log_file")); + Log::setLevel(options.as_string("log_level")); - auto rates = std::make_shared(); + auto rates = std::make_shared(); if (!options.as_string("xml_file").empty()) { - const auto data = ECB::Data_Loader::load_from_file(options.as_string("xml_file")); + const auto data = Data_Loader::load_from_file(options.as_string("xml_file")); if (!data.empty()) { @@ -88,7 +88,7 @@ int main(int argc, char *argv[]) // if no file was specified, load from the url else if (!options.as_string("xml_url").empty()) { - const auto data = ECB::Data_Loader::load_from_url(options.as_string("xml_url")); + const auto data = Data_Loader::load_from_url(options.as_string("xml_url")); if (!data.empty()) { @@ -107,7 +107,7 @@ int main(int argc, char *argv[]) cout << "Pretty JSON output: " << (pretty ? "yes" : "no") << endl; cout << "Numerical precision: " << precision << endl; - auto &server = ECB::Server::instance(); + auto &server = Server::instance(); server.set_pretty_json(pretty); server.set_precision(precision); @@ -119,22 +119,22 @@ int main(int argc, char *argv[]) // start thread for serving web requests std::thread web_thread([&server]() { - ECB::Log::info("Starting web server in separate thread"); + Log::info("Starting web server in separate thread"); server.start(); - ECB::Log::info("Stopping web server"); + Log::info("Stopping web server"); server.stop(); }); - ECB::Log::info("Starting loop in main thread"); + Log::info("Starting loop in main thread"); while (Main_Signals::keep_running()) { if (Main_Signals::load_more_data()) { Main_Signals::reset_load_more_data(); - const auto data = ECB::Data_Loader::load_from_url(options.as_string("signal_xml_url")); + const auto data = Data_Loader::load_from_url(options.as_string("signal_xml_url")); if (!data.empty()) { - ECB::Log::info("Loaded {} records", data.size()); + Log::info("Loaded {} records", data.size()); rates->add(data); } } @@ -142,12 +142,12 @@ int main(int argc, char *argv[]) std::this_thread::sleep_for(1s); } - ECB::Log::info("Stopping the web thread"); + Log::info("Stopping the web thread"); server.stop(); - ECB::Log::info("Waiting for web thread to join..."); + Log::info("Waiting for web thread to join..."); web_thread.join(); - ECB::Log::info("done"); + Log::info("done"); return 0; } diff --git a/src/Rates.cpp b/src/Rates.cpp index 26fb89f..ef8f0e1 100644 --- a/src/Rates.cpp +++ b/src/Rates.cpp @@ -1,26 +1,23 @@ #include "Rates.hpp" -namespace ECB +std::optional Rates::get(const Time_Point &tp, std::optional base) const { - std::optional Rates::get(const Time_Point &tp, std::optional base) const - { - std::scoped_lock lock(m_mutex); + std::scoped_lock lock(m_mutex); - const auto IT = m_data.find(tp); + const auto IT = m_data.find(tp); - if (IT == m_data.end()) - return {}; + if (IT == m_data.end()) + return {}; - Record ret = IT->second; + Record ret = IT->second; - if (!base || ret.base() == base) - return ret; + if (!base || ret.base() == base) + return ret; - // different base, so rebase - if (!ret.rebase(base.value())) // invalid base so return nothing - return {}; + // different base, so rebase + if (!ret.rebase(base.value())) // invalid base so return nothing + return {}; - // successfully rebased - return ret; - } -} // namespace ECB + // successfully rebased + return ret; +} diff --git a/src/Rates.hpp b/src/Rates.hpp index 8579b1f..e8eb2e2 100644 --- a/src/Rates.hpp +++ b/src/Rates.hpp @@ -8,57 +8,54 @@ #include #include -namespace ECB +// An object of this class stores exchange rates for different currencies at different time points and allows easy +// retrieval. A single record consists of a time point, base and a set of values for different currencies. Records +// can be added to this object and returned in with a different base or with different currencies. Only a single +// record is always returned. +class Rates { - // An object of this class stores exchange rates for different currencies at different time points and allows easy - // retrieval. A single record consists of a time point, base and a set of values for different currencies. Records - // can be added to this object and returned in with a different base or with different currencies. Only a single - // record is always returned. - class Rates +public: + // Clears the local database. + void clear() { - public: - // Clears the local database. - void clear() - { - std::scoped_lock lock(m_mutex); - m_data.clear(); - } + std::scoped_lock lock(m_mutex); + m_data.clear(); + } - // Returns number of stored records. - size_t count() const - { - std::scoped_lock lock(m_mutex); - return m_data.size(); - } - - std::optional last() const - { - std::scoped_lock lock(m_mutex); - if (m_data.empty()) - return {}; - return m_data.rbegin()->first; - } - - // Adds a new record to the local database. - void add(const Record &a_record) - { - std::scoped_lock lock(m_mutex); - m_data[a_record.time_point()] = a_record; - } - - // Adds a vector of records to the local database. - void add(const std::vector &a_records) - { - std::scoped_lock lock(m_mutex); - for (const auto &rec: a_records) - m_data[rec.time_point()] = rec; - } + // Returns number of stored records. + size_t count() const + { + std::scoped_lock lock(m_mutex); + return m_data.size(); + } - // Returns a record for the given time point. If the base is given, the record is rebased to the given base. - std::optional get(const Time_Point &tp, std::optional base) const; + std::optional last() const + { + std::scoped_lock lock(m_mutex); + if (m_data.empty()) + return {}; + return m_data.rbegin()->first; + } + + // Adds a new record to the local database. + void add(const Record &a_record) + { + std::scoped_lock lock(m_mutex); + m_data[a_record.time_point()] = a_record; + } - private: - std::map m_data; - mutable std::recursive_mutex m_mutex; - }; -} // namespace ECB + // Adds a vector of records to the local database. + void add(const std::vector &a_records) + { + std::scoped_lock lock(m_mutex); + for (const auto &rec: a_records) + m_data[rec.time_point()] = rec; + } + + // Returns a record for the given time point. If the base is given, the record is rebased to the given base. + std::optional get(const Time_Point &tp, std::optional base) const; + +private: + std::map m_data; + mutable std::recursive_mutex m_mutex; +}; diff --git a/src/Record.cpp b/src/Record.cpp index 4ceb452..86085a3 100644 --- a/src/Record.cpp +++ b/src/Record.cpp @@ -4,50 +4,47 @@ #include #include -namespace ECB +bool Record::rebase(const std::string &new_base) { - bool Record::rebase(const std::string &new_base) - { - if (m_base == new_base) - return false; + if (m_base == new_base) + return false; - // find the rate for the new base - auto new_base_rate = std::find_if(m_rates.begin(), m_rates.end(), - [&new_base](const Currency_Value &cv) { return cv.currency == new_base; }); + // find the rate for the new base + auto new_base_rate = std::find_if(m_rates.begin(), m_rates.end(), + [&new_base](const Currency_Value &cv) { return cv.currency == new_base; }); - if (new_base_rate == m_rates.end()) - return false; + if (new_base_rate == m_rates.end()) + return false; - // save the old value - double value_of_new_base_in_old_base = new_base_rate->value; + // save the old value + double value_of_new_base_in_old_base = new_base_rate->value; - // just divide all the rates by the value of the new base - for (auto &cv: m_rates) - cv.value /= value_of_new_base_in_old_base; + // just divide all the rates by the value of the new base + for (auto &cv: m_rates) + cv.value /= value_of_new_base_in_old_base; - // replace the rate of the new base with the old base and value - new_base_rate->currency = m_base; - new_base_rate->value = 1.0 / value_of_new_base_in_old_base; + // replace the rate of the new base with the old base and value + new_base_rate->currency = m_base; + new_base_rate->value = 1.0 / value_of_new_base_in_old_base; - // set the new base - m_base = new_base; + // set the new base + m_base = new_base; - return true; - } + return true; +} - std::string Record::as_string(bool with_base) const - { - std::stringstream ss; +std::string Record::as_string(bool with_base) const +{ + std::stringstream ss; - ss << static_cast(m_time_point); + ss << static_cast(m_time_point); - if (with_base) - ss << "(" + m_base + ")"; + if (with_base) + ss << "(" + m_base + ")"; - ss << ":"; + ss << ":"; - for (const auto &cv: m_rates) - ss << " " << cv.currency << "(" << std::fixed << std::setprecision(2) << cv.value << ")"; - return ss.str(); - } -} // namespace ECB + for (const auto &cv: m_rates) + ss << " " << cv.currency << "(" << std::fixed << std::setprecision(2) << cv.value << ")"; + return ss.str(); +} diff --git a/src/Record.hpp b/src/Record.hpp index f8cc9e8..3d4d897 100644 --- a/src/Record.hpp +++ b/src/Record.hpp @@ -6,36 +6,33 @@ #include #include -namespace ECB +// A single "record" consists of a time point, base and a set of values for different currencies. +// It is a simple container for storing the values. +class Record { - // A single "record" consists of a time point, base and a set of values for different currencies. - // It is a simple container for storing the values. - class Record - { - public: - Record() = default; +public: + Record() = default; - Record(const Time_Point &tp, const std::string &base, const std::vector &rates) - : m_time_point(tp), m_base(base), m_rates(rates) - { - } + Record(const Time_Point &tp, const std::string &base, const std::vector &rates) + : m_time_point(tp), m_base(base), m_rates(rates) + { + } - const Time_Point &time_point() const { return m_time_point; } - const std::string &base() const { return m_base; } - const std::vector &rates() const { return m_rates; } + const Time_Point &time_point() const { return m_time_point; } + const std::string &base() const { return m_base; } + const std::vector &rates() const { return m_rates; } - // Change the base currency of the record and all the rates accordingly. - // Returns true if the base was changed, false if it was the same or the new base was not found. - bool rebase(const std::string &new_base); + // Change the base currency of the record and all the rates accordingly. + // Returns true if the base was changed, false if it was the same or the new base was not found. + bool rebase(const std::string &new_base); - std::string as_string_with_base() const { return as_string(true); } - std::string as_string_without_base() const { return as_string(false); } + std::string as_string_with_base() const { return as_string(true); } + std::string as_string_without_base() const { return as_string(false); } - private: - std::string as_string(bool with_base) const; +private: + std::string as_string(bool with_base) const; - Time_Point m_time_point; - std::string m_base; - std::vector m_rates; - }; -} // namespace ECB + Time_Point m_time_point; + std::string m_base; + std::vector m_rates; +}; diff --git a/src/Server.cpp b/src/Server.cpp index 2b50798..11c6006 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -1,32 +1,28 @@ #include "Server.hpp" #include "Server_Impl.hpp" -namespace ECB +Server &Server::instance() { - Server &Server::instance() - { - static Server instance; - return instance; - } + static Server instance; + return instance; +} - Server::~Server() { stop(); } +Server::~Server() { stop(); } - bool Server::initialize(std::shared_ptr ecb, uint16_t port, bool listen_all) - { - const std::string listening_address = - std::string("http://") + (listen_all ? "0.0.0.0:" : "127.0.0.1:") + std::to_string(port); - - return m_impl->initialize(ecb, listening_address); - } +bool Server::initialize(std::shared_ptr ecb, uint16_t port, bool listen_all) +{ + const std::string listening_address = + std::string("http://") + (listen_all ? "0.0.0.0:" : "127.0.0.1:") + std::to_string(port); - void Server::set_pretty_json(bool pretty) { m_impl->set_pretty_json(pretty); } + return m_impl->initialize(ecb, listening_address); +} - void Server::set_precision(uint16_t precision) { m_impl->set_precision(precision); } +void Server::set_pretty_json(bool pretty) { m_impl->set_pretty_json(pretty); } - void Server::start() { m_impl->start_polling(); } +void Server::set_precision(uint16_t precision) { m_impl->set_precision(precision); } - void Server::stop() { m_impl->stop_polling(); } +void Server::start() { m_impl->start_polling(); } - Server::Server() : m_impl{std::make_unique()} {} +void Server::stop() { m_impl->stop_polling(); } -} // namespace ECB +Server::Server() : m_impl{std::make_unique()} {} diff --git a/src/Server.hpp b/src/Server.hpp index 45e8abb..2bb707f 100644 --- a/src/Server.hpp +++ b/src/Server.hpp @@ -2,36 +2,34 @@ #include -namespace ECB -{ - class Rates; // forward declaration - class Server_Impl; +// forward declarations +class Rates; +class Server_Impl; - // Singleton facade class to handle server requests. - // The actual implementation is in Server_Impl. This header file does not depend on mongoose.h. - class Server - { - public: - Server(const Server &) = delete; - Server &operator=(const Server &) = delete; +// Singleton facade class to handle server requests. +// The actual implementation is in Server_Impl. This header file does not depend on mongoose.h. +class Server +{ +public: + Server(const Server &) = delete; + Server &operator=(const Server &) = delete; - static Server &instance(); + static Server &instance(); - ~Server(); + ~Server(); - bool initialize(std::shared_ptr ecb, uint16_t port, bool listen_all); + bool initialize(std::shared_ptr ecb, uint16_t port, bool listen_all); - void set_pretty_json(bool pretty); + void set_pretty_json(bool pretty); - void set_precision(uint16_t precision); + void set_precision(uint16_t precision); - void start(); + void start(); - void stop(); + void stop(); - private: - Server(); +private: + Server(); - std::unique_ptr m_impl; - }; -} // namespace ECB + std::unique_ptr m_impl; +}; diff --git a/src/Server_Impl.cpp b/src/Server_Impl.cpp index 57b9bf3..189981b 100644 --- a/src/Server_Impl.cpp +++ b/src/Server_Impl.cpp @@ -7,198 +7,195 @@ #include -namespace ECB +const std::string_view Server_Impl::HEADER_NORMAL = "Content-Type: application/json\r\n"; +const std::string_view Server_Impl::HEADER_ERROR = "Content-Type: application/json\r\n"; + +Server_Impl::Server_Impl() { - const std::string_view Server_Impl::HEADER_NORMAL = "Content-Type: application/json\r\n"; - const std::string_view Server_Impl::HEADER_ERROR = "Content-Type: application/json\r\n"; + mg_mgr_init(&m_mgr); + m_json_builder["indentation"] = ""; + m_json_builder["precision"] = 6; // default is 17 +} + +Server_Impl::~Server_Impl() { mg_mgr_free(&m_mgr); } - Server_Impl::Server_Impl() +bool Server_Impl::initialize(std::shared_ptr rates, const std::string &listen_address) +{ + if (m_conn != nullptr) // already created { - mg_mgr_init(&m_mgr); - m_json_builder["indentation"] = ""; - m_json_builder["precision"] = 6; // default is 17 + Log::warn("Server_Impl::initialize() - already initialized"); + return false; } - Server_Impl::~Server_Impl() { mg_mgr_free(&m_mgr); } - - bool Server_Impl::initialize(std::shared_ptr rates, const std::string &listen_address) - { - if (m_conn != nullptr) // already created - { - Log::warn("Server_Impl::initialize() - already initialized"); - return false; - } + m_rates = rates; - m_rates = rates; + m_conn = mg_http_listen(&m_mgr, listen_address.c_str(), handler, this); - m_conn = mg_http_listen(&m_mgr, listen_address.c_str(), handler, this); + return m_conn != nullptr; +} - return m_conn != nullptr; - } +bool Server_Impl::is_historical_request(const mg_str *uri) const +{ + if (uri == nullptr) + return false; - bool Server_Impl::is_historical_request(const mg_str *uri) const - { - if (uri == nullptr) - return false; + static const std::string_view TEMPLATE = "/api/XXXX-XX-XX"; - static const std::string_view TEMPLATE = "/api/XXXX-XX-XX"; + if (uri->len != TEMPLATE.size()) + return false; - if (uri->len != TEMPLATE.size()) - return false; + // uri len is the same as the TEMPLATE + for (size_t pos = 0; pos < uri->len; ++pos) + { + const char c = uri->ptr[pos]; - // uri len is the same as the TEMPLATE - for (size_t pos = 0; pos < uri->len; ++pos) + // All "X" must be a digit, all other characters must match + if (TEMPLATE[pos] == 'X') { - const char c = uri->ptr[pos]; - - // All "X" must be a digit, all other characters must match - if (TEMPLATE[pos] == 'X') - { - if (c < '0' || c > '9') - return false; - } - else if (c != TEMPLATE[pos]) - { + if (c < '0' || c > '9') return false; - } } - return true; + else if (c != TEMPLATE[pos]) + { + return false; + } } + return true; +} - std::string Server_Impl::print_record(const Record &record, const std::vector &symbols) const - { - Json::Value ans; +std::string Server_Impl::print_record(const Record &record, const std::vector &symbols) const +{ + Json::Value ans; - ans["success"] = true; - ans["base"] = record.base(); - ans["date"] = static_cast(record.time_point()); - ans["rates"] = Json::Value(Json::objectValue); - auto &ans_rates = ans["rates"]; // alias + ans["success"] = true; + ans["base"] = record.base(); + ans["date"] = static_cast(record.time_point()); + ans["rates"] = Json::Value(Json::objectValue); + auto &ans_rates = ans["rates"]; // alias - if (symbols.empty()) + if (symbols.empty()) + { + // return all symbols + for (const auto &[sym, price]: record.rates()) + ans_rates[sym] = price; + } + else + { + // filter symbols + for (const auto &[sym, price]: record.rates()) { - // return all symbols - for (const auto &[sym, price]: record.rates()) + if (std::find(symbols.begin(), symbols.end(), sym) != symbols.end()) ans_rates[sym] = price; } - else - { - // filter symbols - for (const auto &[sym, price]: record.rates()) - { - if (std::find(symbols.begin(), symbols.end(), sym) != symbols.end()) - ans_rates[sym] = price; - } - } - - return Json::writeString(m_json_builder, ans); } - std::string Server_Impl::print_error(const std::string &msg) const - { - Json::Value ans; + return Json::writeString(m_json_builder, ans); +} - ans["success"] = false; - ans["error_text"] = msg; +std::string Server_Impl::print_error(const std::string &msg) const +{ + Json::Value ans; - return Json::writeString(m_json_builder, ans); - } + ans["success"] = false; + ans["error_text"] = msg; - std::optional Server_Impl::get_param_base(const mg_http_message *message) const - { - static const mg_str BASE = mg_str("base"); - mg_str var_base = mg_http_var(message->query, BASE); + return Json::writeString(m_json_builder, ans); +} - if (var_base.len > 0) - { - auto base = std::string(var_base.ptr, std::min(var_base.len, 3u)); - return Utils::uppercase(base); - } - return {}; - } +std::optional Server_Impl::get_param_base(const mg_http_message *message) const +{ + static const mg_str BASE = mg_str("base"); + mg_str var_base = mg_http_var(message->query, BASE); - std::vector Server_Impl::get_param_symbols(const mg_http_message *message) const + if (var_base.len > 0) { - static const mg_str SYMBOLS = mg_str("symbols"); - static constexpr uint32_t MAX_SYMBOLS_LEN = 4u * 50u; // 4 chars per symbol "eur," - mg_str var_symbols = mg_http_var(message->query, SYMBOLS); + auto base = std::string(var_base.ptr, std::min(var_base.len, 3u)); + return Utils::uppercase(base); + } + return {}; +} - if (var_symbols.len > 0) - { - auto symbols_str = std::string(var_symbols.ptr, std::min(var_symbols.len, MAX_SYMBOLS_LEN)); - Utils::uppercase(symbols_str); - return Utils::split(symbols_str, ','); - } - return {}; +std::vector Server_Impl::get_param_symbols(const mg_http_message *message) const +{ + static const mg_str SYMBOLS = mg_str("symbols"); + static constexpr uint32_t MAX_SYMBOLS_LEN = 4u * 50u; // 4 chars per symbol "eur," + mg_str var_symbols = mg_http_var(message->query, SYMBOLS); + + if (var_symbols.len > 0) + { + auto symbols_str = std::string(var_symbols.ptr, std::min(var_symbols.len, MAX_SYMBOLS_LEN)); + Utils::uppercase(symbols_str); + return Utils::split(symbols_str, ','); } + return {}; +} - void Server_Impl::handler(mg_connection *connection, int event, void *event_data) +void Server_Impl::handler(mg_connection *connection, int event, void *event_data) +{ + if (event == MG_EV_HTTP_MSG) { - if (event == MG_EV_HTTP_MSG) - { - auto *hm = reinterpret_cast(event_data); - auto *impl = reinterpret_cast(connection->fn_data); + auto *hm = reinterpret_cast(event_data); + auto *impl = reinterpret_cast(connection->fn_data); - impl->handle(connection, hm); - } + impl->handle(connection, hm); } +} - void Server_Impl::handle(mg_connection *connection, mg_http_message *message) - { - const bool is_latest = mg_http_match_uri(message, "/api/latest"); - const bool is_historical = (!is_latest && is_historical_request(&message->uri)); +void Server_Impl::handle(mg_connection *connection, mg_http_message *message) +{ + const bool is_latest = mg_http_match_uri(message, "/api/latest"); + const bool is_historical = (!is_latest && is_historical_request(&message->uri)); - if (!is_latest && !is_historical) - { - mg_http_reply(connection, 404, HEADER_ERROR.data(), print_error("Invalid request").c_str()); - return; - } + if (!is_latest && !is_historical) + { + mg_http_reply(connection, 404, HEADER_ERROR.data(), print_error("Invalid request").c_str()); + return; + } - // this is one of the two possible requests + // this is one of the two possible requests - // get time point. In case of historical request, the time point is in the uri /api/XXXX-XX-XX, so - // we need to extract it skipping the first 5 characters. - const std::optional tp = - (is_historical) ? std::make_optional(Time_Point{std::string{message->uri.ptr + 5, message->uri.len - 5}}) - : m_rates->last(); + // get time point. In case of historical request, the time point is in the uri /api/XXXX-XX-XX, so + // we need to extract it skipping the first 5 characters. + const std::optional tp = + (is_historical) ? std::make_optional(Time_Point{std::string{message->uri.ptr + 5, message->uri.len - 5}}) + : m_rates->last(); - if (!tp.has_value()) - { - mg_http_reply(connection, 404, HEADER_ERROR.data(), print_error("Time point not found").c_str()); - return; - } + if (!tp.has_value()) + { + mg_http_reply(connection, 404, HEADER_ERROR.data(), print_error("Time point not found").c_str()); + return; + } - // time point is valid, so proceed + // time point is valid, so proceed - // collect query parameters - const std::optional base = get_param_base(message); - const std::vector symbols = get_param_symbols(message); + // collect query parameters + const std::optional base = get_param_base(message); + const std::vector symbols = get_param_symbols(message); - // get record for the given time point - const auto record = m_rates->get(tp.value(), base); - if (record.has_value()) - { - const auto json_str = print_record(record.value(), symbols); - mg_http_reply(connection, 200, HEADER_NORMAL.data(), json_str.c_str()); - } - else - { - mg_http_reply(connection, 404, HEADER_ERROR.data(), - print_error("Record for given time stamp not found").c_str()); - } + // get record for the given time point + const auto record = m_rates->get(tp.value(), base); + if (record.has_value()) + { + const auto json_str = print_record(record.value(), symbols); + mg_http_reply(connection, 200, HEADER_NORMAL.data(), json_str.c_str()); } - - void Server_Impl::start_polling() + else { - if (m_conn == nullptr || m_running) - { - Log::warn("Server_Impl::start_polling() already running"); - return; - } + mg_http_reply(connection, 404, HEADER_ERROR.data(), + print_error("Record for given time stamp not found").c_str()); + } +} - Log::info("Server_Impl::start_polling() starting loop"); - m_running = true; - while (m_running) - mg_mgr_poll(&m_mgr, 500); +void Server_Impl::start_polling() +{ + if (m_conn == nullptr || m_running) + { + Log::warn("Server_Impl::start_polling() already running"); + return; } -} // namespace ECB + + Log::info("Server_Impl::start_polling() starting loop"); + m_running = true; + while (m_running) + mg_mgr_poll(&m_mgr, 500); +} diff --git a/src/Server_Impl.hpp b/src/Server_Impl.hpp index c92d42d..e3f4801 100644 --- a/src/Server_Impl.hpp +++ b/src/Server_Impl.hpp @@ -8,53 +8,50 @@ #include #include -namespace ECB -{ - class Rates; - class Record; +class Rates; +class Record; - class Server_Impl - { - public: - Server_Impl(); - ~Server_Impl(); +class Server_Impl +{ +public: + Server_Impl(); + ~Server_Impl(); - bool initialize(std::shared_ptr rates, const std::string &listen_address); - void set_pretty_json(bool pretty) { m_json_builder["indentation"] = pretty ? " " : ""; } - void set_precision(uint16_t precision) { m_json_builder["precision"] = precision; } + bool initialize(std::shared_ptr rates, const std::string &listen_address); + void set_pretty_json(bool pretty) { m_json_builder["indentation"] = pretty ? " " : ""; } + void set_precision(uint16_t precision) { m_json_builder["precision"] = precision; } - void start_polling(); - void stop_polling() { m_running = false; } + void start_polling(); + void stop_polling() { m_running = false; } - private: - // Handles the request generating a response. - void handle(mg_connection *connection, mg_http_message *message); +private: + // Handles the request generating a response. + void handle(mg_connection *connection, mg_http_message *message); - // Checks if request has format /api/dddd-dd-dd - bool is_historical_request(const mg_str *) const; + // Checks if request has format /api/dddd-dd-dd + bool is_historical_request(const mg_str *) const; - // Return record as json string. - std::string print_record(const Record &record, const std::vector &symbols) const; + // Return record as json string. + std::string print_record(const Record &record, const std::vector &symbols) const; - // Return error message as json string. - std::string print_error(const std::string &msg) const; + // Return error message as json string. + std::string print_error(const std::string &msg) const; - // Get optionally base if found in the message. - std::optional get_param_base(const mg_http_message *message) const; + // Get optionally base if found in the message. + std::optional get_param_base(const mg_http_message *message) const; - // Get symbols from the message. - std::vector get_param_symbols(const mg_http_message *message) const; + // Get symbols from the message. + std::vector get_param_symbols(const mg_http_message *message) const; - struct mg_mgr m_mgr = {}; - struct mg_connection *m_conn = nullptr; - bool m_running = false; - std::shared_ptr m_rates; - Json::StreamWriterBuilder m_json_builder; + struct mg_mgr m_mgr = {}; + struct mg_connection *m_conn = nullptr; + bool m_running = false; + std::shared_ptr m_rates; + Json::StreamWriterBuilder m_json_builder; - // must be static to be used as a callback for mongoose - static void handler(mg_connection *connection, int event, void *event_data); + // must be static to be used as a callback for mongoose + static void handler(mg_connection *connection, int event, void *event_data); - const static std::string_view HEADER_NORMAL; - const static std::string_view HEADER_ERROR; - }; -} // namespace ECB + const static std::string_view HEADER_NORMAL; + const static std::string_view HEADER_ERROR; +}; diff --git a/src/Time_Point.cpp b/src/Time_Point.cpp index a879e49..3e9d6a6 100644 --- a/src/Time_Point.cpp +++ b/src/Time_Point.cpp @@ -1,37 +1,34 @@ #include "Time_Point.hpp" #include "Log.hpp" -namespace ECB +Time_Point::Time_Point(const std::string &value) { - Time_Point::Time_Point(const std::string &value) + static const std::string TEMPLATE{"dddd-dd-dd"}; + + if (value.length() != TEMPLATE.length()) + { + Log::error("Initializing Time_Point with a string of length {} failed\n", value.length()); + return; + } + + // check format + for (size_t pos = 0; pos < TEMPLATE.length(); ++pos) { - static const std::string TEMPLATE{"dddd-dd-dd"}; + const char c = value[pos]; + + const bool c_is_expected_digit = (TEMPLATE[pos] == 'd') && (c >= '0' && c <= '9'); + const bool c_is_expected_separator = (TEMPLATE[pos] == '-') && (c == '-'); - if (value.length() != TEMPLATE.length()) + if (c_is_expected_digit || c_is_expected_separator) { - Log::error("Initializing Time_Point with a string of length {} failed\n", value.length()); - return; + continue; } - - // check format - for (size_t pos = 0; pos < TEMPLATE.length(); ++pos) + else { - const char c = value[pos]; - - const bool c_is_expected_digit = (TEMPLATE[pos] == 'd') && (c >= '0' && c <= '9'); - const bool c_is_expected_separator = (TEMPLATE[pos] == '-') && (c == '-'); - - if (c_is_expected_digit || c_is_expected_separator) - { - continue; - } - else - { - Log::error("Initializing Time_Point with a string '{}' failed\n", value); - return; - } + Log::error("Initializing Time_Point with a string '{}' failed\n", value); + return; } - - m_date = value; } -} // namespace ECB + + m_date = value; +} diff --git a/src/Time_Point.hpp b/src/Time_Point.hpp index e129072..bfd2503 100644 --- a/src/Time_Point.hpp +++ b/src/Time_Point.hpp @@ -2,29 +2,26 @@ #include -namespace ECB +// Represents a time point in the format "yyyy-mm-dd". +// No checking is made on the validity of the date. +class Time_Point { - // Represents a time point in the format "yyyy-mm-dd". - // No checking is made on the validity of the date. - class Time_Point - { - public: - Time_Point() = default; +public: + Time_Point() = default; - Time_Point(const std::string &value); + Time_Point(const std::string &value); - bool is_set() const { return !m_date.empty(); } + bool is_set() const { return !m_date.empty(); } - bool operator==(const Time_Point &other) const { return m_date == other.m_date; } - bool operator!=(const Time_Point &other) const { return m_date != other.m_date; } - bool operator<(const Time_Point &other) const { return m_date < other.m_date; } - bool operator>(const Time_Point &other) const { return m_date > other.m_date; } - bool operator<=(const Time_Point &other) const { return m_date <= other.m_date; } - bool operator>=(const Time_Point &other) const { return m_date >= other.m_date; } + bool operator==(const Time_Point &other) const { return m_date == other.m_date; } + bool operator!=(const Time_Point &other) const { return m_date != other.m_date; } + bool operator<(const Time_Point &other) const { return m_date < other.m_date; } + bool operator>(const Time_Point &other) const { return m_date > other.m_date; } + bool operator<=(const Time_Point &other) const { return m_date <= other.m_date; } + bool operator>=(const Time_Point &other) const { return m_date >= other.m_date; } - operator std::string() const { return m_date; } + operator std::string() const { return m_date; } - private: - std::string m_date; // textual representation - }; -} // namespace ECB +private: + std::string m_date; // textual representation +}; diff --git a/src/Urls.hpp b/src/Urls.hpp index 50b5ebc..cca3f45 100644 --- a/src/Urls.hpp +++ b/src/Urls.hpp @@ -2,11 +2,6 @@ #include -namespace ECB -{ - static const std::string ECB_URL_BASE{"https://www.ecb.europa.eu/stats/eurofxref/"}; - - static const std::string ECB_URL_HIST = ECB_URL_BASE + "eurofxref-hist.xml"; - static const std::string ECB_URL_DAILY = ECB_URL_BASE + "eurofxref-daily.xml"; - -} // namespace ECB +static const std::string ECB_URL_BASE{"https://www.ecb.europa.eu/stats/eurofxref/"}; +static const std::string ECB_URL_HIST = ECB_URL_BASE + "eurofxref-hist.xml"; +static const std::string ECB_URL_DAILY = ECB_URL_BASE + "eurofxref-daily.xml"; diff --git a/src/Utils.cpp b/src/Utils.cpp index cf3a684..8909a89 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -3,25 +3,22 @@ #include #include -namespace ECB +std::vector Utils::split(const std::string &a_string, char a_delimiter) { - std::vector Utils::split(const std::string &a_string, char a_delimiter) - { - std::stringstream ss(a_string); - std::string item; - std::vector elems; + std::stringstream ss(a_string); + std::string item; + std::vector elems; - while (std::getline(ss, item, a_delimiter)) - { - elems.emplace_back(item.c_str()); - } - return elems; + while (std::getline(ss, item, a_delimiter)) + { + elems.emplace_back(item.c_str()); } + return elems; +} - std::string &Utils::uppercase(std::string &a_string) - { - std::transform(a_string.begin(), a_string.end(), a_string.begin(), [](char c) { return std::toupper(c); }); +std::string &Utils::uppercase(std::string &a_string) +{ + std::transform(a_string.begin(), a_string.end(), a_string.begin(), [](char c) { return std::toupper(c); }); - return a_string; - } -} // namespace ECB + return a_string; +} diff --git a/src/Utils.hpp b/src/Utils.hpp index d60ff12..67378b2 100644 --- a/src/Utils.hpp +++ b/src/Utils.hpp @@ -3,15 +3,12 @@ #include #include -namespace ECB +class Utils { - class Utils - { - public: - // Split given string using given delimiter. - static std::vector split(const std::string &a_string, char a_delimiter); +public: + // Split given string using given delimiter. + static std::vector split(const std::string &a_string, char a_delimiter); - // Makes string uppercase inplace. - static std::string &uppercase(std::string &a_string); - }; -} // namespace ECB + // Makes string uppercase inplace. + static std::string &uppercase(std::string &a_string); +}; diff --git a/src/Version_Info.cpp.in b/src/Version_Info.cpp.in index 0f2fc97..dea7174 100644 --- a/src/Version_Info.cpp.in +++ b/src/Version_Info.cpp.in @@ -1,6 +1,6 @@ #include "Version_Info.hpp" -namespace ECB::Version_Info +namespace Version_Info { const std::string HASH{"@GIT_HASH@"}; const std::string DATE{"@GIT_DATE@"}; diff --git a/src/Version_Info.hpp b/src/Version_Info.hpp index bf5edb8..c285d88 100644 --- a/src/Version_Info.hpp +++ b/src/Version_Info.hpp @@ -2,8 +2,8 @@ #include -namespace ECB::Version_Info +namespace Version_Info { extern const std::string HASH; extern const std::string DATE; -} // namespace ECB::Version_Info +} // namespace Version_Info diff --git a/tests/Rates_Tests.cpp b/tests/Rates_Tests.cpp index 4f5acf4..e0d5fe0 100644 --- a/tests/Rates_Tests.cpp +++ b/tests/Rates_Tests.cpp @@ -2,8 +2,6 @@ #include "Rates.hpp" -using namespace ECB; - TEST(Rates, Clear) { Rates rates; diff --git a/tests/Record_Tests.cpp b/tests/Record_Tests.cpp index 2618a3e..d44200e 100644 --- a/tests/Record_Tests.cpp +++ b/tests/Record_Tests.cpp @@ -2,8 +2,6 @@ #include "Record.hpp" -using namespace ECB; - TEST(Record, AlmostEmpty) { Record rec(Time_Point("1234-56-78"), "EUR", {}); diff --git a/tests/Time_Point_Tests.cpp b/tests/Time_Point_Tests.cpp index be621ac..4986103 100644 --- a/tests/Time_Point_Tests.cpp +++ b/tests/Time_Point_Tests.cpp @@ -4,8 +4,6 @@ #include -using namespace ECB; - TEST(Time_Point, Assigning_Invalid_Data_Results_In_Empty_Time_Point) { // clang-format off diff --git a/tests/Utils_Tests.cpp b/tests/Utils_Tests.cpp index f665408..e0354c0 100644 --- a/tests/Utils_Tests.cpp +++ b/tests/Utils_Tests.cpp @@ -9,21 +9,21 @@ TEST(Utils, SplitString) { std::vector out; - out = ECB::Utils::split("", ' '); + out = Utils::split("", ' '); ASSERT_EQ(out.size(), 0); - out = ECB::Utils::split("", ','); + out = Utils::split("", ','); ASSERT_EQ(out.size(), 0); - out = ECB::Utils::split("a", ','); + out = Utils::split("a", ','); ASSERT_EQ(out.size(), 1); ASSERT_EQ(out[0], "a"); - out = ECB::Utils::split("b,", ','); + out = Utils::split("b,", ','); ASSERT_EQ(out.size(), 1); ASSERT_EQ(out[0], "b"); - out = ECB::Utils::split("usd,eur,pln", ','); + out = Utils::split("usd,eur,pln", ','); ASSERT_EQ(out.size(), 3); ASSERT_EQ(out[0], "usd"); ASSERT_EQ(out[1], "eur");