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