[libc-commits] [libc] [libc] Implement strftime (PR #122556)
Nick Desaulniers via libc-commits
libc-commits at lists.llvm.org
Thu Feb 13 11:19:08 PST 2025
================
@@ -0,0 +1,2329 @@
+//===-- Unittests for strftime --------------------------------------------===//
+//
+// 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 "hdr/types/struct_tm.h"
+#include "src/__support/CPP/array.h"
+#include "src/__support/integer_to_string.h"
+#include "src/time/strftime.h"
+#include "src/time/time_constants.h"
+#include "test/UnitTest/Test.h"
+
+// Copied from sprintf_test.cpp.
+// TODO: put this somewhere more reusable, it's handy.
+// Subtract 1 from sizeof(expected_str) to account for the null byte.
+#define EXPECT_STREQ_LEN(actual_written, actual_str, expected_str) \
+ EXPECT_EQ(actual_written, sizeof(expected_str) - 1); \
+ EXPECT_STREQ(actual_str, expected_str);
+
+constexpr int get_adjusted_year(int year) {
+ // tm_year counts years since 1900, so subtract 1900 to get the tm_year for a
+ // given raw year.
+ return year - LIBC_NAMESPACE::time_constants::TIME_YEAR_BASE;
+}
+
+// TODO: Move this somewhere it can be reused. It seems like a useful tool to
+// have.
+// A helper class to generate simple padded numbers. It places the result in its
+// internal buffer, which is cleared on every call.
+class SimplePaddedNum {
+ static constexpr size_t BUFF_LEN = 16;
+ char buff[BUFF_LEN];
+ size_t cur_len; // length of string currently in buff
+
+ void clear_buff() {
+ // TODO: builtin_memset?
+ for (size_t i = 0; i < BUFF_LEN; ++i)
+ buff[i] = '\0';
+ }
+
+public:
+ SimplePaddedNum() = default;
+
+ // PRECONDITIONS: 0 < num < 2**31, min_width < 16
+ // Returns: Pointer to the start of the padded number as a string, stored in
+ // the internal buffer.
+ char *get_padded_num(int num, size_t min_width, char padding_char = '0') {
+ clear_buff();
+
+ // we're not handling the negative sign here, so padding on negative numbers
+ // will be incorrect. For this use case I consider that to be a reasonable
+ // tradeoff for simplicity. This is more meant for the cases where we can
+ // loop through all the possibilities, and for time those are all positive.
+ LIBC_NAMESPACE::IntegerToString<int> raw(num);
+ auto str = raw.view();
+ int leading_zeroes = min_width - raw.size();
+
+ size_t i = 0;
+ for (; static_cast<int>(i) < leading_zeroes; ++i)
+ buff[i] = padding_char;
+ for (size_t str_cur = 0; str_cur < str.size(); ++i, ++str_cur)
+ buff[i] = str[str_cur];
----------------
nickdesaulniers wrote:
https://llvm.org/docs/CodingStandards.html#don-t-evaluate-end-every-time-through-a-loop is about calls to `end`, but I think it applies to calls to `size` for the same reasons. You'll find that pattern VERY COMMON throughout the use of LLVM.
For this simple loop body, the code is likely very similar either way (since the definitions of `size` and `operator[]` are defined in headers), but for loop bodies containing function calls where we can't see the definition from this TU, we can't assume such functions don't already have non-const references that alias to something we might otherwise try to hoist out of a loop (such as a vector's size).
https://github.com/llvm/llvm-project/pull/122556
More information about the libc-commits
mailing list