| /* |
| * Copyright © 2019-2026 Ebrahim Byagowi |
| * |
| * This is part of HarfBuzz, a text shaping library. |
| * |
| * Permission is hereby granted, without written agreement and without |
| * license or royalty fees, to use, copy, modify, and distribute this |
| * software and its documentation for any purpose, provided that the |
| * above copyright notice and the following two paragraphs appear in |
| * all copies of this software. |
| * |
| * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
| * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
| * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
| * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
| * DAMAGE. |
| * |
| * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
| * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
| * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
| * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
| * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
| * |
| */ |
| |
| #include <cmath> |
| #include <cstdlib> |
| |
| #include "hb.hh" |
| #include "hb-number.hh" |
| |
| static void |
| test_parse_int () |
| { |
| { |
| const char str[] = "123"; |
| const char *pp = str; |
| const char *end = str + 3; |
| |
| int pv; |
| hb_always_assert (hb_parse_int (&pp, end, &pv)); |
| hb_always_assert (pv == 123); |
| hb_always_assert (pp - str == 3); |
| hb_always_assert (end - pp == 0); |
| hb_always_assert (!*end); |
| } |
| |
| { |
| const char str[] = "-123"; |
| const char *pp = str; |
| const char *end = str + 4; |
| |
| int pv; |
| hb_always_assert (hb_parse_int (&pp, end, &pv)); |
| hb_always_assert (pv == -123); |
| hb_always_assert (pp - str == 4); |
| hb_always_assert (end - pp == 0); |
| hb_always_assert (!*end); |
| } |
| |
| /* Leading whitespace */ |
| { |
| const char str[] = " 123"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv; |
| hb_always_assert (hb_parse_int (&pp, end, &pv)); |
| hb_always_assert (pv == 123); |
| hb_always_assert (pp == end); |
| } |
| { |
| const char str[] = "\t123"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv; |
| hb_always_assert (hb_parse_int (&pp, end, &pv)); |
| hb_always_assert (pv == 123); |
| hb_always_assert (pp == end); |
| } |
| { |
| const char str[] = "\n123"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv; |
| hb_always_assert (hb_parse_int (&pp, end, &pv)); |
| hb_always_assert (pv == 123); |
| hb_always_assert (pp == end); |
| } |
| { |
| const char str[] = " -123"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv; |
| hb_always_assert (hb_parse_int (&pp, end, &pv)); |
| hb_always_assert (pv == -123); |
| hb_always_assert (pp == end); |
| } |
| |
| /* Leading '+' sign */ |
| { |
| const char str[] = "+123"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv; |
| hb_always_assert (hb_parse_int (&pp, end, &pv)); |
| hb_always_assert (pv == 123); |
| hb_always_assert (pp == end); |
| } |
| { |
| const char str[] = "+0"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv; |
| hb_always_assert (hb_parse_int (&pp, end, &pv)); |
| hb_always_assert (pv == 0); |
| hb_always_assert (pp == end); |
| } |
| |
| /* Leading zeros are decimal, not octal (base is passed as 10) */ |
| { |
| const char str[] = "007"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv; |
| hb_always_assert (hb_parse_int (&pp, end, &pv)); |
| hb_always_assert (pv == 7); |
| hb_always_assert (pp == end); |
| } |
| |
| /* Negative zero */ |
| { |
| const char str[] = "-0"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv; |
| hb_always_assert (hb_parse_int (&pp, end, &pv)); |
| hb_always_assert (pv == 0); |
| hb_always_assert (pp == end); |
| } |
| |
| /* Partial parse: stops at first non-digit */ |
| { |
| const char str[] = "123abc"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv; |
| hb_always_assert (hb_parse_int (&pp, end, &pv)); |
| hb_always_assert (pv == 123); |
| hb_always_assert (pp == str + 3); |
| } |
| |
| /* INT_MAX / INT_MIN (fits in long on every supported platform) */ |
| { |
| const char str[] = "2147483647"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv; |
| hb_always_assert (hb_parse_int (&pp, end, &pv)); |
| hb_always_assert (pv == 2147483647); |
| hb_always_assert (pp == end); |
| } |
| { |
| const char str[] = "-2147483648"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv; |
| hb_always_assert (hb_parse_int (&pp, end, &pv)); |
| hb_always_assert (pv == -2147483647 - 1); |
| hb_always_assert (pp == end); |
| } |
| |
| /* Failures: no digits */ |
| { |
| const char str[] = " "; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv = 99; |
| hb_always_assert (!hb_parse_int (&pp, end, &pv)); |
| hb_always_assert (pp == str); |
| hb_always_assert (pv == 99); |
| } |
| { |
| const char str[] = "+"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv = 99; |
| hb_always_assert (!hb_parse_int (&pp, end, &pv)); |
| } |
| { |
| const char str[] = "-"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv = 99; |
| hb_always_assert (!hb_parse_int (&pp, end, &pv)); |
| } |
| { |
| const char str[] = "abc"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv = 99; |
| hb_always_assert (!hb_parse_int (&pp, end, &pv)); |
| } |
| |
| /* Multiple signs fail */ |
| { |
| const char str[] = "++1"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv = 99; |
| hb_always_assert (!hb_parse_int (&pp, end, &pv)); |
| } |
| { |
| const char str[] = "--1"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv = 99; |
| hb_always_assert (!hb_parse_int (&pp, end, &pv)); |
| } |
| { |
| const char str[] = "+-1"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv = 99; |
| hb_always_assert (!hb_parse_int (&pp, end, &pv)); |
| } |
| { |
| const char str[] = "-+1"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv = 99; |
| hb_always_assert (!hb_parse_int (&pp, end, &pv)); |
| } |
| |
| /* whole_buffer: leading whitespace ok, trailing content rejected, |
| * and *pp / *pv are left untouched on failure */ |
| { |
| const char str[] = " 123"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv; |
| hb_always_assert (hb_parse_int (&pp, end, &pv, true)); |
| hb_always_assert (pv == 123); |
| hb_always_assert (pp == end); |
| } |
| { |
| const char str[] = "123abc"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv = 99; |
| hb_always_assert (!hb_parse_int (&pp, end, &pv, true)); |
| hb_always_assert (pp == str); |
| hb_always_assert (pv == 99); |
| } |
| { |
| /* 10 digits > INT_MAX. The old strtol-based implementation silently |
| * truncated on 64-bit platforms (long is 64-bit) but rejected on |
| * 32-bit; the new implementation rejects uniformly. */ |
| const char str[] = "9999999999"; /* 10 digits, > INT_MAX */ |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv = 99; |
| hb_always_assert (!hb_parse_int (&pp, end, &pv)); |
| hb_always_assert (pp == str); |
| hb_always_assert (pv == 99); |
| } |
| |
| /* INT_MAX / INT_MIN - exactly representable */ |
| { |
| const char str[] = "2147483647"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv; |
| hb_always_assert (hb_parse_int (&pp, end, &pv)); |
| hb_always_assert (pv == 2147483647); |
| hb_always_assert (pp == end); |
| } |
| { |
| const char str[] = "-2147483648"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv; |
| hb_always_assert (hb_parse_int (&pp, end, &pv)); |
| hb_always_assert (pv == -2147483647 - 1); /* not -2147483648, that's UB as an int literal */ |
| hb_always_assert (pp == end); |
| } |
| |
| /* One past INT_MAX - must fail */ |
| { |
| const char str[] = "2147483648"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv = 99; |
| hb_always_assert (!hb_parse_int (&pp, end, &pv)); |
| hb_always_assert (pp == str); |
| hb_always_assert (pv == 99); |
| } |
| /* One past INT_MIN - must fail */ |
| { |
| const char str[] = "-2147483649"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv = 99; |
| hb_always_assert (!hb_parse_int (&pp, end, &pv)); |
| hb_always_assert (pp == str); |
| hb_always_assert (pv == 99); |
| } |
| |
| /* Same for signed */ |
| { |
| const char str[] = "9999999999999999999999999999999999999999"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv = 99; |
| hb_always_assert (!hb_parse_int (&pp, end, &pv)); |
| hb_always_assert (pp == str); |
| hb_always_assert (pv == 99); |
| } |
| |
| { |
| /* Verify *pv and *pp are untouched when a range check rejects. */ |
| const char str[] = "9999999999"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv = 42; |
| hb_always_assert (!hb_parse_int (&pp, end, &pv)); |
| hb_always_assert (pp == str); |
| hb_always_assert (pv == 42); |
| } |
| |
| /* Whitespace between sign and digits is not allowed */ |
| { |
| const char str[] = "- 123"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv = 99; |
| hb_always_assert (!hb_parse_int (&pp, end, &pv)); |
| hb_always_assert (pp == str); |
| hb_always_assert (pv == 99); |
| } |
| |
| /* Plus zero, for symmetry with the -0 case */ |
| { |
| const char str[] = "+0"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv = 99; |
| hb_always_assert (hb_parse_int (&pp, end, &pv)); |
| hb_always_assert (pv == 0); |
| hb_always_assert (pp == end); |
| } |
| |
| /* Sign alone plus trailing whitespace still fails */ |
| { |
| const char str[] = "- "; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| int pv = 99; |
| hb_always_assert (!hb_parse_int (&pp, end, &pv)); |
| hb_always_assert (pv == 99); |
| } |
| } |
| |
| static void |
| test_parse_uint () |
| { |
| { |
| const char str[] = "123"; |
| const char *pp = str; |
| const char *end = str + strlen (str); |
| |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv)); |
| hb_always_assert (pv == 123); |
| hb_always_assert (pp - str == 3); |
| hb_always_assert (end - pp == 0); |
| hb_always_assert (!*end); |
| } |
| |
| { |
| const char str[] = "12F"; |
| const char *pp = str; |
| const char *end = str + 3; |
| |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv, true, 16)); |
| hb_always_assert (pv == 0x12F); |
| hb_always_assert (pp - str == 3); |
| hb_always_assert (end - pp == 0); |
| hb_always_assert (!*end); |
| } |
| |
| { |
| const char str[] = "12Fq"; |
| const char *pp = str; |
| const char *end = str + 4; |
| |
| unsigned int pv; |
| hb_always_assert (!hb_parse_uint (&pp, end, &pv, true, 16)); |
| hb_always_assert (hb_parse_uint (&pp, end, &pv, false, 16)); |
| hb_always_assert (pv == 0x12F); |
| hb_always_assert (pp - str == 3); |
| hb_always_assert (end - pp == 1); |
| hb_always_assert (!*end); |
| } |
| |
| { |
| const char str[] = "123"; |
| const char *pp = str; |
| hb_always_assert (ARRAY_LENGTH (str) == 4); |
| const char *end = str + ARRAY_LENGTH (str); |
| |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv)); |
| hb_always_assert (pv == 123); |
| hb_always_assert (pp - str == 3); |
| hb_always_assert (end - pp == 1); |
| } |
| |
| { |
| const char str[] = "123\0"; |
| const char *pp = str; |
| hb_always_assert (ARRAY_LENGTH (str) == 5); |
| const char *end = str + ARRAY_LENGTH (str); |
| |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv)); |
| hb_always_assert (pv == 123); |
| hb_always_assert (pp - str == 3); |
| hb_always_assert (end - pp == 2); |
| } |
| |
| { |
| const char str[] = "123V"; |
| const char *pp = str; |
| hb_always_assert (ARRAY_LENGTH (str) == 5); |
| const char *end = str + ARRAY_LENGTH (str); |
| |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv)); |
| hb_always_assert (pv == 123); |
| hb_always_assert (pp - str == 3); |
| hb_always_assert (end - pp == 2); |
| } |
| |
| { |
| const char str[] = "123abc"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv = 99; |
| hb_always_assert (!hb_parse_uint (&pp, end, &pv, true)); |
| hb_always_assert (pp == str); |
| hb_always_assert (pv == 99); |
| } |
| |
| /* Leading whitespace */ |
| { |
| const char str[] = " 123"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv)); |
| hb_always_assert (pv == 123); |
| hb_always_assert (pp == end); |
| } |
| { |
| const char str[] = "\t123"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv)); |
| hb_always_assert (pv == 123); |
| hb_always_assert (pp == end); |
| } |
| |
| /* Leading zeros (still decimal when base is 10) */ |
| { |
| const char str[] = "007"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv)); |
| hb_always_assert (pv == 7); |
| hb_always_assert (pp == end); |
| } |
| { |
| const char str[] = "000"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv)); |
| hb_always_assert (pv == 0); |
| hb_always_assert (pp == end); |
| } |
| |
| /* UINT_MAX */ |
| { |
| const char str[] = "4294967295"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv)); |
| hb_always_assert (pv == 4294967295u); |
| hb_always_assert (pp == end); |
| } |
| |
| /* Negative wraps in two's complement (matches strtoul on unsigned) */ |
| { |
| const char str[] = "-1"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv)); |
| hb_always_assert (pv == 4294967295u); |
| hb_always_assert (pp == end); |
| } |
| { |
| const char str[] = "-0"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv = 99; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv)); |
| hb_always_assert (pv == 0); |
| hb_always_assert (pp == end); |
| } |
| |
| /* Base 2 */ |
| { |
| const char str[] = "1010"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv, true, 2)); |
| hb_always_assert (pv == 10); |
| hb_always_assert (pp == end); |
| } |
| { |
| const char str[] = "11111111"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv, true, 2)); |
| hb_always_assert (pv == 255); |
| hb_always_assert (pp == end); |
| } |
| { |
| const char str[] = "12"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| /* '2' is not a base-2 digit; parse stops at index 1 */ |
| hb_always_assert (hb_parse_uint (&pp, end, &pv, false, 2)); |
| hb_always_assert (pv == 1); |
| hb_always_assert (pp == str + 1); |
| } |
| |
| /* Base 8 */ |
| { |
| const char str[] = "777"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv, true, 8)); |
| hb_always_assert (pv == 511); |
| hb_always_assert (pp == end); |
| } |
| { |
| const char str[] = "010"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv, true, 8)); |
| hb_always_assert (pv == 8); |
| hb_always_assert (pp == end); |
| } |
| |
| /* Base 16, with and without 0x prefix, mixed case */ |
| { |
| const char str[] = "FF"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv, true, 16)); |
| hb_always_assert (pv == 255); |
| hb_always_assert (pp == end); |
| } |
| { |
| const char str[] = "ff"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv, true, 16)); |
| hb_always_assert (pv == 255); |
| hb_always_assert (pp == end); |
| } |
| { |
| const char str[] = "Ff"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv, true, 16)); |
| hb_always_assert (pv == 255); |
| hb_always_assert (pp == end); |
| } |
| { |
| const char str[] = "0xFF"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv, true, 16)); |
| hb_always_assert (pv == 255); |
| hb_always_assert (pp == end); |
| } |
| { |
| const char str[] = "0XFF"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv, true, 16)); |
| hb_always_assert (pv == 255); |
| hb_always_assert (pp == end); |
| } |
| |
| /* Base 36 */ |
| { |
| const char str[] = "Z"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv, true, 36)); |
| hb_always_assert (pv == 35); |
| hb_always_assert (pp == end); |
| } |
| { |
| const char str[] = "z"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv, true, 36)); |
| hb_always_assert (pv == 35); |
| hb_always_assert (pp == end); |
| } |
| { |
| const char str[] = "10"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv, true, 36)); |
| hb_always_assert (pv == 36); |
| hb_always_assert (pp == end); |
| } |
| |
| /* Failures */ |
| { |
| const char str[] = "abc"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv = 99; |
| /* 'a' isn't a decimal digit; whole parse fails */ |
| hb_always_assert (!hb_parse_uint (&pp, end, &pv, false, 10)); |
| hb_always_assert (pp == str); |
| hb_always_assert (pv == 99); |
| } |
| { |
| const char str[] = "+"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv = 99; |
| hb_always_assert (!hb_parse_uint (&pp, end, &pv)); |
| } |
| { |
| const char str[] = "-"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv = 99; |
| hb_always_assert (!hb_parse_uint (&pp, end, &pv)); |
| } |
| { |
| const char str[] = ""; |
| const char *pp = str; |
| const char *end = str; |
| unsigned int pv = 99; |
| hb_always_assert (!hb_parse_uint (&pp, end, &pv)); |
| } |
| |
| { |
| const char str[] = "0XFF"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv, true, 16)); |
| hb_always_assert (pv == 255); |
| hb_always_assert (pp == end); |
| } |
| { |
| const char str[] = "0xff"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv, true, 16)); |
| hb_always_assert (pv == 255); |
| hb_always_assert (pp == end); |
| } |
| { |
| const char str[] = "0x0"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv, true, 16)); |
| hb_always_assert (pv == 0); |
| hb_always_assert (pp == end); |
| } |
| /* "0x" alone: consume only the 0, leave the x */ |
| { |
| const char str[] = "0x"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv, false, 16)); |
| hb_always_assert (pv == 0); |
| hb_always_assert (pp == str + 1); |
| } |
| /* "0xG": 0 is consumed, xG left */ |
| { |
| const char str[] = "0xG"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv, false, 16)); |
| hb_always_assert (pv == 0); |
| hb_always_assert (pp == str + 1); |
| } |
| /* Negative with prefix */ |
| { |
| const char str[] = "-0xFF"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv, true, 16)); |
| hb_always_assert (pv == (unsigned) -255); |
| hb_always_assert (pp == end); |
| } |
| /* Prefix rule doesn't fire for base 10 */ |
| { |
| const char str[] = "0xFF"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv, false, 10)); |
| hb_always_assert (pv == 0); |
| hb_always_assert (pp == str + 1); |
| } |
| { |
| /* 10 digits > UINT_MAX. The old strtol-based implementation silently |
| * truncated on 64-bit platforms (unsigned long is 64-bit) but rejected on |
| * 32-bit; the new implementation rejects uniformly. */ |
| const char str[] = "9999999999"; /* 10 digits, > UINT_MAX */ |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv = 99; |
| hb_always_assert (!hb_parse_uint (&pp, end, &pv)); |
| hb_always_assert (pp == str); |
| hb_always_assert (pv == 99); |
| } |
| |
| /* UINT_MAX - exactly representable */ |
| { |
| const char str[] = "4294967295"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv)); |
| hb_always_assert (pv == 4294967295u); |
| hb_always_assert (pp == end); |
| } |
| /* One past UINT_MAX - must fail (currently truncates to 0) */ |
| { |
| const char str[] = "4294967296"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv = 99; |
| hb_always_assert (!hb_parse_uint (&pp, end, &pv)); |
| hb_always_assert (pp == str); |
| hb_always_assert (pv == 99); |
| } |
| |
| /* 20 digits, way past UINT_MAX */ |
| { |
| const char str[] = "99999999999999999999"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv = 99; |
| hb_always_assert (!hb_parse_uint (&pp, end, &pv)); |
| hb_always_assert (pp == str); |
| hb_always_assert (pv == 99); |
| } |
| /* 40 digits, past the old 32-byte stack buffer */ |
| { |
| const char str[] = "9999999999999999999999999999999999999999"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv = 99; |
| hb_always_assert (!hb_parse_uint (&pp, end, &pv)); |
| hb_always_assert (pp == str); |
| hb_always_assert (pv == 99); |
| } |
| |
| /* 0xFFFFFFFF = UINT_MAX */ |
| { |
| const char str[] = "0xFFFFFFFF"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv, true, 16)); |
| hb_always_assert (pv == 4294967295u); |
| hb_always_assert (pp == end); |
| } |
| /* 0x100000000 = UINT_MAX + 1 */ |
| { |
| const char str[] = "0x100000000"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv = 99; |
| hb_always_assert (!hb_parse_uint (&pp, end, &pv, true, 16)); |
| hb_always_assert (pp == str); |
| hb_always_assert (pv == 99); |
| } |
| |
| /* 13 'Z's = 36^13 - 1, comfortably > UINT64_MAX would need ~12 digits */ |
| { |
| const char str[] = "ZZZZZZZZZZZZZZ"; /* 14 Z's */ |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv = 99; |
| hb_always_assert (!hb_parse_uint (&pp, end, &pv, true, 36)); |
| hb_always_assert (pp == str); |
| hb_always_assert (pv == 99); |
| } |
| |
| { |
| const char str[] = "9999999999"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv = 42; |
| hb_always_assert (!hb_parse_uint (&pp, end, &pv)); |
| hb_always_assert (pp == str); |
| hb_always_assert (pv == 42); |
| } |
| |
| /* Negative values whose magnitude exceeds UINT_MAX must fail, not wrap */ |
| { |
| const char str[] = "-4294967296"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv = 99; |
| hb_always_assert (!hb_parse_uint (&pp, end, &pv)); |
| hb_always_assert (pp == str); |
| hb_always_assert (pv == 99); |
| } |
| |
| /* INT_MIN magnitude as unsigned: wraps to 0x80000000 */ |
| { |
| const char str[] = "-2147483648"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv)); |
| hb_always_assert (pv == 2147483648u); |
| hb_always_assert (pp == end); |
| } |
| |
| /* Mixed case in base 36 */ |
| { |
| const char str[] = "Az"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv, true, 36)); |
| hb_always_assert (pv == 10 * 36 + 35); |
| hb_always_assert (pp == end); |
| } |
| |
| /* Whitespace between sign and digits is not allowed */ |
| { |
| const char str[] = "- 1"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv = 99; |
| hb_always_assert (!hb_parse_uint (&pp, end, &pv)); |
| hb_always_assert (pv == 99); |
| } |
| |
| /* "0x" prefix is case-insensitive but only for base 16 */ |
| { |
| const char str[] = "0X10"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv, true, 16)); |
| hb_always_assert (pv == 16); |
| hb_always_assert (pp == end); |
| } |
| |
| /* A second "0x" is not consumed as a prefix */ |
| { |
| const char str[] = "0x0x10"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv, false, 16)); |
| hb_always_assert (pv == 0); |
| hb_always_assert (pp == str + 3); |
| } |
| |
| /* Null byte stops the scan (end passed at NUL) */ |
| { |
| const char str[] = "12\0F"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| unsigned int pv; |
| hb_always_assert (hb_parse_uint (&pp, end, &pv)); |
| hb_always_assert (pv == 12); |
| hb_always_assert (pp == str + 2); |
| } |
| } |
| |
| /* Tolerate 1 ULP difference. Needed because 32-bit x86 (x87) computes |
| * at 80-bit precision and rounds to 64-bit on store, which can differ |
| * from a directly-rounded decimal literal by one ULP. */ |
| static inline bool |
| almost_equal (double a, double b) |
| { |
| return fabs (a - b) <= fabs (a) * 2 * DBL_EPSILON; |
| } |
| |
| static void |
| test_parse_double (void) |
| { |
| { |
| const char str[] = ".123"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str); |
| |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert ((int) roundf (pv * 1000.) == 123); |
| hb_always_assert (pp - str == 4); |
| hb_always_assert (end - pp == 1); |
| } |
| |
| { |
| const char str[] = "0.123"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert ((int) roundf (pv * 1000.) == 123); |
| hb_always_assert (pp - str == 5); |
| hb_always_assert (end - pp == 0); |
| } |
| |
| { |
| const char str[] = "0.123e0"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert ((int) roundf (pv * 1000.) == 123); |
| hb_always_assert (pp - str == 7); |
| hb_always_assert (end - pp == 0); |
| } |
| |
| { |
| const char str[] = "123e-3"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert ((int) roundf (pv * 1000.) == 123); |
| hb_always_assert (pp - str == 6); |
| hb_always_assert (end - pp == 0); |
| } |
| |
| { |
| const char str[] = ".000123e+3"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert ((int) roundf (pv * 1000.) == 123); |
| hb_always_assert (pp - str == 10); |
| hb_always_assert (end - pp == 0); |
| } |
| |
| { |
| const char str[] = "-.000000123e6"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert ((int) roundf (pv * 1000.) == -123); |
| hb_always_assert (pp - str == 13); |
| hb_always_assert (end - pp == 0); |
| |
| } |
| |
| { |
| const char str[] = "-1.23E-1"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert ((int) roundf (pv * 1000.) == -123); |
| hb_always_assert (pp - str == 8); |
| hb_always_assert (end - pp == 0); |
| } |
| |
| { |
| const char str[] = "1e512"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (std::isinf (pv) && pv > 0); |
| } |
| { |
| const char str[] = "1e600"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (std::isinf (pv) && pv > 0); |
| } |
| { |
| const char str[] = "1e-512"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 0.0); |
| } |
| { |
| const char str[] = "1e-600"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 0.0); |
| } |
| |
| { |
| const char str[] = "0.9999999999999999"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 1.0); |
| } |
| { |
| const char str[] = "0.499999999999999999"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 0.5); |
| } |
| |
| { |
| const char str[] = "1e"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 1.0); |
| hb_always_assert (pp == str + 1); |
| } |
| { |
| const char str[] = "1e+"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 1.0); |
| hb_always_assert (pp == str + 1); |
| } |
| { |
| const char str[] = "-"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv = 99.0; |
| hb_always_assert (!hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 99); |
| } |
| { |
| const char str[] = "."; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv = 99.0; |
| hb_always_assert (!hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 99); |
| } |
| { |
| const char str[] = "1e-"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 1.0); |
| hb_always_assert (pp == str + 1); |
| } |
| { |
| const char str[] = "-1e"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == -1.0); |
| hb_always_assert (pp == str + 2); |
| } |
| { |
| const char str[] = "+"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv = 99.0; |
| hb_always_assert (!hb_parse_double (&pp, end, &pv)); |
| } |
| { |
| const char str[] = "-."; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv = 99.0; |
| hb_always_assert (!hb_parse_double (&pp, end, &pv)); |
| } |
| |
| // But be careful with fractional parts |
| { |
| const char str[] = "1."; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv, true)); |
| hb_always_assert (pv == 1.0); |
| hb_always_assert (pp == end); |
| } |
| { |
| const char str[] = "1.abc"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 1.0); |
| hb_always_assert (pp == str + 2); // at least "1." was consumed |
| } |
| |
| { |
| const char str[] = "abc"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv = 99.0; |
| hb_always_assert (!hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 99.0); |
| } |
| { |
| const char str[] = ""; |
| const char *pp = str; |
| const char *end = str; |
| double pv = 99.0; |
| hb_always_assert (!hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 99.0); |
| } |
| { |
| const char str[] = " \t 123"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 123.0); |
| hb_always_assert (pp == end); |
| } |
| { |
| const char str[] = "-0.0"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 0.0 && std::signbit (pv)); |
| } |
| { |
| const char str[] = "1.5E10"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv, true)); |
| hb_always_assert (pv == 1.5e10); |
| } |
| { |
| const char str[] = "1.5E+10"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv, true)); |
| hb_always_assert (pv == 1.5e10); |
| } |
| { |
| const char str[] = "1e308"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv > 0 && pv <= DBL_MAX); |
| } |
| { |
| const char str[] = "1e309"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (std::isinf (pv) && pv > 0); |
| } |
| { |
| const char str[] = "1e-309"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv > 0.0 && pv < DBL_MIN); |
| hb_always_assert (pv == strtod (str, nullptr)); |
| } |
| { |
| const char str[] = "5e-324"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv, true)); |
| hb_always_assert (pv > 0.0 && pv < DBL_MIN); |
| hb_always_assert (pv == strtod (str, nullptr)); |
| } |
| { |
| const char str[] = "1e+5"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 100000.0); |
| } |
| { |
| const char str[] = "1E5"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 100000.0); |
| } |
| { |
| const char str[] = "123abc"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 123.0); |
| hb_always_assert (pp == str + 3); |
| } |
| { |
| const char str[] = "123abc"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (!hb_parse_double (&pp, end, &pv, true)); |
| } |
| { |
| const char str[] = "-1.5"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv, true)); |
| hb_always_assert (pv == -1.5); |
| } |
| { |
| const char str[] = "1.5E-10"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv, true)); |
| hb_always_assert (almost_equal (pv, 1.5e-10)); |
| } |
| { |
| const char str[] = "-.5"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv, true)); |
| hb_always_assert (pv == -0.5); |
| } |
| { |
| const char str[] = "500"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 500.0); |
| } |
| { |
| const char str[] = "-7.5"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == -7.5); |
| } |
| { |
| const char str[] = "123 "; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (!hb_parse_double (&pp, end, &pv, true)); |
| } |
| { |
| const char str[] = " 123"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv, true)); |
| hb_always_assert (pv == 123.0); |
| } |
| { |
| const char str[] = "+1"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv, true)); |
| hb_always_assert (pv == 1.0); |
| } |
| { |
| const char str[] = "+1.5"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv, true)); |
| hb_always_assert (pv == 1.5); |
| } |
| { |
| const char str[] = "--1"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv = 99.0; |
| hb_always_assert (!hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 99.0); |
| } |
| { |
| const char str[] = "+-1"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv = 99.0; |
| hb_always_assert (!hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 99.0); |
| } |
| { |
| const char str[] = "0e5"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv, true)); |
| hb_always_assert (pv == 0.0); |
| } |
| { |
| const char str[] = "1.5e"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 1.5); |
| hb_always_assert (pp == str + 3); |
| } |
| { |
| const char str[] = "1.5e+"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 1.5); |
| hb_always_assert (pp == str + 3); |
| } |
| { |
| const char str[] = "1e9999999"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == DBL_MAX); |
| } |
| { |
| const char str[] = "-1e9999999"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == -DBL_MAX); |
| } |
| { |
| const char str[] = "1e-9999999"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == .0); |
| hb_always_assert (pv == strtod (str, nullptr)); |
| } |
| { |
| const char str[] = "-1e-9999999"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == -.0); |
| hb_always_assert (pv == -strtod (str, nullptr)); |
| } |
| { |
| const char str[] = "1e-400"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 0.0); |
| } |
| { |
| const char str[] = "007"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv, true)); |
| hb_always_assert (pv == 7.0); |
| } |
| { |
| const char str[] = "0.0"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv, true)); |
| hb_always_assert (pv == 0.0 && !std::signbit (pv)); |
| } |
| { |
| const char str[] = "NaN"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv = 99.0; |
| hb_always_assert (!hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 99.0); |
| } |
| { |
| const char str[] = "inf"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv = 99.0; |
| hb_always_assert (!hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 99.0); |
| } |
| { |
| const char str[] = "1..5"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 1.0); |
| hb_always_assert (pp == str + 2); // Don't consume ending ".5" |
| } |
| { |
| const char str[] = "1.5.5"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 1.5); |
| hb_always_assert (pp == str + 3); // Don't consume ending ".5" |
| } |
| |
| { |
| const char str[] = " "; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv = 99.0; |
| hb_always_assert (!hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 99.0); |
| } |
| { |
| const char str[] = " abc"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv = 99.0; |
| hb_always_assert (!hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pp == str); |
| hb_always_assert (pv == 99.0); |
| } |
| |
| { |
| const char str[] = "1.7976931348623157e308"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv, true)); |
| hb_always_assert (pv >= DBL_MAX || std::isinf (pv)); |
| hb_always_assert (pp == end); |
| } |
| { |
| const char str[] = "99999999999999999999"; // 20 nines |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv, true)); |
| hb_always_assert (pv >= 1e19 && pv <= 1.1e20); |
| hb_always_assert (pp == end); |
| } |
| { |
| const char str[] = "1.e5"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 100000.0); |
| hb_always_assert (pp == end); |
| } |
| |
| /* Exponent with leading zeros */ |
| { |
| const char str[] = "1e005"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv, true)); |
| hb_always_assert (pv == 100000.0); |
| hb_always_assert (pp == end); |
| } |
| { |
| const char str[] = "1e-005"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv, true)); |
| hb_always_assert (almost_equal (pv, 1e-5)); |
| hb_always_assert (pp == end); |
| } |
| |
| /* Bare -0 (no decimal) preserves the sign, matching strtod */ |
| { |
| const char str[] = "-0"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv, true)); |
| hb_always_assert (pv == 0.0 && std::signbit (pv)); |
| hb_always_assert (pp == end); |
| } |
| |
| /* Long mantissa followed by an exponent */ |
| { |
| const char str[] = "12345678901234567890e-10"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv, true)); |
| hb_always_assert (pv > 1.234e9 && pv < 1.235e9); |
| hb_always_assert (pp == end); |
| } |
| |
| /* whole_buffer failure must not touch *pv */ |
| { |
| const char str[] = "123abc"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv = 42.0; |
| hb_always_assert (!hb_parse_double (&pp, end, &pv, true)); |
| hb_always_assert (pp == str); |
| hb_always_assert (pv == 42.0); |
| } |
| |
| /* Same for no-match failure */ |
| { |
| const char str[] = "abc"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv = 42.0; |
| hb_always_assert (!hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pp == str); |
| hb_always_assert (pv == 42.0); |
| } |
| |
| /* Exponent followed by trailing content */ |
| { |
| const char str[] = "1e5abc"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 100000.0); |
| hb_always_assert (pp == str + 3); |
| } |
| /* Same with a sign in the exponent */ |
| { |
| const char str[] = "1e+5x"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 100000.0); |
| hb_always_assert (pp == str + 4); |
| } |
| /* Malformed exponent followed by content: should stop at the 'e' */ |
| { |
| const char str[] = "1ex"; |
| const char *pp = str; |
| const char *end = str + ARRAY_LENGTH (str) - 1; |
| double pv; |
| hb_always_assert (hb_parse_double (&pp, end, &pv)); |
| hb_always_assert (pv == 1.0); |
| hb_always_assert (pp == str + 1); |
| } |
| } |
| |
| int |
| main (int argc, char **argv) |
| { |
| test_parse_double (); |
| test_parse_int (); |
| test_parse_uint (); |
| |
| return 0; |
| } |