Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create abstraction around conversion facilities ECFLOW-1922 #45

Merged
merged 4 commits into from
Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions ACore/src/Converter.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright 2023- ECMWF.
*
* This software is licensed under the terms of the Apache Licence version 2.0
* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
* In applying this licence, ECMWF does not waive the privileges and immunities
* granted to it by virtue of its status as an intergovernmental organisation
* nor does it submit to any jurisdiction.
*/

#ifndef ECFLOW_CORE_CONVERTER_HPP
#define ECFLOW_CORE_CONVERTER_HPP

#include <string>
#include <utility>

#include <boost/lexical_cast.hpp>

namespace ecf {

struct bad_conversion : public std::runtime_error
{
explicit bad_conversion(const char* m) : std::runtime_error(m) {}
explicit bad_conversion(const std::string& m) : std::runtime_error(m) {}
};

namespace details {

template <typename To, typename From>
inline static auto try_lexical_convert(From&& v) {
try {
return boost::lexical_cast<To>(v);
}
catch (const boost::bad_lexical_cast& e) {
throw bad_conversion(e.what());
}
}

}

template <typename From, typename To>
struct converter_traits
{
inline static auto convert(From&& v) {
return details::try_lexical_convert<To>(std::forward<From>(v));
}
};

template <>
struct converter_traits<char, std::string>
{
inline static auto convert(char v) { return std::string{v}; }
};

template <>
struct converter_traits<const char*, std::string>
{
inline static auto convert(const char* v) { return std::string{v}; }
};

template <typename From>
struct converter_traits<From, std::enable_if<std::is_integral_v<From> || std::is_floating_point_v<From>,std::string>>
{
inline static auto convert(From&& v) { return std::to_string(v); }
};

template <typename To, typename From>
inline auto convert_to(From&& v) {
using namespace ecf::details;
return converter_traits<From, To>::convert(std::forward<From>(v));
}

} // namespace ecf

#endif
4 changes: 2 additions & 2 deletions ACore/src/EcfPortLock.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,16 @@

#include <boost/filesystem.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/lexical_cast.hpp>

#include "Converter.hpp"
#include "File.hpp"

namespace ecf {

class EcfPortLock {
public:
static bool is_free(int port, bool debug = false) {
std::string the_port = boost::lexical_cast<std::string>(port);
std::string the_port = ecf::convert_to<std::string>(port);
if (boost::filesystem::exists(port_file(the_port))) {
if (debug)
std::cout << " EcfPortLock::is_free(" << port << ") returning FALSE\n ";
Expand Down
7 changes: 4 additions & 3 deletions ACore/src/Extract.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
#include <stdexcept>

#include <boost/date_time/posix_time/time_formatters.hpp> // requires boost date and time lib
#include <boost/lexical_cast.hpp>

#include "Converter.hpp"

// #define DEBUG_PARSER 1

Expand Down Expand Up @@ -73,9 +74,9 @@ bool Extract::split_get_second(const std::string& str, std::string& ret, char se
int Extract::theInt(const std::string& token, const std::string& errorMsg) {
int the_int = -1;
try {
the_int = boost::lexical_cast<int>(token);
the_int = ecf::convert_to<int>(token);
}
catch (boost::bad_lexical_cast& e) {
catch (const ecf::bad_conversion&) {
throw std::runtime_error(errorMsg);
}
return the_int;
Expand Down
14 changes: 7 additions & 7 deletions ACore/src/PasswdFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
#include <iostream>

#include <boost/algorithm/string/trim.hpp>
#include <boost/lexical_cast.hpp>

#include "Converter.hpp"
#include "File.hpp"
#include "PasswordEncryption.hpp"
#include "Str.hpp"
Expand Down Expand Up @@ -227,9 +227,9 @@ bool PasswdFile::validateVersionNumber(const std::string& line, std::string& err
}

try {
auto major = boost::lexical_cast<int>(versionNumberTokens[0]);
auto minor = boost::lexical_cast<int>(versionNumberTokens[1]);
auto part = boost::lexical_cast<int>(versionNumberTokens[2]);
auto major = ecf::convert_to<int>(versionNumberTokens[0]);
auto minor = ecf::convert_to<int>(versionNumberTokens[1]);
auto part = ecf::convert_to<int>(versionNumberTokens[2]);
if (major < 4) {
errorMsg += "Only passwd files with a version >= 4.5.0 is supported\n";
return false;
Expand All @@ -243,7 +243,7 @@ bool PasswdFile::validateVersionNumber(const std::string& line, std::string& err
return false;
}
}
catch (boost::bad_lexical_cast&) {
catch (const ecf::bad_conversion&) {
errorMsg += "Invalid version number \n";
return false;
}
Expand All @@ -268,9 +268,9 @@ bool PasswdFile::add_user(std::vector<std::string>& tokens, std::string& error_m
}

try {
boost::lexical_cast<int>(tokens[2]);
ecf::convert_to<int>(tokens[2]);
}
catch (boost::bad_lexical_cast&) {
catch (const ecf::bad_conversion&) {
error_msg += "Port number must be integer's\n";
return false;
}
Expand Down
6 changes: 3 additions & 3 deletions ACore/src/Pid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@
#include <stdexcept>
#include <unistd.h> // for getpid

#include <boost/lexical_cast.hpp>
#include "Converter.hpp"

std::string Pid::getpid() {
std::string pid;
try {
pid = boost::lexical_cast<std::string>(::getpid());
pid = ecf::convert_to<std::string>(::getpid());
}
catch (boost::bad_lexical_cast& e) {
catch (const ecf::bad_conversion&) {
throw std::runtime_error("Pid::getpid(): Could not convert PID to a string\n");
}
return pid;
Expand Down
7 changes: 4 additions & 3 deletions ACore/src/Str.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@
//
// Description : This class is used as a helper class
//============================================================================

#include "Str.hpp"

#include <boost/lexical_cast.hpp>
#include "Converter.hpp"

using namespace std;

Expand Down Expand Up @@ -529,9 +530,9 @@ bool Str::valid_name(const std::string& name) {
int Str::to_int(const std::string& the_str, int error_return) {
if (the_str.find_first_of(Str::NUMERIC(), 0) != std::string::npos) {
try {
return boost::lexical_cast<int>(the_str);
return ecf::convert_to<int>(the_str);
}
catch (boost::bad_lexical_cast&) {
catch (const ecf::bad_conversion&) {
}
}
return error_return;
Expand Down
11 changes: 7 additions & 4 deletions ACore/src/Str.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,13 @@ class Str {
static bool valid_name(const std::string& name, std::string& msg);
static bool valid_name(const std::string& name);

/// Use this function when you are not sure if string is convertible to an integer.
/// This function will check if string has a numeric first & hence faster than
/// using boost::lexical_cast< int > alone. Will trap any exception
/// will return numeric_limits<int>::max() for invalid conversions
/// This function checks if the given string actually has any digits before attempting the conversion;
/// this approach is faster than using ecf::convert_to<int> directly (and thus always attempt to
/// perform the conversion).
/// Use this function when it is not possible to ensure the string is convertible to an integer (e.g. user input).
///
/// This function return the given `error_return` (by default, numeric_limits<int>::max()),
/// in cases where the conversion is invalid.
static int to_int(const std::string&, int error_return = std::numeric_limits<int>::max());

/// Truncate the input string at the start/end if exceeds max_lines_ newlines
Expand Down
7 changes: 3 additions & 4 deletions ACore/src/TimeSlot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@

#include <ostream>

#include <boost/lexical_cast.hpp>

#include "Converter.hpp"
#include "Serialization.hpp"
#include "Str.hpp"

Expand Down Expand Up @@ -72,12 +71,12 @@ void TimeSlot::write(std::string& ret) const {

if (h_ < 10)
ret += "0";
ret += boost::lexical_cast<std::string>(h_);
ret += ecf::convert_to<std::string>(h_);

ret += Str::COLON();
if (m_ < 10)
ret += "0";
ret += boost::lexical_cast<std::string>(m_);
ret += ecf::convert_to<std::string>(m_);
}

boost::posix_time::time_duration TimeSlot::duration() const {
Expand Down
17 changes: 9 additions & 8 deletions ACore/src/Version.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@
//
// Description :
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8

#include "Version.hpp"

#include <sstream>

#include <boost/lexical_cast.hpp>
#include <boost/version.hpp>
#include <cereal/version.hpp>

#include "Converter.hpp"
#include "ecflow_version.h"

namespace ecf {
Expand Down Expand Up @@ -81,20 +82,20 @@ std::string Version::description() {

std::string Version::version() {
std::string ret = "ecflow_";
ret += boost::lexical_cast<std::string>(ECFLOW_RELEASE);
ret += ecf::convert_to<std::string>(ECFLOW_RELEASE);
ret += "_";
ret += boost::lexical_cast<std::string>(ECFLOW_MAJOR);
ret += ecf::convert_to<std::string>(ECFLOW_MAJOR);
ret += "_";
ret += boost::lexical_cast<std::string>(ECFLOW_MINOR);
ret += ecf::convert_to<std::string>(ECFLOW_MINOR);
return ret;
}

std::string Version::raw() {
std::string ret = boost::lexical_cast<std::string>(ECFLOW_RELEASE);
std::string ret = ecf::convert_to<std::string>(ECFLOW_RELEASE);
ret += ".";
ret += boost::lexical_cast<std::string>(ECFLOW_MAJOR);
ret += ecf::convert_to<std::string>(ECFLOW_MAJOR);
ret += ".";
ret += boost::lexical_cast<std::string>(ECFLOW_MINOR);
ret += ecf::convert_to<std::string>(ECFLOW_MINOR);
return ret;
}

Expand All @@ -111,7 +112,7 @@ std::string Version::compiler() {
#if defined(_AIX)
ss << "aix " << __IBMCPP__;
#elif defined(HPUX)
ss << "aCC " << __HP_aCC; // type aCC +help, this will show compiler manual, search for Predefined Macros
ss << "aCC " << __HP_aCC; // type aCC +help, this will show compiler manual, search for Predefined Macros
#else
#if defined(__clang__)
// To find the list of defines for clang use:
Expand Down
11 changes: 6 additions & 5 deletions ACore/src/WhiteListFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@
//
// Description : Parser for white list file
//============================================================================

#include "WhiteListFile.hpp"

#include <iostream>
#include <vector>

#include <boost/algorithm/string/trim.hpp>
#include <boost/lexical_cast.hpp>

#include "Converter.hpp"
#include "File.hpp"
#include "Str.hpp"
#include "User.hpp"
Expand Down Expand Up @@ -356,9 +357,9 @@ bool WhiteListFile::validateVersionNumber(const std::string& line, std::string&
}

try {
auto major = boost::lexical_cast<int>(versionNumberTokens[0]);
auto minor = boost::lexical_cast<int>(versionNumberTokens[1]);
auto part = boost::lexical_cast<int>(versionNumberTokens[2]);
auto major = ecf::convert_to<int>(versionNumberTokens[0]);
auto minor = ecf::convert_to<int>(versionNumberTokens[1]);
auto part = ecf::convert_to<int>(versionNumberTokens[2]);
if (major < 4) {
errorMsg += "Only white list files with a version >= 4.4.5 is supported\n";
return false;
Expand All @@ -372,7 +373,7 @@ bool WhiteListFile::validateVersionNumber(const std::string& line, std::string&
return false;
}
}
catch (boost::bad_lexical_cast&) {
catch (const ecf::bad_conversion&) {
errorMsg += "Invalid version number \n";
return false;
}
Expand Down
2 changes: 0 additions & 2 deletions ACore/src/perf_timer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
#include <string>
#include <vector>

#include <boost/lexical_cast.hpp>

// remove when we use c++17
template <typename F, typename... Args>
auto invoke(F f, Args&&... args) -> decltype(std::ref(f)(std::forward<Args>(args)...)) {
Expand Down
3 changes: 2 additions & 1 deletion ACore/test/TestCalendar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include "Cal.hpp"
#include "Calendar.hpp"
#include "Converter.hpp"
#include "Str.hpp"
#include "TimeSeries.hpp"

Expand Down Expand Up @@ -537,7 +538,7 @@ BOOST_AUTO_TEST_CASE(test_calendar_julian) {
long boost_julian = cal_date.julian_day();

std::string iso_string = to_iso_string(cal_date);
auto date_as_long = boost::lexical_cast<long>(iso_string);
auto date_as_long = ecf::convert_to<long>(iso_string);
long ecmwf_julian = Cal::date_to_julian(date_as_long);

BOOST_CHECK_MESSAGE(boost_julian == ecmwf_julian,
Expand Down
9 changes: 0 additions & 9 deletions ACore/test/TestClassDataMemberInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
#include <string>
#include <vector>

#include <boost/lexical_cast.hpp>
#include <boost/test/unit_test.hpp>

using namespace boost;
Expand Down Expand Up @@ -83,14 +82,6 @@ BOOST_AUTO_TEST_SUITE(CoreTestSuite)
BOOST_AUTO_TEST_CASE(test_class_data_member_init) {
cout << "ACore:: ...test_class_data_member_init \n";

// // MyType needs noexcept on move copy constructor, during vec resize.
// std::vector<MyType> vec;
// for(int i =0; i < 4; i++) {
// //vec.push_back(MyType(boost::lexical_cast<string>(i)));
// vec.emplace_back(boost::lexical_cast<string>(i));
// cout << vec.size() << " " << vec.capacity() << endl;
// }

{
MyType type("ABC");
auto tmoved = std::move(type);
Expand Down
Loading
Loading