Skip to content

Commit

Permalink
[libc] Implement strfromd() and strfroml() (#86113)
Browse files Browse the repository at this point in the history
Follow up to #85438.

Implements the functions `strfromd()` and `strfroml()` introduced in
C23, and unifies the testing framework for `strfrom*()` functions.
  • Loading branch information
vinayakdsci committed Mar 22, 2024
1 parent 721f149 commit 83e9697
Show file tree
Hide file tree
Showing 13 changed files with 650 additions and 97 deletions.
2 changes: 2 additions & 0 deletions libc/config/linux/x86_64/entrypoints.txt
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions libc/spec/stdc.td
Expand Up @@ -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>]>,
Expand Down
20 changes: 20 additions & 0 deletions libc/src/stdlib/CMakeLists.txt
Expand Up @@ -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
Expand Down
42 changes: 42 additions & 0 deletions libc/src/stdlib/strfromd.cpp
@@ -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 changes: 21 additions & 0 deletions libc/src/stdlib/strfromd.h
@@ -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
2 changes: 1 addition & 1 deletion libc/src/stdlib/strfromf.h
Expand Up @@ -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 changes: 47 additions & 0 deletions libc/src/stdlib/strfroml.cpp
@@ -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 changes: 21 additions & 0 deletions libc/src/stdlib/strfroml.h
@@ -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
31 changes: 31 additions & 0 deletions libc/test/src/stdlib/CMakeLists.txt
Expand Up @@ -168,16 +168,47 @@ 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
libc-stdlib-tests
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
Expand Down

0 comments on commit 83e9697

Please sign in to comment.