@@ -102,66 +102,15 @@ namespace csv {
102102 *
103103 */
104104 template <typename T = std::string> T get () {
105- IF_CONSTEXPR (std::is_arithmetic<T>::value) {
106- // Note: this->type() also converts the CSV value to float
107- if (this ->type () <= DataType::CSV_STRING) {
108- throw std::runtime_error (internals::ERROR_NAN);
109- }
110- }
111-
112- IF_CONSTEXPR (std::is_integral<T>::value) {
113- // Note: this->is_float() also converts the CSV value to float
114- if (this ->is_float ()) {
115- throw std::runtime_error (internals::ERROR_FLOAT_TO_INT);
116- }
117-
118- IF_CONSTEXPR (std::is_unsigned<T>::value) {
119- if (this ->value < 0 ) {
120- throw std::runtime_error (internals::ERROR_NEG_TO_UNSIGNED);
121- }
122- }
123- }
124-
125- // Allow fallthrough from previous if branch
126- IF_CONSTEXPR (!std::is_floating_point<T>::value) {
127- IF_CONSTEXPR (std::is_unsigned<T>::value) {
128- // Quick hack to perform correct unsigned integer boundary checks
129- if (this ->value > internals::get_uint_max<sizeof (T)>()) {
130- throw std::runtime_error (internals::ERROR_OVERFLOW);
131- }
132- }
133- else if (internals::type_num<T>() < this ->_type ) {
134- throw std::runtime_error (internals::ERROR_OVERFLOW);
135- }
136- }
137-
138- return static_cast <T>(this ->value );
105+ T out{};
106+ if (const auto * err = check_convert (out)) throw std::runtime_error (err);
107+ return out;
139108 }
140109
141- /* * Attempts to retrieve the value as the requested type without throwing exceptions.
142- *
143- * @param[out] out Output parameter that receives the converted value if successful
144- * @return true if conversion succeeded, false otherwise
145- *
146- * \par Valid options for T
147- * - std::string or csv::string_view
148- * - signed integral types (signed char, short, int, long int, long long int)
149- * - floating point types (float, double, long double)
150- * - unsigned integers are not supported at this time, but may be in a later release
151- *
152- * \par When conversion fails (returns false)
153- * - Converting non-numeric values to any numeric type
154- * - Converting floating point values to integers
155- * - Converting a large integer to a smaller type that will not hold it
156- * - Converting negative values to unsigned types
110+ /* * Non-throwing equivalent of get(). Applies the same type checks and conversions;
111+ * returns true and writes to @p out on success, or returns false without throwing.
157112 *
158- * @note This method is capable of parsing scientific E-notation.
159- *
160- * @warning Currently, conversions to floating point types are not
161- * checked for loss of precision
162- *
163- * @warning Any string_views returned are only guaranteed to be valid
164- * if the parent CSVRow is still alive.
113+ * @sa get() for the full description of valid types, conversion rules, and warnings.
165114 *
166115 * Example:
167116 * @code
@@ -175,40 +124,7 @@ namespace csv {
175124 */
176125 template <typename T = std::string>
177126 bool try_get (T& out) noexcept {
178- IF_CONSTEXPR (std::is_arithmetic<T>::value) {
179- // Check if value is numeric
180- if (this ->type () <= DataType::CSV_STRING) {
181- return false ;
182- }
183- }
184-
185- IF_CONSTEXPR (std::is_integral<T>::value) {
186- // Check for float-to-int conversion
187- if (this ->is_float ()) {
188- return false ;
189- }
190-
191- IF_CONSTEXPR (std::is_unsigned<T>::value) {
192- if (this ->value < 0 ) {
193- return false ;
194- }
195- }
196- }
197-
198- // Check for overflow
199- IF_CONSTEXPR (!std::is_floating_point<T>::value) {
200- IF_CONSTEXPR (std::is_unsigned<T>::value) {
201- if (this ->value > internals::get_uint_max<sizeof (T)>()) {
202- return false ;
203- }
204- }
205- else if (internals::type_num<T>() < this ->_type ) {
206- return false ;
207- }
208- }
209-
210- out = static_cast <T>(this ->value );
211- return true ;
127+ return check_convert (out) == nullptr ;
212128 }
213129
214130 /* * Parse a hexadecimal value, returning false if the value is not hex.
@@ -294,6 +210,42 @@ namespace csv {
294210 long double value = 0 ; /* *< Cached numeric value */
295211 csv::string_view sv = " " ; /* *< A pointer to this field's text */
296212 DataType _type = DataType::UNKNOWN; /* *< Cached data type value */
213+
214+ /* * Shared validation + conversion kernel used by get() and try_get().
215+ * Assigns to @p out and returns nullptr on success;
216+ * returns a pointer to a static error message on failure, without throwing.
217+ */
218+ template <typename T>
219+ const char * check_convert (T& out) noexcept {
220+ IF_CONSTEXPR (std::is_arithmetic<T>::value) {
221+ if (this ->type () <= DataType::CSV_STRING)
222+ return internals::ERROR_NAN.c_str ();
223+ }
224+
225+ IF_CONSTEXPR (std::is_integral<T>::value) {
226+ if (this ->is_float ())
227+ return internals::ERROR_FLOAT_TO_INT.c_str ();
228+
229+ IF_CONSTEXPR (std::is_unsigned<T>::value) {
230+ if (this ->value < 0 )
231+ return internals::ERROR_NEG_TO_UNSIGNED.c_str ();
232+ }
233+ }
234+
235+ IF_CONSTEXPR (!std::is_floating_point<T>::value) {
236+ IF_CONSTEXPR (std::is_unsigned<T>::value) {
237+ if (this ->value > internals::get_uint_max<sizeof (T)>())
238+ return internals::ERROR_OVERFLOW.c_str ();
239+ }
240+ else if (internals::type_num<T>() < this ->_type ) {
241+ return internals::ERROR_OVERFLOW.c_str ();
242+ }
243+ }
244+
245+ out = static_cast <T>(this ->value );
246+ return nullptr ;
247+ }
248+
297249 CONSTEXPR_14 void get_value () noexcept {
298250 /* Check to see if value has been cached previously, if not
299251 * evaluate it
0 commit comments