1//===------------------------- charconv.cpp -------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "charconv"
10#include <string.h>
11
12_LIBCPP_BEGIN_NAMESPACE_STD
13
14namespace __itoa
15{
16
17static constexpr char cDigitsLut[200] = {
18    '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0',
19    '7', '0', '8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3', '1', '4',
20    '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '2', '0', '2', '1', '2',
21    '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
22    '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', '3', '5', '3', '6', '3',
23    '7', '3', '8', '3', '9', '4', '0', '4', '1', '4', '2', '4', '3', '4', '4',
24    '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', '5', '0', '5', '1', '5',
25    '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
26    '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6',
27    '7', '6', '8', '6', '9', '7', '0', '7', '1', '7', '2', '7', '3', '7', '4',
28    '7', '5', '7', '6', '7', '7', '7', '8', '7', '9', '8', '0', '8', '1', '8',
29    '2', '8', '3', '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9',
30    '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9',
31    '7', '9', '8', '9', '9'};
32
33template <typename T>
34inline _LIBCPP_INLINE_VISIBILITY char*
35append1(char* buffer, T i)
36{
37    *buffer = '0' + static_cast<char>(i);
38    return buffer + 1;
39}
40
41template <typename T>
42inline _LIBCPP_INLINE_VISIBILITY char*
43append2(char* buffer, T i)
44{
45    memcpy(buffer, &cDigitsLut[(i)*2], 2);
46    return buffer + 2;
47}
48
49template <typename T>
50inline _LIBCPP_INLINE_VISIBILITY char*
51append3(char* buffer, T i)
52{
53    return append2(append1(buffer, (i) / 100), (i) % 100);
54}
55
56template <typename T>
57inline _LIBCPP_INLINE_VISIBILITY char*
58append4(char* buffer, T i)
59{
60    return append2(append2(buffer, (i) / 100), (i) % 100);
61}
62
63template <typename T>
64inline _LIBCPP_INLINE_VISIBILITY char*
65append2_no_zeros(char* buffer, T v)
66{
67    if (v < 10)
68        return append1(buffer, v);
69    else
70        return append2(buffer, v);
71}
72
73template <typename T>
74inline _LIBCPP_INLINE_VISIBILITY char*
75append4_no_zeros(char* buffer, T v)
76{
77    if (v < 100)
78        return append2_no_zeros(buffer, v);
79    else if (v < 1000)
80        return append3(buffer, v);
81    else
82        return append4(buffer, v);
83}
84
85template <typename T>
86inline _LIBCPP_INLINE_VISIBILITY char*
87append8_no_zeros(char* buffer, T v)
88{
89    if (v < 10000)
90    {
91        buffer = append4_no_zeros(buffer, v);
92    }
93    else
94    {
95        buffer = append4_no_zeros(buffer, v / 10000);
96        buffer = append4(buffer, v % 10000);
97    }
98    return buffer;
99}
100
101char*
102__u32toa(uint32_t value, char* buffer)
103{
104    if (value < 100000000)
105    {
106        buffer = append8_no_zeros(buffer, value);
107    }
108    else
109    {
110        // value = aabbbbcccc in decimal
111        const uint32_t a = value / 100000000;  // 1 to 42
112        value %= 100000000;
113
114        buffer = append2_no_zeros(buffer, a);
115        buffer = append4(buffer, value / 10000);
116        buffer = append4(buffer, value % 10000);
117    }
118
119    return buffer;
120}
121
122char*
123__u64toa(uint64_t value, char* buffer)
124{
125    if (value < 100000000)
126    {
127        uint32_t v = static_cast<uint32_t>(value);
128        buffer = append8_no_zeros(buffer, v);
129    }
130    else if (value < 10000000000000000)
131    {
132        const uint32_t v0 = static_cast<uint32_t>(value / 100000000);
133        const uint32_t v1 = static_cast<uint32_t>(value % 100000000);
134
135        buffer = append8_no_zeros(buffer, v0);
136        buffer = append4(buffer, v1 / 10000);
137        buffer = append4(buffer, v1 % 10000);
138    }
139    else
140    {
141        const uint32_t a =
142            static_cast<uint32_t>(value / 10000000000000000);  // 1 to 1844
143        value %= 10000000000000000;
144
145        buffer = append4_no_zeros(buffer, a);
146
147        const uint32_t v0 = static_cast<uint32_t>(value / 100000000);
148        const uint32_t v1 = static_cast<uint32_t>(value % 100000000);
149        buffer = append4(buffer, v0 / 10000);
150        buffer = append4(buffer, v0 % 10000);
151        buffer = append4(buffer, v1 / 10000);
152        buffer = append4(buffer, v1 % 10000);
153    }
154
155    return buffer;
156}
157
158}  // namespace __itoa
159
160_LIBCPP_END_NAMESPACE_STD
161