Path: blob/main/contrib/llvm-project/libcxx/include/__charconv/to_chars_integral.h
35262 views
// -*- C++ -*-1//===----------------------------------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//89#ifndef _LIBCPP___CHARCONV_TO_CHARS_INTEGRAL_H10#define _LIBCPP___CHARCONV_TO_CHARS_INTEGRAL_H1112#include <__algorithm/copy_n.h>13#include <__assert>14#include <__bit/countl.h>15#include <__charconv/tables.h>16#include <__charconv/to_chars_base_10.h>17#include <__charconv/to_chars_result.h>18#include <__charconv/traits.h>19#include <__config>20#include <__system_error/errc.h>21#include <__type_traits/enable_if.h>22#include <__type_traits/integral_constant.h>23#include <__type_traits/is_same.h>24#include <__type_traits/make_32_64_or_128_bit.h>25#include <__type_traits/make_unsigned.h>26#include <__utility/unreachable.h>27#include <cstddef>28#include <cstdint>29#include <limits>3031#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)32# pragma GCC system_header33#endif3435_LIBCPP_PUSH_MACROS36#include <__undef_macros>3738_LIBCPP_BEGIN_NAMESPACE_STD3940#if _LIBCPP_STD_VER >= 174142to_chars_result to_chars(char*, char*, bool, int = 10) = delete;4344template <typename _Tp>45inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result46__to_chars_itoa(char* __first, char* __last, _Tp __value, false_type);4748template <typename _Tp>49inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result50__to_chars_itoa(char* __first, char* __last, _Tp __value, true_type) {51auto __x = std::__to_unsigned_like(__value);52if (__value < 0 && __first != __last) {53*__first++ = '-';54__x = std::__complement(__x);55}5657return std::__to_chars_itoa(__first, __last, __x, false_type());58}5960template <typename _Tp>61inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result62__to_chars_itoa(char* __first, char* __last, _Tp __value, false_type) {63using __tx = __itoa::__traits<_Tp>;64auto __diff = __last - __first;6566if (__tx::digits <= __diff || __tx::__width(__value) <= __diff)67return {__tx::__convert(__first, __value), errc(0)};68else69return {__last, errc::value_too_large};70}7172# ifndef _LIBCPP_HAS_NO_INT12873template <>74inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result75__to_chars_itoa(char* __first, char* __last, __uint128_t __value, false_type) {76// When the value fits in 64-bits use the 64-bit code path. This reduces77// the number of expensive calculations on 128-bit values.78//79// NOTE the 128-bit code path requires this optimization.80if (__value <= numeric_limits<uint64_t>::max())81return __to_chars_itoa(__first, __last, static_cast<uint64_t>(__value), false_type());8283using __tx = __itoa::__traits<__uint128_t>;84auto __diff = __last - __first;8586if (__tx::digits <= __diff || __tx::__width(__value) <= __diff)87return {__tx::__convert(__first, __value), errc(0)};88else89return {__last, errc::value_too_large};90}91# endif9293template <class _Tp>94inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result95__to_chars_integral(char* __first, char* __last, _Tp __value, int __base, false_type);9697template <typename _Tp>98inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result99__to_chars_integral(char* __first, char* __last, _Tp __value, int __base, true_type) {100auto __x = std::__to_unsigned_like(__value);101if (__value < 0 && __first != __last) {102*__first++ = '-';103__x = std::__complement(__x);104}105106return std::__to_chars_integral(__first, __last, __x, __base, false_type());107}108109namespace __itoa {110111template <unsigned _Base>112struct _LIBCPP_HIDDEN __integral;113114template <>115struct _LIBCPP_HIDDEN __integral<2> {116template <typename _Tp>117_LIBCPP_HIDE_FROM_ABI static constexpr int __width(_Tp __value) noexcept {118// If value == 0 still need one digit. If the value != this has no119// effect since the code scans for the most significant bit set. (Note120// that __libcpp_clz doesn't work for 0.)121return numeric_limits<_Tp>::digits - std::__libcpp_clz(__value | 1);122}123124template <typename _Tp>125_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI static to_chars_result126__to_chars(char* __first, char* __last, _Tp __value) {127ptrdiff_t __cap = __last - __first;128int __n = __width(__value);129if (__n > __cap)130return {__last, errc::value_too_large};131132__last = __first + __n;133char* __p = __last;134const unsigned __divisor = 16;135while (__value > __divisor) {136unsigned __c = __value % __divisor;137__value /= __divisor;138__p -= 4;139std::copy_n(&__base_2_lut[4 * __c], 4, __p);140}141do {142unsigned __c = __value % 2;143__value /= 2;144*--__p = "01"[__c];145} while (__value != 0);146return {__last, errc(0)};147}148};149150template <>151struct _LIBCPP_HIDDEN __integral<8> {152template <typename _Tp>153_LIBCPP_HIDE_FROM_ABI static constexpr int __width(_Tp __value) noexcept {154// If value == 0 still need one digit. If the value != this has no155// effect since the code scans for the most significat bit set. (Note156// that __libcpp_clz doesn't work for 0.)157return ((numeric_limits<_Tp>::digits - std::__libcpp_clz(__value | 1)) + 2) / 3;158}159160template <typename _Tp>161_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI static to_chars_result162__to_chars(char* __first, char* __last, _Tp __value) {163ptrdiff_t __cap = __last - __first;164int __n = __width(__value);165if (__n > __cap)166return {__last, errc::value_too_large};167168__last = __first + __n;169char* __p = __last;170unsigned __divisor = 64;171while (__value > __divisor) {172unsigned __c = __value % __divisor;173__value /= __divisor;174__p -= 2;175std::copy_n(&__base_8_lut[2 * __c], 2, __p);176}177do {178unsigned __c = __value % 8;179__value /= 8;180*--__p = "01234567"[__c];181} while (__value != 0);182return {__last, errc(0)};183}184};185186template <>187struct _LIBCPP_HIDDEN __integral<16> {188template <typename _Tp>189_LIBCPP_HIDE_FROM_ABI static constexpr int __width(_Tp __value) noexcept {190// If value == 0 still need one digit. If the value != this has no191// effect since the code scans for the most significat bit set. (Note192// that __libcpp_clz doesn't work for 0.)193return (numeric_limits<_Tp>::digits - std::__libcpp_clz(__value | 1) + 3) / 4;194}195196template <typename _Tp>197_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI static to_chars_result198__to_chars(char* __first, char* __last, _Tp __value) {199ptrdiff_t __cap = __last - __first;200int __n = __width(__value);201if (__n > __cap)202return {__last, errc::value_too_large};203204__last = __first + __n;205char* __p = __last;206unsigned __divisor = 256;207while (__value > __divisor) {208unsigned __c = __value % __divisor;209__value /= __divisor;210__p -= 2;211std::copy_n(&__base_16_lut[2 * __c], 2, __p);212}213if (__first != __last)214do {215unsigned __c = __value % 16;216__value /= 16;217*--__p = "0123456789abcdef"[__c];218} while (__value != 0);219return {__last, errc(0)};220}221};222223} // namespace __itoa224225template <unsigned _Base, typename _Tp, __enable_if_t<(sizeof(_Tp) >= sizeof(unsigned)), int> = 0>226_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int __to_chars_integral_width(_Tp __value) {227return __itoa::__integral<_Base>::__width(__value);228}229230template <unsigned _Base, typename _Tp, __enable_if_t<(sizeof(_Tp) < sizeof(unsigned)), int> = 0>231_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int __to_chars_integral_width(_Tp __value) {232return std::__to_chars_integral_width<_Base>(static_cast<unsigned>(__value));233}234235template <unsigned _Base, typename _Tp, __enable_if_t<(sizeof(_Tp) >= sizeof(unsigned)), int> = 0>236_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result237__to_chars_integral(char* __first, char* __last, _Tp __value) {238return __itoa::__integral<_Base>::__to_chars(__first, __last, __value);239}240241template <unsigned _Base, typename _Tp, __enable_if_t<(sizeof(_Tp) < sizeof(unsigned)), int> = 0>242_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result243__to_chars_integral(char* __first, char* __last, _Tp __value) {244return std::__to_chars_integral<_Base>(__first, __last, static_cast<unsigned>(__value));245}246247template <typename _Tp>248_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int __to_chars_integral_width(_Tp __value, unsigned __base) {249_LIBCPP_ASSERT_INTERNAL(__value >= 0, "The function requires a non-negative value.");250251unsigned __base_2 = __base * __base;252unsigned __base_3 = __base_2 * __base;253unsigned __base_4 = __base_2 * __base_2;254255int __r = 0;256while (true) {257if (__value < __base)258return __r + 1;259if (__value < __base_2)260return __r + 2;261if (__value < __base_3)262return __r + 3;263if (__value < __base_4)264return __r + 4;265266__value /= __base_4;267__r += 4;268}269270__libcpp_unreachable();271}272273template <typename _Tp>274inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result275__to_chars_integral(char* __first, char* __last, _Tp __value, int __base, false_type) {276if (__base == 10) [[likely]]277return std::__to_chars_itoa(__first, __last, __value, false_type());278279switch (__base) {280case 2:281return std::__to_chars_integral<2>(__first, __last, __value);282case 8:283return std::__to_chars_integral<8>(__first, __last, __value);284case 16:285return std::__to_chars_integral<16>(__first, __last, __value);286}287288ptrdiff_t __cap = __last - __first;289int __n = std::__to_chars_integral_width(__value, __base);290if (__n > __cap)291return {__last, errc::value_too_large};292293__last = __first + __n;294char* __p = __last;295do {296unsigned __c = __value % __base;297__value /= __base;298*--__p = "0123456789abcdefghijklmnopqrstuvwxyz"[__c];299} while (__value != 0);300return {__last, errc(0)};301}302303template <typename _Tp, __enable_if_t<is_integral<_Tp>::value, int> = 0>304inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result305to_chars(char* __first, char* __last, _Tp __value) {306using _Type = __make_32_64_or_128_bit_t<_Tp>;307static_assert(!is_same<_Type, void>::value, "unsupported integral type used in to_chars");308return std::__to_chars_itoa(__first, __last, static_cast<_Type>(__value), is_signed<_Tp>());309}310311template <typename _Tp, __enable_if_t<is_integral<_Tp>::value, int> = 0>312inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result313to_chars(char* __first, char* __last, _Tp __value, int __base) {314_LIBCPP_ASSERT_UNCATEGORIZED(2 <= __base && __base <= 36, "base not in [2, 36]");315316using _Type = __make_32_64_or_128_bit_t<_Tp>;317return std::__to_chars_integral(__first, __last, static_cast<_Type>(__value), __base, is_signed<_Tp>());318}319320#endif // _LIBCPP_STD_VER >= 17321322_LIBCPP_END_NAMESPACE_STD323324_LIBCPP_POP_MACROS325326#endif // _LIBCPP___CHARCONV_TO_CHARS_INTEGRAL_H327328329