[libc] Implement strfromd() and strfroml() (#86113)
Follow up to #85438. Implements the functions `strfromd()` and `strfroml()` introduced in C23, and unifies the testing framework for `strfrom*()` functions.
This commit is contained in:
@@ -180,7 +180,9 @@ set(TARGET_LIBC_ENTRYPOINTS
|
||||
libc.src.stdlib.qsort_r
|
||||
libc.src.stdlib.rand
|
||||
libc.src.stdlib.srand
|
||||
libc.src.stdlib.strfromd
|
||||
libc.src.stdlib.strfromf
|
||||
libc.src.stdlib.strfroml
|
||||
libc.src.stdlib.strtod
|
||||
libc.src.stdlib.strtof
|
||||
libc.src.stdlib.strtol
|
||||
|
||||
@@ -962,6 +962,8 @@ def StdC : StandardSpec<"stdc"> {
|
||||
FunctionSpec<"srand", RetValSpec<VoidType>, [ArgSpec<UnsignedIntType>]>,
|
||||
|
||||
FunctionSpec<"strfromf", RetValSpec<IntType>, [ArgSpec<CharRestrictedPtr>, ArgSpec<SizeTType>, ArgSpec<ConstCharRestrictedPtr>, ArgSpec<FloatType>]>,
|
||||
FunctionSpec<"strfromd", RetValSpec<IntType>, [ArgSpec<CharRestrictedPtr>, ArgSpec<SizeTType>, ArgSpec<ConstCharRestrictedPtr>, ArgSpec<DoubleType>]>,
|
||||
FunctionSpec<"strfroml", RetValSpec<IntType>, [ArgSpec<CharRestrictedPtr>, ArgSpec<SizeTType>, ArgSpec<ConstCharRestrictedPtr>, ArgSpec<LongDoubleType>]>,
|
||||
|
||||
FunctionSpec<"strtof", RetValSpec<FloatType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>]>,
|
||||
FunctionSpec<"strtod", RetValSpec<DoubleType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>]>,
|
||||
|
||||
@@ -62,6 +62,26 @@ add_entrypoint_object(
|
||||
.str_from_util
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
strfromd
|
||||
SRCS
|
||||
strfromd.cpp
|
||||
HDRS
|
||||
strfromd.h
|
||||
DEPENDS
|
||||
.str_from_util
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
strfroml
|
||||
SRCS
|
||||
strfroml.cpp
|
||||
HDRS
|
||||
strfroml.h
|
||||
DEPENDS
|
||||
.str_from_util
|
||||
)
|
||||
|
||||
add_header_library(
|
||||
str_from_util
|
||||
HDRS
|
||||
|
||||
42
libc/src/stdlib/strfromd.cpp
Normal file
42
libc/src/stdlib/strfromd.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
//===-- Implementation of strfromd ------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "src/stdlib/strfromd.h"
|
||||
#include "src/stdlib/str_from_util.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
namespace LIBC_NAMESPACE {
|
||||
|
||||
LLVM_LIBC_FUNCTION(int, strfromd,
|
||||
(char *__restrict s, size_t n, const char *__restrict format,
|
||||
double fp)) {
|
||||
LIBC_ASSERT(s != nullptr);
|
||||
|
||||
printf_core::FormatSection section =
|
||||
internal::parse_format_string(format, fp);
|
||||
printf_core::WriteBuffer wb(s, (n > 0 ? n - 1 : 0));
|
||||
printf_core::Writer writer(&wb);
|
||||
|
||||
int result = 0;
|
||||
if (section.has_conv)
|
||||
result = internal::strfromfloat_convert<double>(&writer, section);
|
||||
else
|
||||
result = writer.write(section.raw_string);
|
||||
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
if (n > 0)
|
||||
wb.buff[wb.buff_cur] = '\0';
|
||||
|
||||
return writer.get_chars_written();
|
||||
}
|
||||
|
||||
} // namespace LIBC_NAMESPACE
|
||||
21
libc/src/stdlib/strfromd.h
Normal file
21
libc/src/stdlib/strfromd.h
Normal file
@@ -0,0 +1,21 @@
|
||||
//===-- Implementation header for strfromd ------------------------*- C++--===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIBC_SRC_STDLIB_STRFROMD_H
|
||||
#define LLVM_LIBC_SRC_STDLIB_STRFROMD_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace LIBC_NAMESPACE {
|
||||
|
||||
int strfromd(char *__restrict s, size_t n, const char *__restrict format,
|
||||
double fp);
|
||||
|
||||
} // namespace LIBC_NAMESPACE
|
||||
|
||||
#endif // LLVM_LIBC_SRC_STDLIB_STRFROMD_H
|
||||
@@ -18,4 +18,4 @@ int strfromf(char *__restrict s, size_t n, const char *__restrict format,
|
||||
|
||||
} // namespace LIBC_NAMESPACE
|
||||
|
||||
#endif // LLVM_LIBC_SRC_STDLIB_STRTOF_H
|
||||
#endif // LLVM_LIBC_SRC_STDLIB_STRFROMF_H
|
||||
|
||||
47
libc/src/stdlib/strfroml.cpp
Normal file
47
libc/src/stdlib/strfroml.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
//===-- Implementation of strfroml ------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "src/stdlib/strfroml.h"
|
||||
#include "src/stdlib/str_from_util.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
namespace LIBC_NAMESPACE {
|
||||
|
||||
LLVM_LIBC_FUNCTION(int, strfroml,
|
||||
(char *__restrict s, size_t n, const char *__restrict format,
|
||||
long double fp)) {
|
||||
LIBC_ASSERT(s != nullptr);
|
||||
|
||||
printf_core::FormatSection section =
|
||||
internal::parse_format_string(format, fp);
|
||||
|
||||
// To ensure that the conversion function actually uses long double,
|
||||
// the length modifier has to be set to LenghtModifier::L
|
||||
section.length_modifier = printf_core::LengthModifier::L;
|
||||
|
||||
printf_core::WriteBuffer wb(s, (n > 0 ? n - 1 : 0));
|
||||
printf_core::Writer writer(&wb);
|
||||
|
||||
int result = 0;
|
||||
if (section.has_conv)
|
||||
result = internal::strfromfloat_convert<long double>(&writer, section);
|
||||
else
|
||||
result = writer.write(section.raw_string);
|
||||
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
if (n > 0)
|
||||
wb.buff[wb.buff_cur] = '\0';
|
||||
|
||||
return writer.get_chars_written();
|
||||
}
|
||||
|
||||
} // namespace LIBC_NAMESPACE
|
||||
21
libc/src/stdlib/strfroml.h
Normal file
21
libc/src/stdlib/strfroml.h
Normal file
@@ -0,0 +1,21 @@
|
||||
//===-- Implementation header for strfroml ------------------------*- C++--===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIBC_SRC_STDLIB_STRFROML_H
|
||||
#define LLVM_LIBC_SRC_STDLIB_STRFROML_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace LIBC_NAMESPACE {
|
||||
|
||||
int strfroml(char *__restrict s, size_t n, const char *__restrict format,
|
||||
long double fp);
|
||||
|
||||
} // namespace LIBC_NAMESPACE
|
||||
|
||||
#endif // LLVM_LIBC_SRC_STDLIB_STRFROML_H
|
||||
@@ -168,6 +168,14 @@ add_libc_test(
|
||||
.strtol_test_support
|
||||
)
|
||||
|
||||
add_header_library(
|
||||
strfrom_test_support
|
||||
HDRS
|
||||
StrfromTest.h
|
||||
DEPENDS
|
||||
libc.src.__support.CPP.type_traits
|
||||
)
|
||||
|
||||
add_libc_test(
|
||||
strfromf_test
|
||||
SUITE
|
||||
@@ -175,9 +183,32 @@ add_libc_test(
|
||||
SRCS
|
||||
strfromf_test.cpp
|
||||
DEPENDS
|
||||
.strfrom_test_support
|
||||
libc.src.stdlib.strfromf
|
||||
)
|
||||
|
||||
add_libc_test(
|
||||
strfromd_test
|
||||
SUITE
|
||||
libc-stdlib-tests
|
||||
SRCS
|
||||
strfromd_test.cpp
|
||||
DEPENDS
|
||||
.strfrom_test_support
|
||||
libc.src.stdlib.strfromd
|
||||
)
|
||||
|
||||
add_libc_test(
|
||||
strfroml_test
|
||||
SUITE
|
||||
libc-stdlib-tests
|
||||
SRCS
|
||||
strfroml_test.cpp
|
||||
DEPENDS
|
||||
.strfrom_test_support
|
||||
libc.src.stdlib.strfroml
|
||||
)
|
||||
|
||||
add_libc_test(
|
||||
abs_test
|
||||
SUITE
|
||||
|
||||
435
libc/test/src/stdlib/StrfromTest.h
Normal file
435
libc/test/src/stdlib/StrfromTest.h
Normal file
@@ -0,0 +1,435 @@
|
||||
//===-- A template class for testing strfrom functions ----------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "src/__support/CPP/type_traits.h"
|
||||
#include "test/UnitTest/Test.h"
|
||||
|
||||
#define ASSERT_STREQ_LEN(actual_written, actual_str, expected_str) \
|
||||
EXPECT_EQ(actual_written, static_cast<int>(sizeof(expected_str) - 1)); \
|
||||
EXPECT_STREQ(actual_str, expected_str);
|
||||
|
||||
template <typename InputT>
|
||||
class StrfromTest : public LIBC_NAMESPACE::testing::Test {
|
||||
|
||||
static const bool is_single_prec =
|
||||
LIBC_NAMESPACE::cpp::is_same<InputT, float>::value;
|
||||
static const bool is_double_prec =
|
||||
LIBC_NAMESPACE::cpp::is_same<InputT, double>::value;
|
||||
|
||||
using FunctionT = int (*)(char *, size_t, const char *, InputT fp);
|
||||
|
||||
public:
|
||||
void floatDecimalFormat(FunctionT func) {
|
||||
if (is_single_prec)
|
||||
floatDecimalSinglePrec(func);
|
||||
else if (is_double_prec)
|
||||
floatDecimalDoublePrec(func);
|
||||
else
|
||||
floatDecimalLongDoublePrec(func);
|
||||
}
|
||||
|
||||
void floatHexExpFormat(FunctionT func) {
|
||||
if (is_single_prec)
|
||||
floatHexExpSinglePrec(func);
|
||||
else if (is_double_prec)
|
||||
floatHexExpDoublePrec(func);
|
||||
else
|
||||
floatHexExpLongDoublePrec(func);
|
||||
}
|
||||
|
||||
void floatDecimalExpFormat(FunctionT func) {
|
||||
if (is_single_prec)
|
||||
floatDecimalExpSinglePrec(func);
|
||||
else if (is_double_prec)
|
||||
floatDecimalExpDoublePrec(func);
|
||||
else
|
||||
floatDecimalExpLongDoublePrec(func);
|
||||
}
|
||||
|
||||
void floatDecimalAutoFormat(FunctionT func) {
|
||||
if (is_single_prec)
|
||||
floatDecimalAutoSinglePrec(func);
|
||||
else if (is_double_prec)
|
||||
floatDecimalAutoDoublePrec(func);
|
||||
else
|
||||
floatDecimalAutoLongDoublePrec(func);
|
||||
}
|
||||
|
||||
void improperFormatString(FunctionT func) {
|
||||
char buff[100];
|
||||
int written;
|
||||
const bool is_long_double = !is_single_prec && !is_double_prec;
|
||||
|
||||
written = func(buff, 37, "A simple string with no conversions.", 1.0);
|
||||
ASSERT_STREQ_LEN(written, buff, "A simple string with no conversions.");
|
||||
|
||||
written =
|
||||
func(buff, 37,
|
||||
"%A simple string with one conversion, should overwrite.", 1.0);
|
||||
ASSERT_STREQ_LEN(written, buff, is_long_double ? "0X8P-3" : "0X1P+0");
|
||||
|
||||
written = func(buff, 74,
|
||||
"A simple string with one conversion in %A "
|
||||
"between, writes string as it is",
|
||||
1.0);
|
||||
ASSERT_STREQ_LEN(written, buff,
|
||||
"A simple string with one conversion in %A between, "
|
||||
"writes string as it is");
|
||||
|
||||
written = func(buff, 36, "A simple string with one conversion", 1.0);
|
||||
ASSERT_STREQ_LEN(written, buff, "A simple string with one conversion");
|
||||
|
||||
written = func(buff, 20, "%1f", 1234567890.0);
|
||||
ASSERT_STREQ_LEN(written, buff, "%1f");
|
||||
}
|
||||
|
||||
void insufficentBufsize(FunctionT func) {
|
||||
char buff[20];
|
||||
int written;
|
||||
|
||||
written = func(buff, 5, "%f", 1234567890.0);
|
||||
EXPECT_EQ(written, 17);
|
||||
ASSERT_STREQ(buff, "1234");
|
||||
|
||||
written = func(buff, 5, "%.5f", 1.05);
|
||||
EXPECT_EQ(written, 7);
|
||||
ASSERT_STREQ(buff, "1.05");
|
||||
|
||||
written = func(buff, 0, "%g", 1.0);
|
||||
EXPECT_EQ(written, 1);
|
||||
ASSERT_STREQ(buff, "1.05"); // Make sure that buff has not changed
|
||||
}
|
||||
|
||||
void floatDecimalSinglePrec(FunctionT func) {
|
||||
char buff[70];
|
||||
int written;
|
||||
|
||||
written = func(buff, 16, "%f", 1.0);
|
||||
ASSERT_STREQ_LEN(written, buff, "1.000000");
|
||||
|
||||
written = func(buff, 20, "%f", 1234567890.0);
|
||||
ASSERT_STREQ_LEN(written, buff, "1234567936.000000");
|
||||
|
||||
written = func(buff, 67, "%.3f", 1.0);
|
||||
ASSERT_STREQ_LEN(written, buff, "1.000");
|
||||
}
|
||||
|
||||
void floatDecimalDoublePrec(FunctionT func) {
|
||||
char buff[500];
|
||||
int written;
|
||||
|
||||
written = func(buff, 99, "%f", 1.0);
|
||||
ASSERT_STREQ_LEN(written, buff, "1.000000");
|
||||
|
||||
written = func(buff, 99, "%F", -1.0);
|
||||
ASSERT_STREQ_LEN(written, buff, "-1.000000");
|
||||
|
||||
written = func(buff, 99, "%f", -1.234567);
|
||||
ASSERT_STREQ_LEN(written, buff, "-1.234567");
|
||||
|
||||
written = func(buff, 99, "%f", 0.0);
|
||||
ASSERT_STREQ_LEN(written, buff, "0.000000");
|
||||
|
||||
written = func(buff, 99, "%f", 1.5);
|
||||
ASSERT_STREQ_LEN(written, buff, "1.500000");
|
||||
|
||||
written = func(buff, 499, "%f", 1e300);
|
||||
ASSERT_STREQ_LEN(written, buff,
|
||||
"100000000000000005250476025520442024870446858110815915491"
|
||||
"585411551180245"
|
||||
"798890819578637137508044786404370444383288387817694252323"
|
||||
"536043057564479"
|
||||
"218478670698284838720092657580373783023379478809005936895"
|
||||
"323497079994508"
|
||||
"111903896764088007465274278014249457925878882005684283811"
|
||||
"566947219638686"
|
||||
"5459400540160.000000");
|
||||
|
||||
written = func(buff, 99, "%f", 0.1);
|
||||
ASSERT_STREQ_LEN(written, buff, "0.100000");
|
||||
|
||||
written = func(buff, 99, "%f", 1234567890123456789.0);
|
||||
ASSERT_STREQ_LEN(written, buff, "1234567890123456768.000000");
|
||||
|
||||
written = func(buff, 99, "%f", 9999999999999.99);
|
||||
ASSERT_STREQ_LEN(written, buff, "9999999999999.990234");
|
||||
|
||||
written = func(buff, 99, "%f", 0.1);
|
||||
ASSERT_STREQ_LEN(written, buff, "0.100000");
|
||||
|
||||
written = func(buff, 99, "%f", 1234567890123456789.0);
|
||||
ASSERT_STREQ_LEN(written, buff, "1234567890123456768.000000");
|
||||
|
||||
written = func(buff, 99, "%f", 9999999999999.99);
|
||||
ASSERT_STREQ_LEN(written, buff, "9999999999999.990234");
|
||||
|
||||
// Precision Tests
|
||||
written = func(buff, 100, "%.2f", 9999999999999.99);
|
||||
ASSERT_STREQ_LEN(written, buff, "9999999999999.99");
|
||||
|
||||
written = func(buff, 100, "%.1f", 9999999999999.99);
|
||||
ASSERT_STREQ_LEN(written, buff, "10000000000000.0");
|
||||
|
||||
written = func(buff, 100, "%.5f", 1.25);
|
||||
ASSERT_STREQ_LEN(written, buff, "1.25000");
|
||||
|
||||
written = func(buff, 100, "%.0f", 1.25);
|
||||
ASSERT_STREQ_LEN(written, buff, "1");
|
||||
|
||||
written = func(buff, 100, "%.20f", 1.234e-10);
|
||||
ASSERT_STREQ_LEN(written, buff, "0.00000000012340000000");
|
||||
}
|
||||
|
||||
void floatDecimalLongDoublePrec(FunctionT func) {
|
||||
char buff[45];
|
||||
int written;
|
||||
|
||||
written = func(buff, 40, "%f", 1.0L);
|
||||
ASSERT_STREQ_LEN(written, buff, "1.000000");
|
||||
|
||||
written = func(buff, 10, "%.f", -2.5L);
|
||||
ASSERT_STREQ_LEN(written, buff, "-2");
|
||||
}
|
||||
|
||||
void floatHexExpSinglePrec(FunctionT func) {
|
||||
char buff[25];
|
||||
int written;
|
||||
|
||||
written = func(buff, 0, "%a", 1234567890.0);
|
||||
EXPECT_EQ(written, 14);
|
||||
|
||||
written = func(buff, 20, "%a", 1234567890.0);
|
||||
EXPECT_EQ(written, 14);
|
||||
ASSERT_STREQ(buff, "0x1.26580cp+30");
|
||||
|
||||
written = func(buff, 20, "%A", 1234567890.0);
|
||||
EXPECT_EQ(written, 14);
|
||||
ASSERT_STREQ(buff, "0X1.26580CP+30");
|
||||
}
|
||||
|
||||
void floatHexExpDoublePrec(FunctionT func) {
|
||||
char buff[60];
|
||||
int written;
|
||||
|
||||
written = func(buff, 10, "%a", 1.0);
|
||||
ASSERT_STREQ_LEN(written, buff, "0x1p+0");
|
||||
|
||||
written = func(buff, 10, "%A", -1.0);
|
||||
ASSERT_STREQ_LEN(written, buff, "-0X1P+0");
|
||||
|
||||
written = func(buff, 30, "%a", -0x1.abcdef12345p0);
|
||||
ASSERT_STREQ_LEN(written, buff, "-0x1.abcdef12345p+0");
|
||||
|
||||
written = func(buff, 50, "%A", 0x1.abcdef12345p0);
|
||||
ASSERT_STREQ_LEN(written, buff, "0X1.ABCDEF12345P+0");
|
||||
|
||||
written = func(buff, 10, "%a", 0.0);
|
||||
ASSERT_STREQ_LEN(written, buff, "0x0p+0");
|
||||
|
||||
written = func(buff, 40, "%a", 1.0e100);
|
||||
ASSERT_STREQ_LEN(written, buff, "0x1.249ad2594c37dp+332");
|
||||
|
||||
written = func(buff, 30, "%a", 0.1);
|
||||
ASSERT_STREQ_LEN(written, buff, "0x1.999999999999ap-4");
|
||||
}
|
||||
|
||||
void floatHexExpLongDoublePrec(FunctionT func) {
|
||||
char buff[55];
|
||||
int written;
|
||||
|
||||
written = func(buff, 50, "%a", 0.1L);
|
||||
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
|
||||
ASSERT_STREQ_LEN(written, buff, "0xc.ccccccccccccccdp-7");
|
||||
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
|
||||
ASSERT_STREQ_LEN(written, buff, "0x1.999999999999ap-4");
|
||||
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
|
||||
ASSERT_STREQ_LEN(written, buff, "0x1.999999999999999999999999999ap-4");
|
||||
#endif
|
||||
|
||||
written = func(buff, 20, "%.1a", 0.1L);
|
||||
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
|
||||
ASSERT_STREQ_LEN(written, buff, "0xc.dp-7");
|
||||
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
|
||||
ASSERT_STREQ_LEN(written, buff, "0x1.ap-4");
|
||||
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
|
||||
ASSERT_STREQ_LEN(written, buff, "0x1.ap-4");
|
||||
#endif
|
||||
|
||||
written = func(buff, 50, "%a", 1.0e1000L);
|
||||
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
|
||||
ASSERT_STREQ_LEN(written, buff, "0xf.38db1f9dd3dac05p+3318");
|
||||
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
|
||||
ASSERT_STREQ_LEN(written, buff, "inf");
|
||||
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
|
||||
ASSERT_STREQ_LEN(written, buff, "0x1.e71b63f3ba7b580af1a52d2a7379p+3321");
|
||||
#endif
|
||||
|
||||
written = func(buff, 50, "%a", 1.0e-1000L);
|
||||
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
|
||||
ASSERT_STREQ_LEN(written, buff, "0x8.68a9188a89e1467p-3325");
|
||||
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
|
||||
ASSERT_STREQ_LEN(written, buff, "0x0p+0");
|
||||
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
|
||||
ASSERT_STREQ_LEN(written, buff, "0x1.0d152311513c28ce202627c06ec2p-3322");
|
||||
#endif
|
||||
|
||||
written = func(buff, 50, "%.1a", 0xf.fffffffffffffffp16380L);
|
||||
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
|
||||
ASSERT_STREQ_LEN(written, buff, "0x1.0p+16384");
|
||||
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
|
||||
ASSERT_STREQ_LEN(written, buff, "inf");
|
||||
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
|
||||
ASSERT_STREQ_LEN(written, buff, "0x2.0p+16383");
|
||||
#endif
|
||||
}
|
||||
|
||||
void floatDecimalExpSinglePrec(FunctionT func) {
|
||||
char buff[25];
|
||||
int written;
|
||||
|
||||
written = func(buff, 20, "%.9e", 1234567890.0);
|
||||
ASSERT_STREQ_LEN(written, buff, "1.234567936e+09");
|
||||
|
||||
written = func(buff, 20, "%.9E", 1234567890.0);
|
||||
ASSERT_STREQ_LEN(written, buff, "1.234567936E+09");
|
||||
}
|
||||
|
||||
void floatDecimalExpDoublePrec(FunctionT func) {
|
||||
char buff[101];
|
||||
int written;
|
||||
|
||||
written = func(buff, 100, "%e", 1.0);
|
||||
ASSERT_STREQ_LEN(written, buff, "1.000000e+00");
|
||||
|
||||
written = func(buff, 100, "%E", -1.0);
|
||||
ASSERT_STREQ_LEN(written, buff, "-1.000000E+00");
|
||||
|
||||
written = func(buff, 100, "%e", -1.234567);
|
||||
ASSERT_STREQ_LEN(written, buff, "-1.234567e+00");
|
||||
|
||||
written = func(buff, 100, "%e", 0.0);
|
||||
ASSERT_STREQ_LEN(written, buff, "0.000000e+00");
|
||||
|
||||
written = func(buff, 100, "%e", 1.5);
|
||||
ASSERT_STREQ_LEN(written, buff, "1.500000e+00");
|
||||
|
||||
written = func(buff, 100, "%e", 1e300);
|
||||
ASSERT_STREQ_LEN(written, buff, "1.000000e+300");
|
||||
|
||||
written = func(buff, 100, "%e", 1234567890123456789.0);
|
||||
ASSERT_STREQ_LEN(written, buff, "1.234568e+18");
|
||||
|
||||
// Precision Tests
|
||||
written = func(buff, 100, "%.1e", 1.0);
|
||||
ASSERT_STREQ_LEN(written, buff, "1.0e+00");
|
||||
|
||||
written = func(buff, 100, "%.1e", 1.99);
|
||||
ASSERT_STREQ_LEN(written, buff, "2.0e+00");
|
||||
|
||||
written = func(buff, 100, "%.1e", 9.99);
|
||||
ASSERT_STREQ_LEN(written, buff, "1.0e+01");
|
||||
}
|
||||
|
||||
void floatDecimalExpLongDoublePrec(FunctionT func) {
|
||||
char buff[100];
|
||||
int written;
|
||||
|
||||
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
|
||||
written = func(buff, 90, "%.9e", 1000000000500000000.1L);
|
||||
ASSERT_STREQ_LEN(written, buff, "1.000000001e+18");
|
||||
|
||||
written = func(buff, 90, "%.9e", 1000000000500000000.0L);
|
||||
ASSERT_STREQ_LEN(written, buff, "1.000000000e+18");
|
||||
|
||||
written = func(buff, 90, "%e", 0xf.fffffffffffffffp+16380L);
|
||||
ASSERT_STREQ_LEN(written, buff, "1.189731e+4932");
|
||||
#endif // LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80
|
||||
}
|
||||
|
||||
void floatDecimalAutoSinglePrec(FunctionT func) {
|
||||
char buff[25];
|
||||
int written;
|
||||
|
||||
written = func(buff, 20, "%.9g", 1234567890.0);
|
||||
ASSERT_STREQ_LEN(written, buff, "1.23456794e+09");
|
||||
|
||||
written = func(buff, 20, "%.9G", 1234567890.0);
|
||||
ASSERT_STREQ_LEN(written, buff, "1.23456794E+09");
|
||||
}
|
||||
|
||||
void floatDecimalAutoDoublePrec(FunctionT func) {
|
||||
char buff[120];
|
||||
int written;
|
||||
|
||||
written = func(buff, 100, "%g", 1234567890123456789.0);
|
||||
ASSERT_STREQ_LEN(written, buff, "1.23457e+18");
|
||||
|
||||
written = func(buff, 100, "%g", 9999990000000.00);
|
||||
ASSERT_STREQ_LEN(written, buff, "9.99999e+12");
|
||||
|
||||
written = func(buff, 100, "%g", 9999999000000.00);
|
||||
ASSERT_STREQ_LEN(written, buff, "1e+13");
|
||||
|
||||
written = func(buff, 100, "%g", 0xa.aaaaaaaaaaaaaabp-7);
|
||||
ASSERT_STREQ_LEN(written, buff, "0.0833333");
|
||||
|
||||
written = func(buff, 100, "%g", 0.00001);
|
||||
ASSERT_STREQ_LEN(written, buff, "1e-05");
|
||||
|
||||
// Precision Tests
|
||||
written = func(buff, 100, "%.0g", 0.0);
|
||||
ASSERT_STREQ_LEN(written, buff, "0");
|
||||
|
||||
written = func(buff, 100, "%.2g", 0.1);
|
||||
ASSERT_STREQ_LEN(written, buff, "0.1");
|
||||
|
||||
written = func(buff, 100, "%.2g", 1.09);
|
||||
ASSERT_STREQ_LEN(written, buff, "1.1");
|
||||
|
||||
written = func(buff, 100, "%.15g", 22.25);
|
||||
ASSERT_STREQ_LEN(written, buff, "22.25");
|
||||
|
||||
written = func(buff, 100, "%.20g", 1.234e-10);
|
||||
ASSERT_STREQ_LEN(written, buff, "1.2340000000000000814e-10");
|
||||
}
|
||||
|
||||
void floatDecimalAutoLongDoublePrec(FunctionT func) {
|
||||
char buff[100];
|
||||
int written;
|
||||
|
||||
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
|
||||
written = func(buff, 99, "%g", 0xf.fffffffffffffffp+16380L);
|
||||
ASSERT_STREQ_LEN(written, buff, "1.18973e+4932");
|
||||
|
||||
written = func(buff, 99, "%g", 0xa.aaaaaaaaaaaaaabp-7L);
|
||||
ASSERT_STREQ_LEN(written, buff, "0.0833333");
|
||||
|
||||
written = func(buff, 99, "%g", 9.99999999999e-100L);
|
||||
ASSERT_STREQ_LEN(written, buff, "1e-99");
|
||||
#endif // LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80
|
||||
}
|
||||
};
|
||||
|
||||
#define STRFROM_TEST(InputType, name, func) \
|
||||
using LlvmLibc##name##Test = StrfromTest<InputType>; \
|
||||
TEST_F(LlvmLibc##name##Test, FloatDecimalFormat) { \
|
||||
floatDecimalFormat(func); \
|
||||
} \
|
||||
TEST_F(LlvmLibc##name##Test, FloatHexExpFormat) { floatHexExpFormat(func); } \
|
||||
TEST_F(LlvmLibc##name##Test, FloatDecimalAutoFormat) { \
|
||||
floatDecimalAutoFormat(func); \
|
||||
} \
|
||||
TEST_F(LlvmLibc##name##Test, FloatDecimalExpFormat) { \
|
||||
floatDecimalExpFormat(func); \
|
||||
} \
|
||||
TEST_F(LlvmLibc##name##Test, ImproperFormatString) { \
|
||||
improperFormatString(func); \
|
||||
} \
|
||||
TEST_F(LlvmLibc##name##Test, InsufficientBufferSize) { \
|
||||
insufficentBufsize(func); \
|
||||
}
|
||||
13
libc/test/src/stdlib/strfromd_test.cpp
Normal file
13
libc/test/src/stdlib/strfromd_test.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
//===-- Unittests for strfromd --------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "StrfromTest.h"
|
||||
#include "src/stdlib/strfromd.h"
|
||||
#include "test/UnitTest/Test.h"
|
||||
|
||||
STRFROM_TEST(double, Strfromd, LIBC_NAMESPACE::strfromd)
|
||||
@@ -6,102 +6,8 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "StrfromTest.h"
|
||||
#include "src/stdlib/strfromf.h"
|
||||
#include "test/UnitTest/Test.h"
|
||||
|
||||
TEST(LlvmLibcStrfromfTest, DecimalFloatFormat) {
|
||||
char buff[100];
|
||||
int written;
|
||||
|
||||
written = LIBC_NAMESPACE::strfromf(buff, 16, "%f", 1.0);
|
||||
EXPECT_EQ(written, 8);
|
||||
ASSERT_STREQ(buff, "1.000000");
|
||||
|
||||
written = LIBC_NAMESPACE::strfromf(buff, 20, "%f", 1234567890.0);
|
||||
EXPECT_EQ(written, 17);
|
||||
ASSERT_STREQ(buff, "1234567936.000000");
|
||||
|
||||
written = LIBC_NAMESPACE::strfromf(buff, 5, "%f", 1234567890.0);
|
||||
EXPECT_EQ(written, 17);
|
||||
ASSERT_STREQ(buff, "1234");
|
||||
|
||||
written = LIBC_NAMESPACE::strfromf(buff, 67, "%.3f", 1.0);
|
||||
EXPECT_EQ(written, 5);
|
||||
ASSERT_STREQ(buff, "1.000");
|
||||
|
||||
written = LIBC_NAMESPACE::strfromf(buff, 20, "%1f", 1234567890.0);
|
||||
EXPECT_EQ(written, 3);
|
||||
ASSERT_STREQ(buff, "%1f");
|
||||
}
|
||||
|
||||
TEST(LlvmLibcStrfromfTest, HexExpFloatFormat) {
|
||||
char buff[100];
|
||||
int written;
|
||||
|
||||
written = LIBC_NAMESPACE::strfromf(buff, 0, "%a", 1234567890.0);
|
||||
EXPECT_EQ(written, 14);
|
||||
|
||||
written = LIBC_NAMESPACE::strfromf(buff, 20, "%a", 1234567890.0);
|
||||
EXPECT_EQ(written, 14);
|
||||
ASSERT_STREQ(buff, "0x1.26580cp+30");
|
||||
|
||||
written = LIBC_NAMESPACE::strfromf(buff, 20, "%A", 1234567890.0);
|
||||
EXPECT_EQ(written, 14);
|
||||
ASSERT_STREQ(buff, "0X1.26580CP+30");
|
||||
}
|
||||
|
||||
TEST(LlvmLibcStrfromfTest, DecimalExpFloatFormat) {
|
||||
char buff[100];
|
||||
int written;
|
||||
written = LIBC_NAMESPACE::strfromf(buff, 20, "%.9e", 1234567890.0);
|
||||
EXPECT_EQ(written, 15);
|
||||
ASSERT_STREQ(buff, "1.234567936e+09");
|
||||
|
||||
written = LIBC_NAMESPACE::strfromf(buff, 20, "%.9E", 1234567890.0);
|
||||
EXPECT_EQ(written, 15);
|
||||
ASSERT_STREQ(buff, "1.234567936E+09");
|
||||
}
|
||||
|
||||
TEST(LlvmLibcStrfromfTest, AutoDecimalFloatFormat) {
|
||||
char buff[100];
|
||||
int written;
|
||||
|
||||
written = LIBC_NAMESPACE::strfromf(buff, 20, "%.9g", 1234567890.0);
|
||||
EXPECT_EQ(written, 14);
|
||||
ASSERT_STREQ(buff, "1.23456794e+09");
|
||||
|
||||
written = LIBC_NAMESPACE::strfromf(buff, 20, "%.9G", 1234567890.0);
|
||||
EXPECT_EQ(written, 14);
|
||||
ASSERT_STREQ(buff, "1.23456794E+09");
|
||||
|
||||
written = LIBC_NAMESPACE::strfromf(buff, 0, "%G", 1.0);
|
||||
EXPECT_EQ(written, 1);
|
||||
}
|
||||
|
||||
TEST(LlvmLibcStrfromfTest, ImproperFormatString) {
|
||||
|
||||
char buff[100];
|
||||
int retval;
|
||||
retval = LIBC_NAMESPACE::strfromf(
|
||||
buff, 37, "A simple string with no conversions.", 1.0);
|
||||
EXPECT_EQ(retval, 36);
|
||||
ASSERT_STREQ(buff, "A simple string with no conversions.");
|
||||
|
||||
retval = LIBC_NAMESPACE::strfromf(
|
||||
buff, 37, "%A simple string with one conversion, should overwrite.", 1.0);
|
||||
EXPECT_EQ(retval, 6);
|
||||
ASSERT_STREQ(buff, "0X1P+0");
|
||||
|
||||
retval = LIBC_NAMESPACE::strfromf(buff, 74,
|
||||
"A simple string with one conversion in %A "
|
||||
"between, writes string as it is",
|
||||
1.0);
|
||||
EXPECT_EQ(retval, 73);
|
||||
ASSERT_STREQ(buff, "A simple string with one conversion in %A between, "
|
||||
"writes string as it is");
|
||||
|
||||
retval = LIBC_NAMESPACE::strfromf(buff, 36,
|
||||
"A simple string with one conversion", 1.0);
|
||||
EXPECT_EQ(retval, 35);
|
||||
ASSERT_STREQ(buff, "A simple string with one conversion");
|
||||
}
|
||||
STRFROM_TEST(float, StrFromf, LIBC_NAMESPACE::strfromf)
|
||||
|
||||
13
libc/test/src/stdlib/strfroml_test.cpp
Normal file
13
libc/test/src/stdlib/strfroml_test.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
//===-- Unittests for strfroml --------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "StrfromTest.h"
|
||||
#include "src/stdlib/strfroml.h"
|
||||
#include "test/UnitTest/Test.h"
|
||||
|
||||
STRFROM_TEST(long double, Strfroml, LIBC_NAMESPACE::strfroml)
|
||||
Reference in New Issue
Block a user