1*7c666c14SSiva Chandra Reddy //===-- Utilities to convert integral values to string ----------*- C++ -*-===//
2*7c666c14SSiva Chandra Reddy //
3*7c666c14SSiva Chandra Reddy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*7c666c14SSiva Chandra Reddy // See https://llvm.org/LICENSE.txt for license information.
5*7c666c14SSiva Chandra Reddy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*7c666c14SSiva Chandra Reddy //
7*7c666c14SSiva Chandra Reddy //===----------------------------------------------------------------------===//
8*7c666c14SSiva Chandra Reddy 
9*7c666c14SSiva Chandra Reddy #ifndef LLVM_LIBC_SRC_SUPPORT_INTEGER_TO_STRING_H
10*7c666c14SSiva Chandra Reddy #define LLVM_LIBC_SRC_SUPPORT_INTEGER_TO_STRING_H
11*7c666c14SSiva Chandra Reddy 
12*7c666c14SSiva Chandra Reddy #include "src/__support/CPP/StringView.h"
13*7c666c14SSiva Chandra Reddy #include "src/__support/CPP/TypeTraits.h"
14*7c666c14SSiva Chandra Reddy 
15*7c666c14SSiva Chandra Reddy namespace __llvm_libc {
16*7c666c14SSiva Chandra Reddy 
17*7c666c14SSiva Chandra Reddy template <typename T> class IntegerToString {
18*7c666c14SSiva Chandra Reddy   static_assert(cpp::IsIntegral<T>::Value,
19*7c666c14SSiva Chandra Reddy                 "IntegerToString can only be used with integral types.");
20*7c666c14SSiva Chandra Reddy 
21*7c666c14SSiva Chandra Reddy   using UnsignedType = cpp::MakeUnsignedType<T>;
22*7c666c14SSiva Chandra Reddy 
23*7c666c14SSiva Chandra Reddy   // We size the string buffer using an approximation algorithm:
24*7c666c14SSiva Chandra Reddy   //
25*7c666c14SSiva Chandra Reddy   //   size = ceil(sizeof(T) * 5 / 2)
26*7c666c14SSiva Chandra Reddy   //
27*7c666c14SSiva Chandra Reddy   // If sizeof(T) is 1, then size is 3 (actually 3)
28*7c666c14SSiva Chandra Reddy   // If sizeof(T) is 2, then size is 5 (actually need 5)
29*7c666c14SSiva Chandra Reddy   // If sizeof(T) is 4, then size is 10 (actually need 10)
30*7c666c14SSiva Chandra Reddy   // If sizeof(T) is 8, then size is 20 (actually need 20)
31*7c666c14SSiva Chandra Reddy   // If sizeof(T) is 16, then size is 40 (actually need 39)
32*7c666c14SSiva Chandra Reddy   //
33*7c666c14SSiva Chandra Reddy   // NOTE: The ceil operation is actually implemented as
34*7c666c14SSiva Chandra Reddy   //     floor(((sizeof(T) * 5) + 1)/2)
35*7c666c14SSiva Chandra Reddy   // where floor operation is just integer division.
36*7c666c14SSiva Chandra Reddy   //
37*7c666c14SSiva Chandra Reddy   // This estimation grows slightly faster than the actual value, but the
38*7c666c14SSiva Chandra Reddy   // overhead is small enough to tolerate. In the actual formula below, we
39*7c666c14SSiva Chandra Reddy   // add an additional byte to accommodate the '-' sign in case of signed
40*7c666c14SSiva Chandra Reddy   // integers.
41*7c666c14SSiva Chandra Reddy   static constexpr size_t BUFSIZE =
42*7c666c14SSiva Chandra Reddy       (sizeof(T) * 5 + 1) / 2 + (cpp::IsSigned<T>() ? 1 : 0);
43*7c666c14SSiva Chandra Reddy   char strbuf[BUFSIZE] = {'\0'};
44*7c666c14SSiva Chandra Reddy   size_t len = 0;
45*7c666c14SSiva Chandra Reddy 
convert(UnsignedType val)46*7c666c14SSiva Chandra Reddy   constexpr void convert(UnsignedType val) {
47*7c666c14SSiva Chandra Reddy     size_t buffptr = BUFSIZE;
48*7c666c14SSiva Chandra Reddy     if (val == 0) {
49*7c666c14SSiva Chandra Reddy       strbuf[buffptr - 1] = '0';
50*7c666c14SSiva Chandra Reddy       --buffptr;
51*7c666c14SSiva Chandra Reddy     } else {
52*7c666c14SSiva Chandra Reddy       for (; val > 0; --buffptr, val /= 10)
53*7c666c14SSiva Chandra Reddy         strbuf[buffptr - 1] = (val % 10) + '0';
54*7c666c14SSiva Chandra Reddy     }
55*7c666c14SSiva Chandra Reddy     len = BUFSIZE - buffptr;
56*7c666c14SSiva Chandra Reddy   }
57*7c666c14SSiva Chandra Reddy 
58*7c666c14SSiva Chandra Reddy public:
IntegerToString(T val)59*7c666c14SSiva Chandra Reddy   constexpr explicit IntegerToString(T val) {
60*7c666c14SSiva Chandra Reddy     convert(val < 0 ? UnsignedType(-val) : UnsignedType(val));
61*7c666c14SSiva Chandra Reddy     if (val < 0) {
62*7c666c14SSiva Chandra Reddy       // This branch will be taken only for negative signed values.
63*7c666c14SSiva Chandra Reddy       ++len;
64*7c666c14SSiva Chandra Reddy       strbuf[BUFSIZE - len] = '-';
65*7c666c14SSiva Chandra Reddy     }
66*7c666c14SSiva Chandra Reddy   }
67*7c666c14SSiva Chandra Reddy 
str()68*7c666c14SSiva Chandra Reddy   cpp::StringView str() const {
69*7c666c14SSiva Chandra Reddy     return cpp::StringView(strbuf + BUFSIZE - len, len);
70*7c666c14SSiva Chandra Reddy   }
71*7c666c14SSiva Chandra Reddy 
StringView()72*7c666c14SSiva Chandra Reddy   operator cpp::StringView() const { return str(); }
73*7c666c14SSiva Chandra Reddy };
74*7c666c14SSiva Chandra Reddy 
integer_to_string(T val)75*7c666c14SSiva Chandra Reddy template <typename T> IntegerToString<T> integer_to_string(T val) {
76*7c666c14SSiva Chandra Reddy   return IntegerToString<T>(val);
77*7c666c14SSiva Chandra Reddy }
78*7c666c14SSiva Chandra Reddy 
79*7c666c14SSiva Chandra Reddy } // namespace __llvm_libc
80*7c666c14SSiva Chandra Reddy 
81*7c666c14SSiva Chandra Reddy #endif // LLVM_LIBC_SRC_SUPPORT_INTEGER_TO_STRING_H
82