14
14
#include " arcane/utils/ValueConvert.h"
15
15
16
16
#include " arcane/utils/OStringStream.h"
17
+ #include " arcane/utils/NotSupportedException.h"
17
18
#include " arcane/utils/internal/ValueConvertInternal.h"
18
19
19
20
// En théorie std::from_chars() est disponible avec le C++17 mais pour
@@ -42,6 +43,31 @@ namespace
42
43
return reinterpret_cast <const char *>(s.bytes ().data ());
43
44
}
44
45
46
+ /* !
47
+ * \brief Retourne une vue en supprimant les caratères blancs du début.
48
+ *
49
+ * Un caractère blanc est un caractère pour lequel std::isspace() est vrai.
50
+ * \a pos indique la position dans \a s à partir de laquelle
51
+ * on cherche les blancs.
52
+ */
53
+ StringView _removeLeadingSpaces (StringView s, Int64 pos)
54
+ {
55
+ Span<const Byte > bytes = s.bytes ();
56
+ Int64 nb_byte = bytes.size ();
57
+ // Supprime les espaces potentiels
58
+ for (; pos < nb_byte; ++pos) {
59
+ int charv = static_cast <unsigned char >(bytes[pos]);
60
+ // Visual Studio 2017 or less
61
+ #if defined(_MSC_VER) && _MSC_VER <= 1916
62
+ if (std::isspace (charv, std::locale ()) != 0 )
63
+ break ;
64
+ #else
65
+ if (!std::isspace (charv) != 0 )
66
+ break ;
67
+ #endif
68
+ }
69
+ return StringView (bytes.subSpan (pos, nb_byte));
70
+ }
45
71
} // namespace
46
72
47
73
/* ---------------------------------------------------------------------------*/
@@ -91,113 +117,125 @@ arcaneSetUseSameValueConvertForAllReal(bool v)
91
117
92
118
/* ---------------------------------------------------------------------------*/
93
119
/* ---------------------------------------------------------------------------*/
94
-
95
- namespace
120
+ /* !
121
+ * \brief Classe pour convertir une 'StringView' en 'double'.
122
+ */
123
+ class StringViewToDoubleConverter
96
124
{
97
- #if defined(ARCANE_USE_FROMCHARS)
98
- /* !
99
- * \brief Converti une chaîne de caractères en un double.
100
- *
101
- * Converti \a s en un double et range la valeur dans \a v.
102
- * Il ne doit pas y avoir de caractères blancs au début de \a s.
103
- *
104
- * Le comportement de cette méthode est identique à std::strtod()
105
- * avec le locale 'C' si on est en C++20. Sinon il est identique
106
- * à std::strtod() avec le locale actuel (ce qui peut changer par exemple
107
- * le séparateur décimal). La documentation de référence est
108
- * ici: https://en.cppreference.com/w/cpp/utility/from_chars.
109
- *
110
- * \retval (-1) si la conversion a échouée.
111
- * \retval la position dans \s du dernier caratère lu plus 1.
112
- */
113
- Int64 _getDoubleValueWithFromChars (double & v, StringView s)
114
- {
115
- // ATTENTION: il ne faut pas d'espace en début de \a s
116
- auto bytes = s.bytes ();
117
- Int64 size = bytes.size ();
118
- if (size == 0 )
119
- // NOTE: Avec la version historique d'Arcane (avant la 3.15) il
120
- // n'y avait pas d'erreur retournée lorsqu'on converti une chaîne vide.
121
- // A priori cela n'était jamais utilisé donc cela ne pose pas de
122
- // problème de corriger ce bug.
123
- return (-1 );
124
- const char * orig_data = reinterpret_cast <const char *>(bytes.data ());
125
- const char * last_ptr = nullptr ;
126
- std::chars_format fmt = std::chars_format::general;
127
- const char * data = orig_data;
128
- bool do_negatif = false ;
129
- const bool is_verbose = global_value_convert_verbosity > 0 ;
130
- // std::from_chars() peut lire les valeurs au format hexadécimal
131
- // mais il ne doit pas contenir le '0x' ou '0X' du début, contrairement
132
- // à std::strtod(). On détecte ce cas et on commence la conversion
133
- // après le '0x' ou '0X'.
134
-
135
- // Détecte '-0x' ou '-0X'
136
- if (size >= 3 && (bytes[0 ] == ' -' ) && (bytes[1 ] == ' 0' ) && (bytes[2 ] == ' x' || bytes[2 ] == ' X' )) {
137
- fmt = std::chars_format::hex;
138
- data += 3 ;
139
- do_negatif = true ;
140
- }
141
- // Détecte '0x' ou '0X'
142
- else if (size >= 2 && (bytes[0 ] == ' 0' ) && (bytes[1 ] == ' x' || bytes[1 ] == ' X' )) {
143
- fmt = std::chars_format::hex;
144
- data += 2 ;
145
- }
146
- // Cas général
147
- {
148
- auto [ptr, ec] = std::from_chars (data, data + size, v, fmt);
149
- last_ptr = ptr;
150
- if (is_verbose)
151
- std::cout << " FromChars:TRY GET_DOUBLE data=" << data << " v=" << v << " is_ok=" << (ec == std::errc ()) << " \n " ;
152
- if (ec != std::errc ())
153
- return (-1 );
154
- }
155
- // Prend en compte le signe '-' si demandé
156
- if (do_negatif)
157
- v = -v;
158
- if (is_verbose) {
159
- char * ptr2 = nullptr ;
160
- double v2 = ::strtod (orig_data, &ptr2);
161
- std::cout << " FromChars: COMPARE GET_DOUBLE via strtod v2=" << v2 << " pos=" << (ptr2 - orig_data) << " \n " ;
162
- }
163
- return (last_ptr - orig_data);
164
- }
165
- #endif
125
+ public:
166
126
167
- /* ---------------------------------------------------------------------------*/
168
- /* ---------------------------------------------------------------------------*/
127
+ static Int64 _getDoubleValueWithFromChars (double & v, StringView s);
128
+ static Int64 _getDoubleValue (double & v, StringView s);
129
+ };
169
130
170
- /* !
171
- * \brief Converti \a s en un double.
172
- *
173
- * Utilise std::from_chars() si \a global_use_from_chars est vrai.
174
- * Sinon, utilise strtod().
175
- */
176
- Int64 _getDoubleValue (double & v, StringView s)
177
- {
131
+ /* ---------------------------------------------------------------------------*/
132
+ /* ---------------------------------------------------------------------------*/
133
+ /* !
134
+ * \brief Converti \a s en un double.
135
+ *
136
+ * Utilise std::from_chars() si \a global_use_from_chars est vrai.
137
+ * Sinon, utilise strtod().
138
+ */
139
+ Int64 StringViewToDoubleConverter::
140
+ _getDoubleValue (double & v, StringView s)
141
+ {
178
142
#if defined(ARCANE_USE_FROMCHARS)
179
- if (global_use_from_chars) {
180
- Int64 p = _getDoubleValueWithFromChars (v, s);
181
- return p;
182
- }
143
+ if (global_use_from_chars) {
144
+ Int64 p = _getDoubleValueWithFromChars (v, s);
145
+ return p;
146
+ }
183
147
#endif
184
148
185
- const char * ptr = _stringViewData (s);
149
+ const char * ptr = _stringViewData (s);
186
150
#ifdef WIN32
187
- if (s == " infinity" || s == " inf" ) {
188
- v = std::numeric_limits<double >::infinity ();
189
- return false ;
190
- }
151
+ if (s == " infinity" || s == " inf" ) {
152
+ v = std::numeric_limits<double >::infinity ();
153
+ return s. size () ;
154
+ }
191
155
#endif
192
- char * ptr2 = nullptr ;
156
+ char * ptr2 = nullptr ;
157
+ if (ptr)
193
158
v = ::strtod (ptr, &ptr2);
194
- return (ptr2 - ptr);
195
- }
159
+ return (ptr2 - ptr);
160
+ }
196
161
197
- /* ---------------------------------------------------------------------------*/
198
- /* ---------------------------------------------------------------------------*/
162
+ /* ---------------------------------------------------------------------------*/
163
+ /* ---------------------------------------------------------------------------*/
164
+ /* !
165
+ * \brief Converti une chaîne de caractères en un double.
166
+ *
167
+ * Converti \a s en un double et range la valeur dans \a v.
168
+ * Il ne doit pas y avoir de caractères blancs au début de \a s.
169
+ *
170
+ * Le comportement de cette méthode est identique à std::strtod()
171
+ * avec le locale 'C' si on est en C++20. Sinon il est identique
172
+ * à std::strtod() avec le locale actuel (ce qui peut changer par exemple
173
+ * le séparateur décimal). La documentation de référence est
174
+ * ici: https://en.cppreference.com/w/cpp/utility/from_chars.
175
+ *
176
+ * \retval (-1) si la conversion a échouée.
177
+ * \retval la position dans \s du dernier caratère lu plus 1.
178
+ */
179
+ Int64 StringViewToDoubleConverter::
180
+ _getDoubleValueWithFromChars (double & v, StringView s)
181
+ {
182
+ #if defined(ARCANE_USE_FROMCHARS)
183
+ // ATTENTION: il ne faut pas d'espace en début de \a s
184
+ auto bytes = s.bytes ();
185
+ Int64 size = bytes.size ();
186
+ if (size == 0 )
187
+ // NOTE: Avec la version historique d'Arcane (avant la 3.15) il
188
+ // n'y avait pas d'erreur retournée lorsqu'on converti une chaîne vide.
189
+ // A priori cela n'était jamais utilisé donc cela ne pose pas de
190
+ // problème de corriger ce bug.
191
+ return (-1 );
192
+ const char * orig_data = reinterpret_cast <const char *>(bytes.data ());
193
+ const char * last_ptr = nullptr ;
194
+ std::chars_format fmt = std::chars_format::general;
195
+ const char * data = orig_data;
196
+ bool do_negatif = false ;
197
+ const bool is_verbose = global_value_convert_verbosity > 0 ;
198
+ // std::from_chars() peut lire les valeurs au format hexadécimal
199
+ // mais il ne doit pas contenir le '0x' ou '0X' du début, contrairement
200
+ // à std::strtod(). On détecte ce cas et on commence la conversion
201
+ // après le '0x' ou '0X'.
202
+
203
+ // Détecte '-0x' ou '-0X'
204
+ if (size >= 3 && (bytes[0 ] == ' -' ) && (bytes[1 ] == ' 0' ) && (bytes[2 ] == ' x' || bytes[2 ] == ' X' )) {
205
+ fmt = std::chars_format::hex;
206
+ data += 3 ;
207
+ do_negatif = true ;
208
+ }
209
+ // Détecte '0x' ou '0X'
210
+ else if (size >= 2 && (bytes[0 ] == ' 0' ) && (bytes[1 ] == ' x' || bytes[1 ] == ' X' )) {
211
+ fmt = std::chars_format::hex;
212
+ data += 2 ;
213
+ }
214
+ // Cas général
215
+ {
216
+ auto [ptr, ec] = std::from_chars (data, data + size, v, fmt);
217
+ last_ptr = ptr;
218
+ if (is_verbose)
219
+ std::cout << " FromChars:TRY GET_DOUBLE data=" << data << " v=" << v << " is_ok=" << (ec == std::errc ()) << " \n " ;
220
+ if (ec != std::errc ())
221
+ return (-1 );
222
+ }
223
+ // Prend en compte le signe '-' si demandé
224
+ if (do_negatif)
225
+ v = -v;
226
+ if (is_verbose) {
227
+ char * ptr2 = nullptr ;
228
+ double v2 = ::strtod (orig_data, &ptr2);
229
+ std::cout << " FromChars: COMPARE GET_DOUBLE via strtod v2=" << v2 << " pos=" << (ptr2 - orig_data) << " \n " ;
230
+ }
231
+ return (last_ptr - orig_data);
232
+ #else
233
+ ARCANE_THROW (NotSupportedException, " using std::from_chars() is not available on this platform" );
234
+ #endif
235
+ }
199
236
200
- } // namespace
237
+ /* ---------------------------------------------------------------------------*/
238
+ /* ---------------------------------------------------------------------------*/
201
239
202
240
/* ---------------------------------------------------------------------------*/
203
241
/* ---------------------------------------------------------------------------*/
@@ -207,7 +245,7 @@ builtInGetValue(double& v, StringView s)
207
245
{
208
246
#if defined(ARCANE_USE_FROMCHARS)
209
247
if (global_use_from_chars) {
210
- Int64 p = _getDoubleValueWithFromChars (v, s);
248
+ Int64 p = StringViewToDoubleConverter:: _getDoubleValueWithFromChars (v, s);
211
249
return (p == (-1 ) || (p != s.size ()));
212
250
}
213
251
#endif
@@ -339,33 +377,43 @@ builtInGetValue(Real2& v, StringView s)
339
377
const bool is_verbose = global_value_convert_verbosity > 0 ;
340
378
if (is_verbose)
341
379
std::cout << " Try Read Real2: '" << s << " '\n " ;
342
- Int64 p = _getDoubleValue (v.x , s);
380
+ Int64 p = StringViewToDoubleConverter:: _getDoubleValue (v.x , s);
343
381
if (p == (-1 ))
344
382
return true ;
345
- Span<const Byte > bytes = s.bytes ();
346
- Int64 nb_byte = bytes.size ();
347
- // Supprime les espaces potentiels
348
- for (; p < nb_byte; ++p)
349
- {
350
- #ifdef _MSC_VER <= 1916 // Visual Studio 2017 or less
351
- if (!std::isspace ((char )bytes[p], std::locale ()))
352
- break ;
353
- #else
354
- if (!std::isspace (bytes[p]))
355
- break ;
356
- #endif
357
- }
358
- s = StringView (bytes.subSpan (p, nb_byte));
383
+ s = _removeLeadingSpaces (s, p);
359
384
if (is_verbose)
360
385
std::cout << " VX=" << v.x << " remaining_s='" << s << " '\n " ;
361
- p = _getDoubleValue (v.y , s);
386
+ p = StringViewToDoubleConverter:: _getDoubleValue (v.y , s);
362
387
return (p == (-1 ) || (p != s.size ()));
363
388
}
364
389
return impl::builtInGetValueGeneric (v, s);
365
390
}
391
+
366
392
template <> ARCANE_UTILS_EXPORT bool
367
393
builtInGetValue (Real3& v, StringView s)
368
394
{
395
+ if (global_use_same_value_convert_for_all_real) {
396
+ // ATTENTION: Pour l'instant ce nouveau mécanisme ne tolère pas
397
+ // les espaces en début de \a s.
398
+ v = {};
399
+ const bool is_verbose = global_value_convert_verbosity > 0 ;
400
+ if (is_verbose)
401
+ std::cout << " Try Read Real3: '" << s << " '\n " ;
402
+ Int64 p = StringViewToDoubleConverter::_getDoubleValue (v.x , s);
403
+ if (p == (-1 ) || (p == s.size ()))
404
+ return true ;
405
+ s = _removeLeadingSpaces (s, p);
406
+ if (is_verbose)
407
+ std::cout << " VX=" << v.x << " remaining_s='" << s << " '\n " ;
408
+ p = StringViewToDoubleConverter::_getDoubleValue (v.y , s);
409
+ if (p == (-1 ) || (p == s.size ()))
410
+ return true ;
411
+ s = _removeLeadingSpaces (s, p);
412
+ if (is_verbose)
413
+ std::cout << " VY=" << v.x << " remaining_s='" << s << " '\n " ;
414
+ p = StringViewToDoubleConverter::_getDoubleValue (v.z , s);
415
+ return (p == (-1 ) || (p != s.size ()));
416
+ }
369
417
return impl::builtInGetValueGeneric (v, s);
370
418
}
371
419
0 commit comments