1/*
2 * Copyright (C) 2018 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28namespace WTF {
29
30inline bool isCharacterAllowedInBase(UChar c, int base)
31{
32 if (c > 0x7F)
33 return false;
34 if (isASCIIDigit(c))
35 return c - '0' < base;
36 if (isASCIIAlpha(c)) {
37 if (base > 36)
38 base = 36;
39 return (c >= 'a' && c < 'a' + base - 10)
40 || (c >= 'A' && c < 'A' + base - 10);
41 }
42 return false;
43}
44
45template<typename IntegralType, typename CharacterType>
46inline IntegralType toIntegralType(const CharacterType* data, size_t length, bool* ok = nullptr, int base = 10)
47{
48 static const IntegralType integralMax = std::numeric_limits<IntegralType>::max();
49 static const bool isSigned = std::numeric_limits<IntegralType>::is_signed;
50 const IntegralType maxMultiplier = integralMax / base;
51
52 IntegralType value = 0;
53 bool isOk = false;
54 bool isNegative = false;
55
56 if (!data)
57 goto bye;
58
59 // skip leading whitespace
60 while (length && isSpaceOrNewline(*data)) {
61 --length;
62 ++data;
63 }
64
65 if (isSigned && length && *data == '-') {
66 --length;
67 ++data;
68 isNegative = true;
69 } else if (length && *data == '+') {
70 --length;
71 ++data;
72 }
73
74 if (!length || !isCharacterAllowedInBase(*data, base))
75 goto bye;
76
77 while (length && isCharacterAllowedInBase(*data, base)) {
78 --length;
79 IntegralType digitValue;
80 auto c = *data;
81 if (isASCIIDigit(c))
82 digitValue = c - '0';
83 else if (c >= 'a')
84 digitValue = c - 'a' + 10;
85 else
86 digitValue = c - 'A' + 10;
87
88 if (value > maxMultiplier || (value == maxMultiplier && digitValue > (integralMax % base) + isNegative))
89 goto bye;
90
91 value = base * value + digitValue;
92 ++data;
93 }
94
95#if COMPILER(MSVC)
96#pragma warning(push, 0)
97#pragma warning(disable:4146)
98#endif
99
100 if (isNegative)
101 value = -value;
102
103#if COMPILER(MSVC)
104#pragma warning(pop)
105#endif
106
107 // skip trailing space
108 while (length && isSpaceOrNewline(*data)) {
109 --length;
110 ++data;
111 }
112
113 if (!length)
114 isOk = true;
115bye:
116 if (ok)
117 *ok = isOk;
118 return isOk ? value : 0;
119}
120
121template<typename IntegralType, typename StringOrStringView>
122inline IntegralType toIntegralType(const StringOrStringView& stringView, bool* ok = nullptr, int base = 10)
123{
124 if (stringView.is8Bit())
125 return toIntegralType<IntegralType, LChar>(stringView.characters8(), stringView.length(), ok, base);
126 return toIntegralType<IntegralType, UChar>(stringView.characters16(), stringView.length(), ok, base);
127}
128
129}
130
131using WTF::toIntegralType;
132