@@ -290,102 +290,108 @@ float OIIO_API strtof (const char *nptr, char **endptr, const std::locale& loc);
290290
291291
292292
293- // Helper template to test if a string is a generic type
294- template <typename T>
295- inline bool string_is (string_view /* s*/ ) {
296- return false ; // Generic: assume there is an explicit specialization
297- }
298- // Special case for int
299- template <> inline bool string_is<int > (string_view s) {
300- if (s.empty ())
301- return false ;
302- char *endptr = 0 ;
303- strtol (s.data (), &endptr, 10 );
304- return (s.data () + s.size () == endptr);
305- }
306- // Special case for float. Note that by using Strutil::strtof, this always
307- // treats '.' as the decimal character.
308- template <> inline bool string_is<float > (string_view s) {
309- if (s.empty ())
310- return false ;
311- char *endptr = 0 ;
312- Strutil::strtof (s.data (), &endptr);
313- return (s.data () + s.size () == endptr);
314- }
315-
316-
317-
318293// stoi() returns the int conversion of text from several string types.
319294// No exceptions or errors -- parsing errors just return 0.
320- inline int stoi (const char * s) {
321- return s && s[0 ] ? strtol (s, nullptr , 10 ) : 0 ;
322- }
323- inline int stoi (const std::string& s) { return Strutil::stoi (s.c_str ()); }
324- inline int stoi (string_view s) { return Strutil::stoi (std::string (s)); }
325-
295+ OIIO_API int stoi (const char * s, size_t * pos=0 , int base=10 );
296+ OIIO_API int stoi (const std::string& s, size_t * pos=0 , int base=10 );
297+ OIIO_API int stoi (string_view s, size_t * pos=0 , int base=10 );
298+ // N.B. For users of ustring, there's a stoi(ustring) defined in ustring.h.
326299
327300
328301// stoul() returns the unsigned int conversion of text from several string
329302// types. No exceptions or errors -- parsing errors just return 0.
330- inline unsigned int stoul (const char * s) {
331- return s && s[0 ] ? strtoul (s, nullptr , 10 ) : 0 ;
332- }
333- inline unsigned int stoul (const std::string& s) { return Strutil::stoul (s.c_str ()); }
334- inline unsigned int stoul (string_view s) { return Strutil::stoul (std::string (s)); }
335-
303+ OIIO_API unsigned int stoul (const char * s, size_t * pos=0 , int base=10 );
304+ OIIO_API unsigned int stoul (const std::string& s, size_t * pos=0 , int base=10 );
305+ OIIO_API unsigned int stoul (string_view s, size_t * pos=0 , int base=10 );
306+ // N.B. For users of ustring, there's a stoi(ustring) defined in ustring.h.
336307
337308
338309// / stof() returns the float conversion of text from several string types.
339310// / No exceptions or errors -- parsing errors just return 0.0. These always
340311// / use '.' for the decimal mark (versus atof and std::strtof, which are
341312// / locale-dependent).
342- inline float stof (const std::string& s) {
343- return s.size () ? Strutil::strtof (s.c_str (), nullptr ) : 0 .0f ;
344- }
345- inline float stof (const char * s) {
346- return Strutil::strtof (s, nullptr );
347- }
348- inline float stof (string_view s) {
349- return Strutil::strtof (std::string (s).c_str (), nullptr );
350- }
313+ OIIO_API float stof (const std::string& s, size_t * pos=0 );
314+ OIIO_API float stof (const char * s, size_t * pos=0 );
315+ OIIO_API float stof (string_view s, size_t * pos=0 );
316+ // N.B. For users of ustring, there's a stof(ustring) defined in ustring.h.
351317
352318// stof() version that takes an explicit locale (for example, if you pass a
353319// default-constructed std::locale, it will use the current native locale's
354320// decimal conventions).
355- inline float stof (const std::string& s, const std::locale& loc) {
356- return s.size () ? Strutil::strtof (s.c_str (), nullptr , loc) : 0 .0f ;
321+ OIIO_API float stof (const std::string& s, const std::locale& loc, size_t * pos=0 );
322+ OIIO_API float stof (const char * s, const std::locale& loc, size_t * pos=0 );
323+ OIIO_API float stof (string_view s, const std::locale& loc, size_t * pos=0 );
324+
325+
326+
327+ // / Return true if the string is exactly (other than leading whitespace)
328+ // / a valid int.
329+ inline bool string_is_int (string_view s) {
330+ size_t pos;
331+ Strutil::stoi (s, &pos);
332+ return pos && pos >= s.size (); // consumed the whole string
357333}
358- inline float stof (const char * s, const std::locale& loc) {
359- return Strutil::strtof (s, nullptr , loc);
334+
335+ // / Return true if the string is exactly (other than leading whitespace)
336+ // / a valid float. This operations in a locale-independent manner, i.e.,
337+ // / it assumes '.' as the decimal mark.
338+ inline bool string_is_float (string_view s) {
339+ size_t pos;
340+ Strutil::stof (s, &pos);
341+ return pos && pos >= s.size (); // consumed the whole string
360342}
361- inline float stof (string_view s, const std::locale& loc) {
362- return Strutil::strtof (std::string (s).c_str (), nullptr , loc);
343+
344+ // / Return true if the string is exactly (other than leading whitespace)
345+ // / a valid float. This operations uses an explicit locale.
346+ inline bool string_is_float (string_view s, const std::locale& loc) {
347+ size_t pos;
348+ Strutil::stof (s, loc, &pos);
349+ return pos && pos >= s.size (); // consumed the whole string
363350}
364351
365352
366353
367354// Helper template to convert from generic type to string (using default
368- // locale).
355+ // locale). Used when you want stoX but you're in a template.
369356template <typename T>
370357inline T from_string (string_view s) {
371358 return T (s); // Generic: assume there is an explicit converter
372359}
373360// Special case for int
374361template <> inline int from_string<int > (string_view s) {
375- return s. size () ? strtol (s. c_str (), nullptr , 10 ) : 0 ;
362+ return Strutil::stoi (s) ;
376363}
377364// Special case for uint
378365template <> inline unsigned int from_string<unsigned int > (string_view s) {
379- return s. size () ? strtoul (s. c_str (), nullptr , 10 ) : ( unsigned int ) 0 ;
366+ return Strutil::stoul (s) ;
380367}
381368// Special case for float -- note that by using Strutil::strtof, this
382369// always treats '.' as the decimal mark.
383370template <> inline float from_string<float > (string_view s) {
384- return s. size () ? Strutil::strtof (s. c_str (), nullptr ) : 0 . 0f ;
371+ return Strutil::stof (s) ;
385372}
386373
387374
388375
376+ // Helper template to test if a string is a generic type. Used instead of
377+ // string_is_X, but when you're inside templated code.
378+ template <typename T>
379+ inline bool string_is (string_view /* s*/ ) {
380+ return false ; // Generic: assume there is an explicit specialization
381+ }
382+ // Special case for int
383+ template <> inline bool string_is<int > (string_view s) {
384+ return string_is_int (s);
385+ }
386+ // Special case for float. Note that by using Strutil::stof, this always
387+ // treats '.' as the decimal character.
388+ template <> inline bool string_is<float > (string_view s) {
389+ return string_is_float (s);
390+ }
391+
392+
393+
394+
389395// / Given a string containing values separated by a comma (or optionally
390396// / another separator), extract the individual values, placing them into
391397// / vals[] which is presumed to already contain defaults. If only a single
0 commit comments