/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see .
*/
#include
#include
#include
#if __has_include()
# include
#endif
#include "pl_string.h"
[[maybe_unused]]
static int ccStrPrintDouble( char *str, int bufsize, int decimals, double value );
namespace {
template
struct has_std_to_chars_impl {
template
static auto _(CT s) -> decltype(std::to_chars(s, s, std::declval()), std::true_type{});
static auto _(...) -> std::false_type;
static constexpr bool value = decltype(_((char *){}))::value;
};
template
constexpr bool has_std_to_chars = has_std_to_chars_impl::value;
template
static inline int to_chars(char *buf, size_t len, T n, Args ...args)
{
if constexpr (has_std_to_chars) {
auto [ptr, ec] = std::to_chars(buf, buf + len, n, args...);
return ec == std::errc() ? ptr - buf : 0;
} else {
static_assert(std::is_same_v || std::is_same_v,
"Not implemented!");
// FIXME: Fallback for GCC <= 10 currently required for MinGW-w64 on
// Ubuntu 22.04. Remove this when Ubuntu 24.04 is released, as it will
// provide newer MinGW-w64 GCC and it will be safe to require it.
return ccStrPrintDouble(buf, len, std::numeric_limits::max_digits10, n);
}
}
template
struct has_std_from_chars_impl {
template
static auto _(CT s) -> decltype(std::from_chars(s, s, std::declval()), std::true_type{});
static auto _(...) -> std::false_type;
static constexpr bool value = decltype(_((const char *){}))::value;
};
template
constexpr bool has_std_from_chars = has_std_from_chars_impl::value;
template
static inline bool from_chars(pl_str str, T &n, Args ...args)
{
if constexpr (has_std_from_chars) {
auto [ptr, ec] = std::from_chars((const char *) str.buf,
(const char *) str.buf + str.len,
n, args...);
return ec == std::errc();
} else {
constexpr bool is_fp = std::is_same_v || std::is_same_v;
static_assert(is_fp, "Not implemented!");
#if !__has_include()
static_assert(!is_fp, " is required, but not " \
"found. Please run `git submodule update --init`" \
" or provide ");
#else
// FIXME: Fallback for libc++, as it does not implement floating-point
// variant of std::from_chars. Remove this when appropriate.
auto [ptr, ec] = fast_float::from_chars((const char *) str.buf,
(const char *) str.buf + str.len,
n, args...);
return ec == std::errc();
#endif
}
}
}
#define CHAR_CONVERT(name, type, ...) \
int pl_str_print_##name(char *buf, size_t len, type n) \
{ \
return to_chars(buf, len, n __VA_OPT__(,) __VA_ARGS__); \
} \
bool pl_str_parse_##name(pl_str str, type *n) \
{ \
return from_chars(str, *n __VA_OPT__(,) __VA_ARGS__); \
}
CHAR_CONVERT(hex, unsigned short, 16)
CHAR_CONVERT(int, int)
CHAR_CONVERT(uint, unsigned int)
CHAR_CONVERT(int64, int64_t)
CHAR_CONVERT(uint64, uint64_t)
CHAR_CONVERT(float, float)
CHAR_CONVERT(double, double)
/* *****************************************************************************
*
* Copyright (c) 2007-2016 Alexis Naveros.
* Modified for use with libplacebo by Niklas Haas
* Changes include:
* - Removed a CC_MIN macro dependency by equivalent logic
* - Removed CC_ALWAYSINLINE
* - Fixed (!seq) check to (!seqlength)
* - Added support for scientific notation (e.g. 1.0e10) in ccSeqParseDouble
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* -----------------------------------------------------------------------------
*/
static int ccStrPrintDouble( char *str, int bufsize, int decimals, double value )
{
int size, offset, index;
int32_t frac, accumsub;
double muldec;
uint32_t u32;
uint64_t u64;
size = 0;
if( value < 0.0 )
{
size = 1;
*str++ = '-';
bufsize--;
value = -value;
}
if( value < 4294967296.0 )
{
u32 = (uint32_t)value;
offset = pl_str_print_uint( str, bufsize, u32 );
if (!offset)
goto error;
size += offset;
bufsize -= size;
value -= (double)u32;
}
else if( value < 18446744073709551616.0 )
{
u64 = (uint64_t)value;
offset = pl_str_print_uint64( str, bufsize, u64 );
if (!offset)
goto error;
size += offset;
bufsize -= size;
value -= (double)u64;
}
else
goto error;
if (decimals > bufsize - 2)
decimals = bufsize - 2;
if( decimals <= 0 )
return size;
muldec = 10.0;
accumsub = 0;
str += offset;
for( index = 0 ; index < decimals ; index++ )
{
// Skip printing insignificant decimal digits
if (value * muldec - accumsub <= std::numeric_limits::epsilon())
break;
if (index == 0) {
size += 1;
*str++ = '.';
}
frac = (int32_t)( value * muldec ) - accumsub;
frac = PL_CLAMP(frac, 0, 9); // FIXME: why is this needed?
str[index] = '0' + (char)frac;
accumsub += frac;
accumsub = ( accumsub << 3 ) + ( accumsub << 1 );
if( muldec < 10000000 )
muldec *= 10.0;
else
{
value *= 10000000.0;
value -= (int32_t)value;
muldec = 10.0;
accumsub = 0;
}
}
// Round up the last decimal digit
if ( str[ index - 1 ] < '9' && (int32_t)( value * muldec ) - accumsub >= 5 )
str[ index - 1 ]++;
str[ index ] = 0;
size += index;
return size;
error:
if( bufsize < 4 )
*str = 0;
else
{
str[0] = 'E';
str[1] = 'R';
str[2] = 'R';
str[3] = 0;
}
return 0;
}