LCOV - code coverage report
Current view: top level - src - convert.cc (source / functions) Hit Total Coverage
Test: Code coverage Lines: 11 11 100.0 %
Date: 2025-03-29 09:04:10 Functions: 12 14 85.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 6 14 42.9 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * This file is part of libplacebo.
       3                 :            :  *
       4                 :            :  * libplacebo is free software; you can redistribute it and/or
       5                 :            :  * modify it under the terms of the GNU Lesser General Public
       6                 :            :  * License as published by the Free Software Foundation; either
       7                 :            :  * version 2.1 of the License, or (at your option) any later version.
       8                 :            :  *
       9                 :            :  * libplacebo is distributed in the hope that it will be useful,
      10                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12                 :            :  * GNU Lesser General Public License for more details.
      13                 :            :  *
      14                 :            :  * You should have received a copy of the GNU Lesser General Public
      15                 :            :  * License along with libplacebo.  If not, see <http://www.gnu.org/licenses/>.
      16                 :            :  */
      17                 :            : 
      18                 :            : #include <charconv>
      19                 :            : #include <limits>
      20                 :            : #include <system_error>
      21                 :            : 
      22                 :            : #if __has_include(<fast_float/fast_float.h>)
      23                 :            : # include <fast_float/fast_float.h>
      24                 :            : #endif
      25                 :            : 
      26                 :            : #include "pl_string.h"
      27                 :            : 
      28                 :            : [[maybe_unused]]
      29                 :            : static int ccStrPrintDouble( char *str, int bufsize, int decimals, double value );
      30                 :            : 
      31                 :            : namespace {
      32                 :            : 
      33                 :            : template <typename T>
      34                 :            : struct has_std_to_chars_impl {
      35                 :            :     template <typename CT>
      36                 :            :     static auto _(CT s) -> decltype(std::to_chars(s, s, std::declval<T>()), std::true_type{});
      37                 :            :     static auto _(...) -> std::false_type;
      38                 :            :     static constexpr bool value = decltype(_((char *){}))::value;
      39                 :            : };
      40                 :            : 
      41                 :            : template <typename T>
      42                 :            : constexpr bool has_std_to_chars = has_std_to_chars_impl<T>::value;
      43                 :            : 
      44                 :            : template <typename T, typename... Args>
      45                 :            : static inline int to_chars(char *buf, size_t len, T n, Args ...args)
      46                 :            : {
      47                 :            :     if constexpr (has_std_to_chars<T>) {
      48                 :     138711 :         auto [ptr, ec] = std::to_chars(buf, buf + len, n, args...);
      49   [ +  -  -  -  :     138711 :         return ec == std::errc() ? ptr - buf : 0;
          +  -  +  -  +  
             -  +  -  +  
                      - ]
      50                 :            :     } else {
      51                 :            :         static_assert(std::is_same_v<float, T> || std::is_same_v<double, T>,
      52                 :            :                       "Not implemented!");
      53                 :            :         // FIXME: Fallback for GCC <= 10 currently required for MinGW-w64 on
      54                 :            :         // Ubuntu 22.04. Remove this when Ubuntu 24.04 is released, as it will
      55                 :            :         // provide newer MinGW-w64 GCC and it will be safe to require it.
      56                 :            :         return ccStrPrintDouble(buf, len, std::numeric_limits<T>::max_digits10, n);
      57                 :            :     }
      58                 :            : }
      59                 :            : 
      60                 :            : template <typename T>
      61                 :            : struct has_std_from_chars_impl {
      62                 :            :     template <typename CT>
      63                 :            :     static auto _(CT s) -> decltype(std::from_chars(s, s, std::declval<T&>()), std::true_type{});
      64                 :            :     static auto _(...) -> std::false_type;
      65                 :            :     static constexpr bool value = decltype(_((const char *){}))::value;
      66                 :            : };
      67                 :            : 
      68                 :            : template <typename T>
      69                 :            : constexpr bool has_std_from_chars = has_std_from_chars_impl<T>::value;
      70                 :            : 
      71                 :            : template <typename T, typename... Args>
      72                 :            : static inline bool from_chars(pl_str str, T &n, Args ...args)
      73                 :            : {
      74                 :            :     if constexpr (has_std_from_chars<T>) {
      75                 :        365 :         auto [ptr, ec] = std::from_chars((const char *) str.buf,
      76                 :            :                                          (const char *) str.buf + str.len,
      77                 :            :                                          n, args...);
      78                 :        365 :         return ec == std::errc();
      79                 :            :     } else {
      80                 :            :         constexpr bool is_fp = std::is_same_v<float, T> || std::is_same_v<double, T>;
      81                 :            :         static_assert(is_fp, "Not implemented!");
      82                 :            : #if !__has_include(<fast_float/fast_float.h>)
      83                 :            :         static_assert(!is_fp, "<fast_float/fast_float.h> is required, but not " \
      84                 :            :                               "found. Please run `git submodule update --init`" \
      85                 :            :                               " or provide <fast_float/fast_float.h>");
      86                 :            : #else
      87                 :            :         // FIXME: Fallback for libc++, as it does not implement floating-point
      88                 :            :         // variant of std::from_chars. Remove this when appropriate.
      89                 :            :         auto [ptr, ec] = fast_float::from_chars((const char *) str.buf,
      90                 :            :                                                 (const char *) str.buf + str.len,
      91                 :            :                                                 n, args...);
      92                 :            :         return ec == std::errc();
      93                 :            : #endif
      94                 :            :     }
      95                 :            : }
      96                 :            : 
      97                 :            : }
      98                 :            : 
      99                 :            : #define CHAR_CONVERT(name, type, ...)                           \
     100                 :            :     int pl_str_print_##name(char *buf, size_t len, type n)      \
     101                 :            :     {                                                           \
     102                 :            :         return to_chars(buf, len, n __VA_OPT__(,) __VA_ARGS__); \
     103                 :            :     }                                                           \
     104                 :            :     bool pl_str_parse_##name(pl_str str, type *n)               \
     105                 :            :     {                                                           \
     106                 :            :         return from_chars(str, *n __VA_OPT__(,) __VA_ARGS__);   \
     107                 :            :     }
     108                 :            : 
     109                 :      54117 : CHAR_CONVERT(hex, unsigned short, 16)
     110                 :      77937 : CHAR_CONVERT(int, int)
     111                 :       1940 : CHAR_CONVERT(uint, unsigned int)
     112                 :          4 : CHAR_CONVERT(int64, int64_t)
     113                 :       1292 : CHAR_CONVERT(uint64, uint64_t)
     114                 :        300 : CHAR_CONVERT(float, float)
     115                 :       3486 : CHAR_CONVERT(double, double)
     116                 :            : 
     117                 :            : /* *****************************************************************************
     118                 :            :  *
     119                 :            :  * Copyright (c) 2007-2016 Alexis Naveros.
     120                 :            :  * Modified for use with libplacebo by Niklas Haas
     121                 :            :  * Changes include:
     122                 :            :  *  - Removed a CC_MIN macro dependency by equivalent logic
     123                 :            :  *  - Removed CC_ALWAYSINLINE
     124                 :            :  *  - Fixed (!seq) check to (!seqlength)
     125                 :            :  *  - Added support for scientific notation (e.g. 1.0e10) in ccSeqParseDouble
     126                 :            :  *
     127                 :            :  * Permission is granted to anyone to use this software for any purpose,
     128                 :            :  * including commercial applications, and to alter it and redistribute it
     129                 :            :  * freely, subject to the following restrictions:
     130                 :            :  *
     131                 :            :  * 1. The origin of this software must not be misrepresented; you must not
     132                 :            :  * claim that you wrote the original software. If you use this software
     133                 :            :  * in a product, an acknowledgment in the product documentation would be
     134                 :            :  * appreciated but is not required.
     135                 :            :  * 2. Altered source versions must be plainly marked as such, and must not be
     136                 :            :  * misrepresented as being the original software.
     137                 :            :  * 3. This notice may not be removed or altered from any source distribution.
     138                 :            :  *
     139                 :            :  * -----------------------------------------------------------------------------
     140                 :            :  */
     141                 :            : 
     142                 :            : static int ccStrPrintDouble( char *str, int bufsize, int decimals, double value )
     143                 :            : {
     144                 :            :     int size, offset, index;
     145                 :            :     int32_t frac, accumsub;
     146                 :            :     double muldec;
     147                 :            :     uint32_t u32;
     148                 :            :     uint64_t u64;
     149                 :            : 
     150                 :            :     size = 0;
     151                 :            :     if( value < 0.0 )
     152                 :            :     {
     153                 :            :         size = 1;
     154                 :            :         *str++ = '-';
     155                 :            :         bufsize--;
     156                 :            :         value = -value;
     157                 :            :     }
     158                 :            : 
     159                 :            :     if( value < 4294967296.0 )
     160                 :            :     {
     161                 :            :         u32 = (uint32_t)value;
     162                 :            :         offset = pl_str_print_uint( str, bufsize, u32 );
     163                 :            :         if (!offset)
     164                 :            :             goto error;
     165                 :            :         size += offset;
     166                 :            :         bufsize -= size;
     167                 :            :         value -= (double)u32;
     168                 :            :     }
     169                 :            :     else if( value < 18446744073709551616.0 )
     170                 :            :     {
     171                 :            :         u64 = (uint64_t)value;
     172                 :            :         offset = pl_str_print_uint64( str, bufsize, u64 );
     173                 :            :         if (!offset)
     174                 :            :             goto error;
     175                 :            :         size += offset;
     176                 :            :         bufsize -= size;
     177                 :            :         value -= (double)u64;
     178                 :            :     }
     179                 :            :     else
     180                 :            :         goto error;
     181                 :            : 
     182                 :            :     if (decimals > bufsize - 2)
     183                 :            :         decimals = bufsize - 2;
     184                 :            :     if( decimals <= 0 )
     185                 :            :         return size;
     186                 :            : 
     187                 :            :     muldec = 10.0;
     188                 :            :     accumsub = 0;
     189                 :            :     str += offset;
     190                 :            : 
     191                 :            :     for( index = 0 ; index < decimals ; index++ )
     192                 :            :     {
     193                 :            :         // Skip printing insignificant decimal digits
     194                 :            :         if (value * muldec - accumsub <= std::numeric_limits<double>::epsilon())
     195                 :            :             break;
     196                 :            :         if (index == 0) {
     197                 :            :             size += 1;
     198                 :            :             *str++ = '.';
     199                 :            :         }
     200                 :            :         frac = (int32_t)( value * muldec ) - accumsub;
     201                 :            :         frac = PL_CLAMP(frac, 0, 9); // FIXME: why is this needed?
     202                 :            :         str[index] = '0' + (char)frac;
     203                 :            :         accumsub += frac;
     204                 :            :         accumsub = ( accumsub << 3 ) + ( accumsub << 1 );
     205                 :            :         if( muldec < 10000000 )
     206                 :            :             muldec *= 10.0;
     207                 :            :         else
     208                 :            :         {
     209                 :            :             value *= 10000000.0;
     210                 :            :             value -= (int32_t)value;
     211                 :            :             muldec = 10.0;
     212                 :            :             accumsub = 0;
     213                 :            :         }
     214                 :            :     }
     215                 :            :     // Round up the last decimal digit
     216                 :            :     if ( str[ index - 1 ] < '9' && (int32_t)( value * muldec ) - accumsub >= 5 )
     217                 :            :         str[ index - 1 ]++;
     218                 :            :     str[ index ] = 0;
     219                 :            :     size += index;
     220                 :            :     return size;
     221                 :            : 
     222                 :            : error:
     223                 :            :     if( bufsize < 4 )
     224                 :            :         *str = 0;
     225                 :            :     else
     226                 :            :     {
     227                 :            :         str[0] = 'E';
     228                 :            :         str[1] = 'R';
     229                 :            :         str[2] = 'R';
     230                 :            :         str[3] = 0;
     231                 :            :     }
     232                 :            :     return 0;
     233                 :            : }

Generated by: LCOV version 1.16