SST 16.0.0
Structural Simulation Toolkit
from_string.h
1// Copyright 2009-2026 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-2026, 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 <cctype>
16#include <cstdlib>
17#include <cstring>
18#include <iomanip>
19#include <limits>
20#include <sstream>
21#include <stdexcept>
22#include <string>
23#include <type_traits>
24#include <typeinfo>
25
26#include "sst_complex.h"
27
28namespace SST::Core {
29
30template <class T>
31std::enable_if_t<std::is_integral_v<T>, T>
32from_string(const std::string& input)
33{
34 if constexpr ( std::is_signed_v<T> ) {
35 if constexpr ( std::is_same_v<int, T> ) {
36 return std::stoi(input, nullptr, 0);
37 }
38 else if constexpr ( std::is_same_v<long, T> ) {
39 return std::stol(input, nullptr, 0);
40 }
41 else if constexpr ( std::is_same_v<long long, T> ) {
42 return std::stoll(input, nullptr, 0);
43 }
44 else { // Smaller than 32-bit
45 return static_cast<T>(std::stol(input, nullptr, 0));
46 }
47 }
48 else {
49 if constexpr ( std::is_same_v<bool, T> ) {
50 // valid pairs: true/false, t/f, yes/no, y/n, on/off, 1/0
51 std::string transform(input);
52 for ( auto& c : transform )
53 c = std::tolower(c);
54 if ( transform == "true" || transform == "t" || transform == "yes" || transform == "y" ||
55 transform == "on" || transform == "1" ) {
56 return true;
57 }
58 else if ( transform == "false" || transform == "f" || transform == "no" || transform == "n" ||
59 transform == "off" || transform == "0" ) {
60 return false;
61 }
62 else {
63 throw std::invalid_argument("from_string: no valid conversion");
64 }
65 }
66 else if constexpr ( std::is_same_v<unsigned long, T> ) {
67 return std::stoul(input, nullptr, 0);
68 }
69 else if constexpr ( std::is_same_v<unsigned long long, T> ) {
70 return std::stoull(input, nullptr, 0);
71 }
72 else { // Smaller than 32-bit
73 return static_cast<T>(std::stoul(input, nullptr, 0));
74 }
75 }
76}
77
78template <class T>
79std::enable_if_t<std::is_floating_point_v<T>, T>
80from_string(const std::string& input)
81{
82 if constexpr ( std::is_same_v<float, T> ) {
83 return stof(input);
84 }
85 else if constexpr ( std::is_same_v<double, T> ) {
86 return stod(input);
87 }
88 else if constexpr ( std::is_same_v<long double, T> ) {
89 return stold(input);
90 }
91 else {
92 static_assert(sizeof(T) == 0, "from_string(): Unsupported type");
93 }
94}
95
96template <class T>
97std::enable_if_t<std::is_class_v<T> && !complex_properties<T>::is_complex, T>
98from_string(const std::string& input)
99{
100 static_assert(std::is_constructible_v<T, std::string>,
101 "ERROR: from_string can only be used with integral and floating point types and with classes that have a "
102 "constructor that takes a single string as input.\n");
103 return T(input);
104}
105
106template <class T>
107std::enable_if_t<std::is_enum_v<T>, T>
108from_string(const std::string& input)
109{
110 return static_cast<T>(from_string<std::underlying_type_t<T>>(input));
111}
112
113// Parse complex numbers
114template <class T>
115std::enable_if_t<complex_properties<T>::is_complex, T>
116from_string(const std::string& input)
117{
118 using REAL = typename complex_properties<T>::real_t;
119 struct
120 {
121 REAL real, imag;
122 } cmplx = { 0, 0 };
123
124 const char* s = input.c_str();
125 while ( isspace(*s) || *s == '(' )
126 ++s;
127
128 char* e;
129 if constexpr ( std::is_same_v<float, REAL> )
130 cmplx.real = strtof(s, &e);
131 else if constexpr ( std::is_same_v<double, REAL> )
132 cmplx.real = strtod(s, &e);
133 else if constexpr ( std::is_same_v<long double, REAL> )
134 cmplx.real = strtold(s, &e);
135 else
136 static_assert(sizeof(REAL) == 0, "complex_from_string(): Unsupported REAL type");
137
138 s = e;
139 while ( isspace(*s) )
140 ++s;
141
142 if ( *s++ == ',' ) {
143 if constexpr ( std::is_same_v<float, REAL> )
144 cmplx.imag = strtof(s, &e);
145 else if constexpr ( std::is_same_v<double, REAL> )
146 cmplx.imag = strtod(s, &e);
147 else if constexpr ( std::is_same_v<long double, REAL> )
148 cmplx.imag = strtold(s, &e);
149 else
150 static_assert(sizeof(REAL) == 0, "complex_from_string(): Unsupported REAL type");
151 }
152
153 T ret;
154 memcpy(reinterpret_cast<char*>(&ret), &cmplx, sizeof(ret));
155 return ret;
156}
157
158///////////////////////////////////////////////////////////////////////////////
159
160// Arithmetic types or a default if no types match
161template <class T>
162std::enable_if_t<!std::is_enum_v<T> && !complex_properties<T>::is_complex, std::string>
163to_string(const T& input)
164{
165 if constexpr ( std::is_floating_point_v<T> ) {
166 std::ostringstream s;
167 T abs_val = input < 0 ? -input : input;
168 if ( abs_val > (T)10e6 || abs_val < (T)10e-6 )
169 s << std::scientific << std::setprecision(std::numeric_limits<double>::max_digits10) << input;
170 else
171 s << std::fixed << std::setprecision(std::numeric_limits<double>::max_digits10) << input;
172 return s.str();
173 }
174 else if constexpr ( std::is_same_v<T, bool> )
175 return input ? "true" : "false";
176 else if constexpr ( std::is_arithmetic_v<T> )
177 return std::to_string(input);
178 else
179 return typeid(T).name(); // For now, return a string if the type isn't handled elsewhere
180}
181
182// Enums
183template <class T>
184std::enable_if_t<std::is_enum_v<T>, std::string>
185to_string(const T& input)
186{
187 return std::to_string(static_cast<std::underlying_type_t<T>>(input));
188}
189
190// for std::string no-op, or class types which define operator std::string()
191inline std::string
192to_string(std::string s)
193{
194 return s;
195}
196
197// Complex numbers
198template <typename T>
199std::enable_if_t<complex_properties<T>::is_complex, std::string>
200to_string(const T& input)
201{
202 typename complex_properties<T>::real_t cmplx[2];
203 memcpy(cmplx, &input, sizeof(cmplx));
204 return "(" + to_string(cmplx[0]) + ", " + to_string(cmplx[1]) + ")";
205}
206
207} // namespace SST::Core
208
209#endif // SST_CORE_FROM_STRING_H