USRP Hardware Driver and Device Manual  Version: 4.10.0.0-0-g2af4ddb9
UHD and USRP Manual
cast.hpp
Go to the documentation of this file.
1 //
2 // Copyright 2014-2015 Ettus Research LLC
3 // Copyright 2018 Ettus Research, a National Instruments Company
4 // Copyright 2019 Ettus Research, a National Instruments Brand
5 //
6 // SPDX-License-Identifier: GPL-3.0-or-later
7 //
8 
9 #pragma once
10 
11 #include <uhd/config.hpp>
12 #include <uhd/exception.hpp>
13 #include <type_traits>
14 #include <complex>
15 #include <cstdint>
16 #include <iomanip>
17 #include <ios>
18 #include <limits>
19 #include <locale>
20 #include <sstream>
21 #include <string>
22 
23 namespace uhd { namespace cast {
25 //
26 // Example:
27 // uint16_t x = hexstr_cast<uint16_t>("0xDEADBEEF");
28 // Uses stringstream.
29 template <typename T>
30 inline T hexstr_cast(const std::string& in)
31 {
32  T x;
33  std::stringstream ss;
34  ss << std::hex << in;
35  ss >> x;
36  return x;
37 }
38 
41 //
42 // Example:
43 // 10, 0x10, 010 get parsed to decimal 10, 16, 8.
44 // uint32_t x = fromstr_cast<uint32_t>("0xaffe");
45 // Uses istringstream.
46 template <typename T>
47 inline T fromstr_cast(const std::string& in)
48 {
49  T x;
50  std::istringstream is(in);
51  is >> std::setbase(0) >> x;
52  return x;
53 }
54 
56 //
57 // Handles size_t aliases (unsigned long, unsigned long long) via if constexpr
58 // when they are not the same type as uint32_t or uint64_t.
59 // Explicit specializations below override this for bool, double, int,
60 // uint32_t, uint64_t, uint16_t, uint8_t, and std::string.
61 //
62 // Note that we need this generic template to handle arbitrary types at runtime.
63 // However, this means we can't use SFINAE to create template specializations,
64 // which means any type that requires template logic needs to go into here and
65 // must be explicitly handled with if constexpr.
66 template <typename data_t>
67 data_t from_str(const std::string& val)
68 {
69  if constexpr (
70  (std::is_same_v<data_t,
71  size_t> || std::is_same_v<data_t, unsigned long> || std::is_same_v<data_t, unsigned long long>)&&!std::
72  is_same_v<data_t, uint32_t> && !std::is_same_v<data_t, uint64_t>) {
73  try {
74  if (!val.empty() && val[0] == '-') {
75  throw std::out_of_range("negative value for unsigned type");
76  }
77  size_t pos;
78  unsigned long long tmp = std::stoull(val, &pos);
79  if (pos != val.length()) {
80  throw std::invalid_argument("trailing characters");
81  }
82  if (tmp > std::numeric_limits<data_t>::max()) {
83  throw std::out_of_range("value out of range");
84  }
85  return static_cast<data_t>(tmp);
86  } catch (std::invalid_argument&) {
87  throw uhd::runtime_error(
88  std::string("Cannot convert `") + val + "' to numeric type!");
89  } catch (std::out_of_range&) {
90  throw uhd::runtime_error(
91  std::string("Cannot convert `") + val + "' to numeric type!");
92  }
93  } else {
94  throw uhd::runtime_error("Cannot convert from string!");
95  }
96 }
97 
98 // Specializations of `uhd::cast::from_str()` for supported data types
99 
101 //
102 // Examples evaluating to `true`: 'True', 'Yes', 'y', '1', empty string
103 // Examples evaluating to `false`: 'false', 'NO', 'n', '0'
104 // Throws `uhd::runtime_error` if the string can't be converted to `bool`
105 template <>
106 UHD_API bool from_str(const std::string& val);
107 
109 template <>
110 UHD_API double from_str(const std::string& val);
111 
113 template <>
114 UHD_API int from_str(const std::string& val);
115 
117 template <>
118 UHD_API uint8_t from_str(const std::string& val);
119 
121 template <>
122 UHD_API uint16_t from_str(const std::string& val);
123 
125 template <>
126 UHD_API uint32_t from_str(const std::string& val);
127 
129 template <>
130 UHD_API uint64_t from_str(const std::string& val);
131 
133 template <>
134 inline UHD_API std::string from_str(const std::string& val)
135 {
136  return val;
137 }
138 
140 UHD_API std::string to_ordinal_string(int val);
141 
143 //
144 // These template implementations provide consistent string conversion
145 // for integer and floating-point types commonly used in UHD, particularly
146 // for device_addr_t parameter handling.
147 
148 // Type trait to detect if a type has a to_string() method
149 namespace detail {
150 template <typename T>
152  -> decltype(std::declval<T>().to_string(), std::true_type{});
153 template <typename T>
154 auto has_to_string_method_impl(...) -> std::false_type;
155 template <typename T>
156 using has_to_string_method = decltype(has_to_string_method_impl<T>(0));
157 } // namespace detail
158 
160 //
161 // This template will automatically work for integer types that std::to_string supports
162 // (int, unsigned int, long, unsigned long, long long, unsigned long long, size_t, etc.),
163 // excluding int8_t and uint8_t which need special handling, and floating-point types
164 // which need precision handling, and excluding types that have their own to_string()
165 // method.
166 template <typename T>
167 auto to_str(const T& val) -> std::enable_if_t<
168  std::is_arithmetic_v<
169  T> && !std::is_floating_point_v<T> && !std::is_same_v<T, int8_t> && !std::is_same_v<T, uint8_t> && !std::is_enum_v<T> && !detail::has_to_string_method<T>::value,
170  decltype(std::to_string(val))>
171 {
172  return std::to_string(val);
173 }
174 
176 //
177 // Convert enum types to their underlying integral type, then to string
178 template <typename T>
179 auto to_str(const T& val) -> std::enable_if_t<std::is_enum_v<T>, std::string>
180 {
181  return std::to_string(static_cast<std::underlying_type_t<T>>(val));
182 }
183 
185 //
186 // Uses ostringstream with max_digits10 precision and classic locale to ensure
187 // round-trip safety for floating-point values.
188 template <typename T>
189 auto to_str(const T& val) -> std::enable_if_t<
190  std::is_floating_point_v<T> && !detail::has_to_string_method<T>::value,
191  std::string>
192 {
193  std::ostringstream oss;
194  oss.imbue(std::locale::classic());
195  oss.precision(std::numeric_limits<T>::max_digits10);
196  oss << val;
197  return oss.str();
198 }
199 
200 // Special handling for int8_t and uint8_t since std::to_string treats them as chars
201 
203 template <typename T>
204 auto to_str(const T& val)
205  -> std::enable_if_t<std::is_same_v<T, int8_t> || std::is_same_v<T, signed char>,
206  std::string>
207 {
208  return std::to_string(static_cast<int>(val));
209 }
210 
212 template <typename T>
213 auto to_str(const T& val)
214  -> std::enable_if_t<std::is_same_v<T, uint8_t> || std::is_same_v<T, unsigned char>,
215  std::string>
216 {
217  return std::to_string(static_cast<unsigned int>(val));
218 }
219 
221 //
222 // This template will work for any std::complex<T> where T has a to_str() function
223 // Creates a string of the form "a+jb" or "a-jb"
224 template <typename T>
225 std::string to_str(const std::complex<T>& val)
226 {
227  std::string real_str = to_str(val.real());
228  T imag_val = val.imag();
229 
230  if (imag_val >= 0) {
231  return real_str + "+j" + to_str(imag_val);
232  } else {
233  return real_str + "-j" + to_str(-imag_val);
234  }
235 }
236 
238 //
239 // This template will automatically work for any type T that has a to_string()
240 // method that returns a type convertible to std::string.
241 template <typename T>
242 auto to_str(const T& val)
243  -> std::enable_if_t<std::is_convertible_v<decltype(val.to_string()), std::string>,
244  std::string>
245 {
246  return val.to_string();
247 }
248 
250 inline std::string to_str(const std::string& val)
251 {
252  return val;
253 }
254 
255 inline std::string to_str(const char* val)
256 {
257  return std::string(val);
258 }
259 
260 }} // namespace uhd::cast
#define UHD_API
Definition: config.h:87
decltype(has_to_string_method_impl< T >(0)) has_to_string_method
Definition: cast.hpp:156
auto has_to_string_method_impl(int) -> decltype(std::declval< T >().to_string(), std::true_type{})
T fromstr_cast(const std::string &in)
Definition: cast.hpp:47
T hexstr_cast(const std::string &in)
Convert a hexadecimal string into a value.
Definition: cast.hpp:30
auto to_str(const T &val) -> std::enable_if_t< std::is_arithmetic_v< T > &&!std::is_floating_point_v< T > &&!std::is_same_v< T, int8_t > &&!std::is_same_v< T, uint8_t > &&!std::is_enum_v< T > &&!detail::has_to_string_method< T >::value, decltype(std::to_string(val))>
SFINAE-based template for integer types that std::to_string can handle.
Definition: cast.hpp:167
data_t from_str(const std::string &val)
Generic cast-from-string function.
Definition: cast.hpp:67
UHD_API std::string to_ordinal_string(int val)
Create an ordinal string from a number.
Definition: build_info.hpp:12
Definition: exception.hpp:132