]> granicus.if.org Git - php/commitdiff
add zend_u_strtod() implementation by Matt Wilmas
authorAntony Dovgal <tony2001@php.net>
Wed, 6 Dec 2006 12:25:29 +0000 (12:25 +0000)
committerAntony Dovgal <tony2001@php.net>
Wed, 6 Dec 2006 12:25:29 +0000 (12:25 +0000)
major speedup when using floats in Unicode mode
also fixes several problems with the current code

Zend/zend_strtod.c

index 696e124fa92002dcf2a9fa028c387487245a3f11..3dfdab571fecf2c555b2b71c761b656ff7b36caf 100644 (file)
@@ -2560,24 +2560,89 @@ ret:
        return result;
 }
 
-/* UTODO: someone can reimplement this using the code above, if they really want to. */
 ZEND_API double zend_u_strtod(const UChar *nptr, UChar **endptr)
 {
-       double value = 0.0;
-       int32_t num_conv = 0, num_read = 0;
+       const UChar *u = nptr, *nstart;
+       UChar c = *u;
+       int any = 0;
 
-       num_conv = u_sscanf(nptr, "%f%n", &value, &num_read);
-       if (num_conv != EOF) {
-               if (endptr != 0) {
-                       *endptr = (UChar *)nptr + num_read;
+       while (u_isspace(c)) {
+               c = *++u;
+       }
+       nstart = u;
+
+       if (c == 0x2D /*'-'*/ || c == 0x2B /*'+'*/) {
+               c = *++u;
+       }
+
+       while (c >= 0x30 /*'0'*/ && c <= 0x39 /*'9'*/) {
+               any = 1;
+               c = *++u;
+       }
+
+       if (c == 0x2E /*'.'*/) {
+               c = *++u;
+               while (c >= 0x30 /*'0'*/ && c <= 0x39 /*'9'*/) {
+                       any = 1;
+                       c = *++u;
                }
-               return value;
-       } else {
-               if (endptr != 0) {
-                       *endptr = (UChar *)nptr;
+       }
+
+       if ((c == 0x65 /*'e'*/ || c == 0x45 /*'E'*/) && any) {
+               const UChar *e = u;
+               int any_exp = 0;
+
+               c = *++u;
+               if (c == 0x2D /*'-'*/ || c == 0x2B /*'+'*/) {
+                       c = *++u;
+               }
+
+               while (c >= 0x30 /*'0'*/ && c <= 0x39 /*'9'*/) {
+                       any_exp = 1;
+                       c = *++u;
+               }
+
+               if (!any_exp) {
+                       u = e;
                }
-               return 0;
        }
+
+       if (any) {
+               char buf[64], *numbuf, *bufpos;
+               int length = u - nstart;
+               double value;
+
+               if (length < sizeof(buf)) {
+                       numbuf = buf;
+               } else {
+                       numbuf = (char *) do_alloca(length + 1);
+               }
+
+               bufpos = numbuf;
+
+               while (nstart < u) {
+                       *bufpos++ = (char) *nstart++;
+               }
+
+               *bufpos = '\0';
+               value = zend_strtod(numbuf, NULL);
+
+               if (numbuf != buf) {
+                       free_alloca(numbuf);
+               }
+
+               if (endptr != NULL) {
+                       *endptr = (UChar *)u;
+               }
+
+               return value;
+       }
+
+       if (endptr != NULL) {
+               *endptr = (UChar *)nptr;
+       }
+
+       return 0;
 }
 
 /*