Skip to content

Instantly share code, notes, and snippets.

@dylanliuh2o
Last active May 31, 2024 02:47
Show Gist options
  • Save dylanliuh2o/66100ab5af2aa23eb144c7bafc5eed1f to your computer and use it in GitHub Desktop.
Save dylanliuh2o/66100ab5af2aa23eb144c7bafc5eed1f to your computer and use it in GitHub Desktop.
Mode Maintainable Cpp String Conversion
cmake_minimum_required(VERSION 3.20)
project(string_conversion_exception)
set(CMAKE_CXX_STANDARD_REQUIRED 17)
find_package(Boost 1.74 REQUIRED)
if (Boost_FOUND)
message("Boost found")
add_executable(main main.cpp)
else()
message("Boost not found")
endif()
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>
#include <map>
#include <boost/format.hpp>
using boost::format ;
template <typename... Args>
void
log_none(const std::string &prefix, format fmt, Args... args)
{
std::ostringstream oss ;
if (!prefix.empty()) {
oss << format("[%s] ") % prefix ;
}
oss << (fmt % ... % args) ;
std::cout << oss.str() << std::endl ;
}
template <typename... Args>
void
log_info(const std::string &prefix, format fmt, Args... args)
{
std::ostringstream oss ;
if (!prefix.empty()) {
oss << format("[%s] ") % prefix ;
}
oss << "INFO: " ;
oss << (fmt % ... % args) ;
std::cout << oss.str() << std::endl ;
}
template <typename... Args>
void
log_warning(const std::string &prefix, format fmt, Args... args)
{
std::ostringstream oss ;
if (!prefix.empty()) {
oss << format("[%s] ") % prefix ;
}
oss << "WARNING: " ;
oss << (fmt % ... % args) ;
std::cout << oss.str() << std::endl ;
}
template <typename... Args>
void
log_error(const std::string &prefix, format fmt, Args... args)
{
std::ostringstream oss ;
if (!prefix.empty()) {
oss << format("[%s] ") % prefix ;
}
oss << "ERROR: " ;
oss << (fmt % ... % args) ;
std::cout << oss.str() << std::endl ;
}
struct Data
{
int total = -1 ;
int covered = -1 ;
double percentage = -1 ;
int count = -1 ;
double x = -1 ;
double y = -1 ;
double z = -1 ;
int pos = -1 ;
} ;
int main(int argc, char *argv[])
{
bool bad_data = false ;
if (argc > 1 && std::string(argv[1]) == "--bad_data") {
bad_data = true ;
}
std::map<std::string, std::string> data_map ;
if (bad_data) {
std::map<std::string, std::string> m {
{ "total", "fj239" },
{ "covered", "aslkdjf" },
{ "percentage", "x1.0" },
{ "count", "777777777777777777777777777777777777777777777777777777777777" },
{ "x", "h3.2" },
{ "y", "x2.1" },
{ "z", "d1.8" },
{ "pos", "h51" },
} ;
data_map = m ;
} else {
std::map<std::string, std::string> m {
{ "total", "239" },
{ "covered", "123" },
{ "percentage", "51.5" },
{ "count", "7" },
{ "x", "3.2" },
{ "y", "2.1" },
{ "z", "1.8" },
{ "pos", "51" },
} ;
data_map = m ;
}
// too verbose, hard to maintain
{
Data data_1 ;
try {
data_1.total = data_map["total"].empty() ? -1 : std::stoi(data_map["total"]) ;
} catch (std::invalid_argument &e) {
log_error("MAIN", format("Failed to convert '%s' into int, might contains unrecognized syntax!"), data_map["total"]) ;
} catch (std::out_of_range &e) {
log_error("MAIN", format("Failed to convert '%s' into int, value is out of range!"), data_map["total"]) ;
}
try {
data_1.covered = data_map["covered"].empty() ? -1 : std::stoi(data_map["covered"]) ;
} catch (std::invalid_argument &e) {
log_error("MAIN", format("Failed to convert '%s' into int, might contains unrecognized syntax!"), data_map["covered"]) ;
} catch (std::out_of_range &e) {
log_error("MAIN", format("Failed to convert '%s' into int, value is out of range!"), data_map["covered"]) ;
}
try {
data_1.percentage = data_map["percentage"].empty() ? -1 : std::stod(data_map["percentage"]) ;
} catch (std::invalid_argument &e) {
log_error("MAIN", format("Failed to convert '%s' into double, might contains unrecognized syntax!"), data_map["percentage"]) ;
} catch (std::out_of_range &e) {
log_error("MAIN", format("Failed to convert '%s' into double, value is out of range!"), data_map["percentage"]) ;
}
try {
data_1.count = data_map["count"].empty() ? -1 : std::stoi(data_map["count"]) ;
} catch (std::invalid_argument &e) {
log_error("MAIN", format("Failed to convert '%s' into int, might contains unrecognized syntax!"), data_map["count"]) ;
} catch (std::out_of_range &e) {
log_error("MAIN", format("Failed to convert '%s' into int, value is out of range!"), data_map["count"]) ;
}
try {
data_1.x = data_map["x"].empty() ? -1 : std::stod(data_map["x"]) ;
} catch (std::invalid_argument &e) {
log_error("MAIN", format("Failed to convert '%s' into double, might contains unrecognized syntax!"), data_map["x"]) ;
} catch (std::out_of_range &e) {
log_error("MAIN", format("Failed to convert '%s' into double, value is out of range!"), data_map["x"]) ;
}
try {
data_1.y = data_map["y"].empty() ? -1 : std::stod(data_map["y"]) ;
} catch (std::invalid_argument &e) {
log_error("MAIN", format("Failed to convert '%s' into double, might contains unrecognized syntax!"), data_map["y"]) ;
} catch (std::out_of_range &e) {
log_error("MAIN", format("Failed to convert '%s' into double, value is out of range!"), data_map["y"]) ;
}
try {
data_1.z = data_map["z"].empty() ? -1 : std::stod(data_map["z"]) ;
} catch (std::invalid_argument &e) {
log_error("MAIN", format("Failed to convert '%s' into double, might contains unrecognized syntax!"), data_map["z"]) ;
} catch (std::out_of_range &e) {
log_error("MAIN", format("Failed to convert '%s' into double, value is out of range!"), data_map["z"]) ;
}
try {
data_1.pos = data_map["pos"].empty() ? -1 : std::stoi(data_map["pos"]) ;
} catch (std::invalid_argument &e) {
log_error("MAIN", format("Failed to convert '%s' into int, might contains unrecognized syntax!"), data_map["pos"]) ;
} catch (std::out_of_range &e) {
log_error("MAIN", format("Failed to convert '%s' into int, value is out of range!"), data_map["pos"]) ;
}
log_info("MAIN", format("data_1: { total: %d, covered: %d, percentage: %.2f%%, count: %d, x: %.2f, y: %.2f, z: %2.f, pos: %d }"), data_1.total, data_1.covered, data_1.percentage, data_1.count, data_1.x, data_1.y, data_1.z, data_1.pos) ;
}
log_none("", format("")) ;
// more tidy, more readable, easier to maintain
{
enum class TargetType { Int = 0, Double } ;
std::map<TargetType, std::string> type_to_string {
{ TargetType::Int, "int" },
{ TargetType::Double, "double" },
} ;
Data data_2 ;
std::vector<std::string> data { data_map["total"], data_map["percentage"], data_map["covered"], data_map["count"], data_map["x"], data_map["y"], data_map["z"], data_map["pos"] } ;
std::vector<TargetType> data_types { TargetType::Int, TargetType::Double, TargetType::Int, TargetType::Int, TargetType::Double, TargetType::Double, TargetType::Double, TargetType::Int } ;
for (decltype(data.size()) i = 0; i < data.size(); i++) {
std::string raw_data = data[i] ;
TargetType target_type = data_types[i] ;
int value_int = -1 ;
double value_double = -1 ;
switch (target_type) {
case TargetType::Int:
try {
value_int = raw_data.empty() ? -1 : std::stoi(raw_data) ;
} catch (std::invalid_argument &e) {
log_error("MAIN", format("Failed to convert '%s' into %s, might contains unrecognized syntax!"), raw_data, type_to_string[target_type]) ;
} catch (std::out_of_range &e) {
log_error("MAIN", format("Failed to convert '%s' into %s, value is out of range!"), raw_data, type_to_string[target_type]) ;
}
break ;
case TargetType::Double:
try {
value_double = raw_data.empty() ? -1 : std::stod(raw_data) ;
} catch (std::invalid_argument &e) {
log_error("MAIN", format("Failed to convert '%s' into %s, might contains unrecognized syntax!"), raw_data, type_to_string[target_type]) ;
} catch (std::out_of_range &e) {
log_error("MAIN", format("Failed to convert '%s' into %s, value is out of range!"), raw_data, type_to_string[target_type]) ;
}
break ;
default:
log_error("MAIN", format("Unexpect target_type '%d'!"), static_cast<int>(target_type)) ;
break ;
}
switch (i) {
case 0: data_2.total = value_int ; break ;
case 1: data_2.percentage = value_double ; break ;
case 2: data_2.covered = value_int ; break ;
case 3: data_2.count = value_int ; break ;
case 4: data_2.x = value_double ; break ;
case 5: data_2.y = value_double ; break ;
case 6: data_2.z = value_double ; break ;
case 7: data_2.pos = value_int ; break ;
default: break ;
}
}
log_info("MAIN", format("data_2: { total: %d, covered: %d, percentage: %.2f%%, count: %d, x: %.2f, y: %.2f, z: %2.f, pos: %d }"), data_2.total, data_2.covered, data_2.percentage, data_2.count, data_2.x, data_2.y, data_2.z, data_2.pos) ;
}
return 0 ;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment