SST  15.1.0
StructuralSimulationToolkit
from_string.h
1 // Copyright 2009-2025 NTESS. Under the terms
2 // of Contract DE-NA0003525 with NTESS, the U.S.
3 // Government retains certain rights in this software.
4 //
5 // Copyright (c) 2009-2025, NTESS
6 // All rights reserved.
7 //
8 // This file is part of the SST software package. For license
9 // information, see the LICENSE file in the top level directory of the
10 // distribution.
11 
12 #ifndef SST_CORE_FROM_STRING_H
13 #define SST_CORE_FROM_STRING_H
14 
15 #include <iomanip>
16 #include <limits>
17 #include <sstream>
18 #include <stdexcept>
19 #include <string>
20 #include <type_traits>
21 
22 namespace SST::Core {
23 
24 template <class T>
25 std::enable_if_t<std::is_integral_v<T>, T>
26 from_string(const std::string& input)
27 {
28  if constexpr ( std::is_signed_v<T> ) {
29  if constexpr ( std::is_same_v<int, T> ) {
30  return std::stoi(input, nullptr, 0);
31  }
32  else if constexpr ( std::is_same_v<long, T> ) {
33  return std::stol(input, nullptr, 0);
34  }
35  else if constexpr ( std::is_same_v<long long, T> ) {
36  return std::stoll(input, nullptr, 0);
37  }
38  else { // Smaller than 32-bit
39  return static_cast<T>(std::stol(input, nullptr, 0));
40  }
41  }
42  else {
43  if constexpr ( std::is_same_v<bool, T> ) {
44  // valid pairs: true/false, t/f, yes/no, y/n, on/off, 1/0
45  std::string transform(input);
46  for ( auto& c : transform )
47  c = std::tolower(c);
48  if ( transform == "true" || transform == "t" || transform == "yes" || transform == "y" ||
49  transform == "on" || transform == "1" ) {
50  return true;
51  }
52  else if ( transform == "false" || transform == "f" || transform == "no" || transform == "n" ||
53  transform == "off" || transform == "0" ) {
54  return false;
55  }
56  else {
57  throw std::invalid_argument("from_string: no valid conversion");
58  }
59  }
60  else if constexpr ( std::is_same_v<unsigned long, T> ) {
61  return std::stoul(input, nullptr, 0);
62  }
63  else if constexpr ( std::is_same_v<unsigned long long, T> ) {
64  return std::stoull(input, nullptr, 0);
65  }
66  else { // Smaller than 32-bit
67  return static_cast<T>(std::stoul(input, nullptr, 0));
68  }
69  }
70 }
71 
72 template <class T>
73 std::enable_if_t<std::is_floating_point_v<T>, T>
74 from_string(const std::string& input)
75 {
76  if constexpr ( std::is_same_v<float, T> ) {
77  return stof(input);
78  }
79  else if constexpr ( std::is_same_v<double, T> ) {
80  return stod(input);
81  }
82  else if constexpr ( std::is_same_v<long double, T> ) {
83  return stold(input);
84  }
85  else { // make compiler happy
86  return stod(input);
87  }
88 }
89 
90 template <class T>
91 std::enable_if_t<std::is_class_v<T>, T>
92 from_string(const std::string& input)
93 {
94  static_assert(std::is_constructible_v<T, std::string>,
95  "ERROR: from_string can only be used with integral and floating point types and with classes that have a "
96  "constructor that takes a single string as input.\n");
97  return T(input);
98 }
99 
100 template <class T>
101 std::enable_if_t<std::is_enum_v<T>, T>
102 from_string(const std::string& input)
103 {
104  return static_cast<T>(from_string<std::underlying_type_t<T>>(input));
105 }
106 
107 ///////////////////////////////////////////////////////////////////////////////
108 
109 template <class T>
110 std::enable_if_t<!std::is_enum_v<T>, std::string>
111 to_string(const T& input)
112 {
113  if constexpr ( std::is_floating_point_v<T> ) {
114  std::stringstream s;
115  T abs_val = input < 0 ? -input : input;
116  if ( abs_val > (T)10e6 || abs_val < (T)10e-6 )
117  s << std::scientific << std::setprecision(std::numeric_limits<double>::max_digits10) << input;
118  else
119  s << std::fixed << std::setprecision(std::numeric_limits<double>::max_digits10) << input;
120  return s.str().c_str();
121  }
122  else if constexpr ( std::is_arithmetic_v<T> )
123  return std::to_string(input);
124  else
125  return typeid(T).name(); // For now, return a string if the type isn't handled elsewhere
126 }
127 
128 template <class T>
129 std::enable_if_t<std::is_enum_v<T>, std::string>
130 to_string(const T& input)
131 {
132  return std::to_string(static_cast<std::underlying_type_t<T>>(input));
133 }
134 
135 // for std::string no-op, or class types which define operator std::string()
136 inline std::string
137 to_string(std::string s)
138 {
139  return s;
140 }
141 
142 } // end namespace SST::Core
143 
144 #endif // SST_CORE_FROM_STRING_H