Skip to content

Commit

Permalink
Create abstraction around conversion facilities
Browse files Browse the repository at this point in the history
These changes create a thin layer wrapper for conversions between basic types (e.g. std::string, int), allowing to encapsulate all uses of boost::lexical_cast.
  • Loading branch information
marcosbento committed Oct 23, 2023
1 parent 0c7aac9 commit 4fb8f66
Show file tree
Hide file tree
Showing 127 changed files with 692 additions and 522 deletions.
78 changes: 78 additions & 0 deletions ACore/src/Converter.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* 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 To>
struct converter_traits
{
template <typename From>
inline static auto convert(From&& v) {
return try_lexical_convert<To>(std::forward<From>(v));
}
};

template <>
struct converter_traits<std::string>
{
template <typename From>
inline static auto convert(From&& v) {

if constexpr (std::is_same_v<From, char>) {
return std::string{v};
}
else if constexpr (std::is_same_v<std::remove_cv_t<From>, const char*>) {
return std::string(v);
}
else if constexpr (std::is_integral_v<From> || std::is_floating_point_v<From>) {
return std::to_string(v);
}

return try_lexical_convert<std::string>(std::forward<From>(v));
}
};

} // namespace details

template <typename To, typename From>
inline auto convert_to(From v) {
using namespace ecf::details;
return converter_traits<To>::convert(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
8 changes: 4 additions & 4 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 @@ -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
4 changes: 2 additions & 2 deletions ACore/test/TestCommandLine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@

#include <iostream>

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

#include "CommandLine.hpp"
#include "Converter.hpp"

using namespace boost;
using namespace std;
Expand Down Expand Up @@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(test_command_line_with_2_args) {
BOOST_AUTO_TEST_CASE(test_command_line_with_10_args) {
std::vector<std::string> theArgs(10);
for (int i = 0; i < 10; i++) {
theArgs.push_back("arg"s + lexical_cast<string>(i));
theArgs.push_back("arg"s + ecf::convert_to<std::string>(i));
}
doCheck(theArgs);
}
Expand Down
Loading

0 comments on commit 4fb8f66

Please sign in to comment.