[libc-commits] [libc] e92c19a - [libc] Add cpp::swap and cpp::clamp utilities (#221236)
via libc-commits
libc-commits at lists.llvm.org
Mon Sep 7 07:54:27 PDT 2026
Author: Jeff Bailey
Date: 2026-09-07T15:54:22+01:00
New Revision: e92c19abae25beb03234bfbf6cfa1a431c6d380a
URL: https://github.com/llvm/llvm-project/commit/e92c19abae25beb03234bfbf6cfa1a431c6d380a
DIFF: https://github.com/llvm/llvm-project/commit/e92c19abae25beb03234bfbf6cfa1a431c6d380a.diff
LOG: [libc] Add cpp::swap and cpp::clamp utilities (#221236)
Added cpp::swap to src/__support/CPP/utility/swap.h with move semantics
and array support, and cpp::clamp to src/__support/CPP/algorithm.h with
comparator support.
Included unit tests in swap_test.cpp and algorithm_test.cpp.
Adopted the new utilities in initial callsites:
* stdlib: Used cpp::swap in qsort_data.h
* wctype: Used cpp::swap in perfect_hash_map.h
* math: Used cpp::clamp in powf.h
* scanf_core: Used cpp::min and cpp::max in parser.h
Also fixed sign extension when parsing scanset specifiers in parser.h:
signed characters greater than or equal to 128 produced negative values,
inverting comparisons and causing out-of-bounds writes in the bitset.
Scanset characters are now cast through uint8_t, and non-ASCII tests
were added to parser_test.cpp.
Assisted-by: Automated tooling, human reviewed.
Added:
libc/src/__support/CPP/utility/swap.h
libc/test/src/__support/CPP/swap_test.cpp
Modified:
libc/src/__support/CPP/CMakeLists.txt
libc/src/__support/CPP/algorithm.h
libc/src/__support/CPP/utility.h
libc/src/__support/math/CMakeLists.txt
libc/src/__support/math/powf.h
libc/src/__support/wctype/CMakeLists.txt
libc/src/__support/wctype/perfect_hash_map.h
libc/src/stdio/scanf_core/CMakeLists.txt
libc/src/stdio/scanf_core/parser.h
libc/src/stdlib/CMakeLists.txt
libc/src/stdlib/qsort_data.h
libc/test/src/__support/CPP/CMakeLists.txt
libc/test/src/__support/CPP/algorithm_test.cpp
libc/test/src/stdio/scanf_core/parser_test.cpp
Removed:
################################################################################
diff --git a/libc/src/__support/CPP/CMakeLists.txt b/libc/src/__support/CPP/CMakeLists.txt
index 8256caebfe754..6777c6a27c0cc 100644
--- a/libc/src/__support/CPP/CMakeLists.txt
+++ b/libc/src/__support/CPP/CMakeLists.txt
@@ -195,6 +195,9 @@ add_header_library(
utility/in_place.h
utility/integer_sequence.h
utility/move.h
+ utility/swap.h
+ DEPENDS
+ libc.hdr.types.size_t
)
add_header_library(
diff --git a/libc/src/__support/CPP/algorithm.h b/libc/src/__support/CPP/algorithm.h
index 3e2ac8b7b95ce..20ec1e85c679b 100644
--- a/libc/src/__support/CPP/algorithm.h
+++ b/libc/src/__support/CPP/algorithm.h
@@ -1,12 +1,14 @@
-//===-- A self contained equivalent of <algorithm> --------------*- 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
//
//===----------------------------------------------------------------------===//
-// This file is minimalist on purpose but can receive a few more function if
-// they prove useful.
+///
+/// \file
+/// Implementation of algorithms analogous to <algorithm>.
+///
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_ALGORITHM_H
@@ -32,6 +34,17 @@ template <class T> LIBC_INLINE constexpr const T &min(const T &a, const T &b) {
return (a < b) ? a : b;
}
+template <class T>
+LIBC_INLINE constexpr const T &clamp(const T &v, const T &lo, const T &hi) {
+ return (v < lo) ? lo : (hi < v) ? hi : v;
+}
+
+template <class T, class Compare>
+LIBC_INLINE constexpr const T &clamp(const T &v, const T &lo, const T &hi,
+ Compare comp) {
+ return comp(v, lo) ? lo : comp(hi, v) ? hi : v;
+}
+
template <class T> LIBC_INLINE constexpr T abs(T a) { return a < 0 ? -a : a; }
template <class InputIt, class UnaryPred>
diff --git a/libc/src/__support/CPP/utility.h b/libc/src/__support/CPP/utility.h
index 083b4877c3921..ac28c811b5a03 100644
--- a/libc/src/__support/CPP/utility.h
+++ b/libc/src/__support/CPP/utility.h
@@ -1,10 +1,15 @@
-//===-- Analogous to <utility> ----------------------------------*- 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
//
//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Header for <utility> analogues.
+///
+//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_H
#define LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_H
@@ -14,5 +19,6 @@
#include "src/__support/CPP/utility/in_place.h"
#include "src/__support/CPP/utility/integer_sequence.h"
#include "src/__support/CPP/utility/move.h"
+#include "src/__support/CPP/utility/swap.h"
#endif // LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_H
diff --git a/libc/src/__support/CPP/utility/swap.h b/libc/src/__support/CPP/utility/swap.h
new file mode 100644
index 0000000000000..496c0f633698d
--- /dev/null
+++ b/libc/src/__support/CPP/utility/swap.h
@@ -0,0 +1,39 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation of the swap utility.
+///
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_SWAP_H
+#define LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_SWAP_H
+
+#include "hdr/types/size_t.h"
+#include "src/__support/CPP/utility/move.h"
+#include "src/__support/macros/attributes.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace cpp {
+
+template <class T> LIBC_INLINE constexpr void swap(T &a, T &b) {
+ T temp = cpp::move(a);
+ a = cpp::move(b);
+ b = cpp::move(temp);
+}
+
+template <class T, size_t N>
+LIBC_INLINE constexpr void swap(T (&a)[N], T (&b)[N]) {
+ for (size_t i = 0; i < N; ++i)
+ swap(a[i], b[i]);
+}
+
+} // namespace cpp
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_SWAP_H
diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt
index cf9bc11fce824..0871a5bf229b6 100644
--- a/libc/src/__support/math/CMakeLists.txt
+++ b/libc/src/__support/math/CMakeLists.txt
@@ -5294,6 +5294,7 @@ add_header_library(
.common_constants
.exp10f
.exp2f
+ libc.src.__support.CPP.algorithm
libc.src.__support.CPP.bit
libc.src.__support.FPUtil.fenv_impl
libc.src.__support.FPUtil.fp_bits
diff --git a/libc/src/__support/math/powf.h b/libc/src/__support/math/powf.h
index 7721d0d7f9534..944b477ac4461 100644
--- a/libc/src/__support/math/powf.h
+++ b/libc/src/__support/math/powf.h
@@ -1,10 +1,15 @@
-//===-- Implementation header for powf --------------------------*- 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
//
//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation header for powf.
+///
+//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_POWF_H
#define LLVM_LIBC_SRC___SUPPORT_MATH_POWF_H
@@ -25,6 +30,7 @@
#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS && LIBC_MATH_HAS_SMALL_TABLES
+#include "src/__support/CPP/algorithm.h"
#include "src/__support/CPP/bit.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/PolyEval.h"
@@ -979,9 +985,8 @@ LIBC_INLINE float powf(float x, float y) {
// Clamp the exponent part into smaller range that fits double precision.
// For those exponents that are out of range, the final conversion will round
// them correctly to inf/max float or 0/min float accordingly.
- int64_t hm_i = static_cast<int64_t>(hm);
- hm_i = (hm_i > (1 << 15)) ? (1 << 15)
- : (hm_i < (-(1 << 15)) ? -(1 << 15) : hm_i);
+ int64_t hm_i =
+ cpp::clamp<int64_t>(static_cast<int64_t>(hm), -(1 << 15), 1 << 15);
int idx_y = hm_i & 0x3f;
diff --git a/libc/src/__support/wctype/CMakeLists.txt b/libc/src/__support/wctype/CMakeLists.txt
index bb67e72d001c9..d87d638ef28b8 100644
--- a/libc/src/__support/wctype/CMakeLists.txt
+++ b/libc/src/__support/wctype/CMakeLists.txt
@@ -12,6 +12,7 @@ add_header_library(
libc.src.__support.CPP.string
libc.src.__support.CPP.tuple
libc.src.__support.CPP.type_traits
+ libc.src.__support.CPP.utility
libc.src.__support.OSUtil.osutil
libc.src.__support.macros.config
libc.src.__support.math.ceil
diff --git a/libc/src/__support/wctype/perfect_hash_map.h b/libc/src/__support/wctype/perfect_hash_map.h
index a5562d589bff7..91b33c8655aac 100644
--- a/libc/src/__support/wctype/perfect_hash_map.h
+++ b/libc/src/__support/wctype/perfect_hash_map.h
@@ -1,10 +1,15 @@
-//===-- Perfect hash map for conversion 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
//
//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Perfect hash map for conversion functions.
+///
+//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC___SUPPORT_WCTYPE_PERFECT_HASH_MAP_H
#define LLVM_LIBC_SRC___SUPPORT_WCTYPE_PERFECT_HASH_MAP_H
@@ -18,6 +23,7 @@
#include "src/__support/CPP/string.h"
#include "src/__support/CPP/tuple.h"
#include "src/__support/CPP/type_traits.h"
+#include "src/__support/CPP/utility/swap.h"
#include "src/__support/macros/config.h"
#include "src/__support/math/ceil.h"
#include "src/__support/math/log.h"
@@ -349,11 +355,8 @@ class PtrHash {
sort_parts(size_t shard, cpp::array<uint64_t, n_> hashes) const {
for (size_t i = 0; i < hashes.size(); i++) {
for (size_t j = i + 1; j < hashes.size(); j++) {
- if (hashes[i] > hashes[j]) {
- auto temp = hashes[i];
- hashes[i] = hashes[j];
- hashes[j] = temp;
- }
+ if (hashes[i] > hashes[j])
+ cpp::swap(hashes[i], hashes[j]);
}
}
diff --git a/libc/src/stdio/scanf_core/CMakeLists.txt b/libc/src/stdio/scanf_core/CMakeLists.txt
index fd68f5d21ae7f..84d3998722ce3 100644
--- a/libc/src/stdio/scanf_core/CMakeLists.txt
+++ b/libc/src/stdio/scanf_core/CMakeLists.txt
@@ -49,6 +49,7 @@ add_header_library(
libc.src.__support.arg_list
libc.src.__support.ctype_utils
libc.src.__support.str_to_integer
+ libc.src.__support.CPP.algorithm
libc.src.__support.CPP.bit
libc.src.__support.CPP.bitset
libc.src.__support.CPP.string_view
diff --git a/libc/src/stdio/scanf_core/parser.h b/libc/src/stdio/scanf_core/parser.h
index 1e2f26e0d3fdd..387c21f8e9ac5 100644
--- a/libc/src/stdio/scanf_core/parser.h
+++ b/libc/src/stdio/scanf_core/parser.h
@@ -1,14 +1,20 @@
-//===-- Format string parser for scanf -------------------------*- 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
//
//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Format string parser for scanf.
+///
+//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC_STDIO_SCANF_CORE_PARSER_H
#define LLVM_LIBC_SRC_STDIO_SCANF_CORE_PARSER_H
+#include "src/__support/CPP/algorithm.h"
#include "src/__support/arg_list.h"
#include "src/__support/ctype_utils.h"
#include "src/__support/macros/config.h"
@@ -146,15 +152,14 @@ template <typename ArgProvider> class Parser {
// Technically there is no requirement to correct the ordering of
// the range, but since the range operator is entirely
// implementation defined it seems like a good convenience.
- char a = str[cur_pos - 1];
- char b = str[cur_pos + 1];
- char start = (a < b ? a : b);
- char end = (a < b ? b : a);
- scan_set.set_range(static_cast<size_t>(start),
- static_cast<size_t>(end));
+ uint8_t a = static_cast<uint8_t>(str[cur_pos - 1]);
+ uint8_t b = static_cast<uint8_t>(str[cur_pos + 1]);
+ uint8_t start = cpp::min(a, b);
+ uint8_t end = cpp::max(a, b);
+ scan_set.set_range(start, end);
cur_pos += 2;
} else {
- scan_set.set(static_cast<size_t>(str[cur_pos]));
+ scan_set.set(static_cast<uint8_t>(str[cur_pos]));
++cur_pos;
}
}
diff --git a/libc/src/stdlib/CMakeLists.txt b/libc/src/stdlib/CMakeLists.txt
index 36f3799cb30f1..6f5ec7811c7bf 100644
--- a/libc/src/stdlib/CMakeLists.txt
+++ b/libc/src/stdlib/CMakeLists.txt
@@ -340,6 +340,7 @@ add_header_library(
libc.hdr.stdint_proxy
libc.include.stdlib
libc.src.__support.CPP.cstddef
+ libc.src.__support.CPP.utility
libc.src.string.memory_utils.inline_memcpy
)
diff --git a/libc/src/stdlib/qsort_data.h b/libc/src/stdlib/qsort_data.h
index 4f9774088fbd3..8271603162678 100644
--- a/libc/src/stdlib/qsort_data.h
+++ b/libc/src/stdlib/qsort_data.h
@@ -1,16 +1,22 @@
-//===-- Data structures for sorting routines --------------------*- 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
//
//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Data structures for sorting routines.
+///
+//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC_STDLIB_QSORT_DATA_H
#define LLVM_LIBC_SRC_STDLIB_QSORT_DATA_H
#include "hdr/stdint_proxy.h"
#include "src/__support/CPP/cstddef.h"
+#include "src/__support/CPP/utility/swap.h"
#include "src/__support/macros/config.h"
#include "src/string/memory_utils/inline_memcpy.h"
@@ -63,11 +69,8 @@ class ArrayGenericSize {
elem_j += BLOCK_SIZE;
}
- for (size_t n = 0; n < elem_size_rem; ++n) {
- cpp::byte tmp = elem_i[n];
- elem_i[n] = elem_j[n];
- elem_j[n] = tmp;
- }
+ for (size_t n = 0; n < elem_size_rem; ++n)
+ cpp::swap(elem_i[n], elem_j[n]);
}
LIBC_INLINE size_t len() const { return array_len; }
diff --git a/libc/test/src/__support/CPP/CMakeLists.txt b/libc/test/src/__support/CPP/CMakeLists.txt
index 179e4ee12c734..beeb6749cceed 100644
--- a/libc/test/src/__support/CPP/CMakeLists.txt
+++ b/libc/test/src/__support/CPP/CMakeLists.txt
@@ -108,6 +108,17 @@ add_libc_test(
libc.src.__support.CPP.utility
)
+add_libc_test(
+ swap_test
+ SUITE
+ libc-cpp-utils-tests
+ SRCS
+ swap_test.cpp
+ DEPENDS
+ libc.hdr.stdint_proxy
+ libc.src.__support.CPP.utility
+)
+
# This test fails with invalid address space operations on sm_60
if(NOT LIBC_TARGET_ARCHITECTURE_IS_NVPTX)
diff --git a/libc/test/src/__support/CPP/algorithm_test.cpp b/libc/test/src/__support/CPP/algorithm_test.cpp
index 00d07bfbfbaaf..663751ff3a332 100644
--- a/libc/test/src/__support/CPP/algorithm_test.cpp
+++ b/libc/test/src/__support/CPP/algorithm_test.cpp
@@ -1,10 +1,15 @@
-//===-- Unittests for Algorithm -------------------------------------------===//
+//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unit tests for algorithm.
+///
+//===----------------------------------------------------------------------===//
#include "src/__support/CPP/algorithm.h"
#include "src/__support/CPP/array.h"
@@ -46,5 +51,44 @@ TEST(LlvmLibcAlgorithmTest, AllOf) {
EXPECT_TRUE(all_of(nums.begin(), nums.begin(), [](int i) { return i < 0; }));
}
+TEST(LlvmLibcAlgorithmTest, MinMax) {
+ EXPECT_EQ(min(1, 2), 1);
+ EXPECT_EQ(min(2, 1), 1);
+ EXPECT_EQ(min(-5, -3), -5);
+ EXPECT_EQ(min(42, 42), 42);
+
+ EXPECT_EQ(max(1, 2), 2);
+ EXPECT_EQ(max(2, 1), 2);
+ EXPECT_EQ(max(-5, -3), -3);
+ EXPECT_EQ(max(42, 42), 42);
+
+ constexpr int a = min(10, 20);
+ static_assert(a == 10);
+ constexpr int b = max(10, 20);
+ static_assert(b == 20);
+}
+
+TEST(LlvmLibcAlgorithmTest, Clamp) {
+ EXPECT_EQ(clamp(5, 0, 10), 5);
+ EXPECT_EQ(clamp(-5, 0, 10), 0);
+ EXPECT_EQ(clamp(15, 0, 10), 10);
+ EXPECT_EQ(clamp(0, 0, 10), 0);
+ EXPECT_EQ(clamp(10, 0, 10), 10);
+
+ // Custom comparator (greater)
+ auto greater = [](int x, int y) { return x > y; };
+ EXPECT_EQ(clamp(5, 10, 0, greater), 5);
+ EXPECT_EQ(clamp(15, 10, 0, greater), 10);
+ EXPECT_EQ(clamp(-5, 10, 0, greater), 0);
+
+ // Constexpr check
+ constexpr int c1 = clamp(5, 0, 10);
+ static_assert(c1 == 5);
+ constexpr int c2 = clamp(-5, 0, 10);
+ static_assert(c2 == 0);
+ constexpr int c3 = clamp(15, 0, 10);
+ static_assert(c3 == 10);
+}
+
} // namespace cpp
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/__support/CPP/swap_test.cpp b/libc/test/src/__support/CPP/swap_test.cpp
new file mode 100644
index 0000000000000..6bc195f7a7f34
--- /dev/null
+++ b/libc/test/src/__support/CPP/swap_test.cpp
@@ -0,0 +1,117 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unit tests for swap.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/stdint_proxy.h"
+#include "src/__support/CPP/utility/swap.h"
+#include "src/__support/macros/config.h"
+#include "test/UnitTest/Test.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace cpp {
+
+TEST(LlvmLibcSwapTest, Primitives) {
+ int a = 10;
+ int b = 20;
+ swap(a, b);
+ EXPECT_EQ(a, 20);
+ EXPECT_EQ(b, 10);
+
+ char c1 = 'x';
+ char c2 = 'y';
+ swap(c1, c2);
+ EXPECT_EQ(c1, 'y');
+ EXPECT_EQ(c2, 'x');
+
+ uint64_t u1 = 0x123456789abcdef0;
+ uint64_t u2 = 0x0fedcba987654321;
+ swap(u1, u2);
+ EXPECT_EQ(u1, uint64_t(0x0fedcba987654321));
+ EXPECT_EQ(u2, uint64_t(0x123456789abcdef0));
+}
+
+struct MoveTracker {
+ int val = 0;
+ int moves = 0;
+ int copies = 0;
+
+ constexpr MoveTracker(int v) : val(v) {}
+ constexpr MoveTracker(const MoveTracker &o)
+ : val(o.val), moves(o.moves), copies(o.copies + 1) {}
+ constexpr MoveTracker(MoveTracker &&o)
+ : val(o.val), moves(o.moves + 1), copies(o.copies) {
+ o.val = 0;
+ }
+ constexpr MoveTracker &operator=(const MoveTracker &o) {
+ val = o.val;
+ copies = o.copies + 1;
+ return *this;
+ }
+ constexpr MoveTracker &operator=(MoveTracker &&o) {
+ val = o.val;
+ moves = o.moves + 1;
+ o.val = 0;
+ return *this;
+ }
+};
+
+TEST(LlvmLibcSwapTest, MoveSemantics) {
+ MoveTracker t1(100);
+ MoveTracker t2(200);
+
+ swap(t1, t2);
+
+ EXPECT_EQ(t1.val, 200);
+ EXPECT_EQ(t2.val, 100);
+ // swap should perform 3 moves and 0 copies
+ EXPECT_EQ(t1.copies, 0);
+ EXPECT_EQ(t2.copies, 0);
+ EXPECT_EQ(t1.moves + t2.moves, 3);
+}
+
+struct MoveOnly {
+ int val;
+ constexpr MoveOnly(int v) : val(v) {}
+ MoveOnly(const MoveOnly &) = delete;
+ MoveOnly &operator=(const MoveOnly &) = delete;
+ constexpr MoveOnly(MoveOnly &&o) : val(o.val) { o.val = 0; }
+ constexpr MoveOnly &operator=(MoveOnly &&o) {
+ val = o.val;
+ o.val = 0;
+ return *this;
+ }
+};
+
+TEST(LlvmLibcSwapTest, MoveOnlyType) {
+ MoveOnly m1(1);
+ MoveOnly m2(2);
+ swap(m1, m2);
+ EXPECT_EQ(m1.val, 2);
+ EXPECT_EQ(m2.val, 1);
+}
+
+TEST(LlvmLibcSwapTest, ArraySwap) {
+ int arr1[3] = {1, 2, 3};
+ int arr2[3] = {4, 5, 6};
+
+ swap(arr1, arr2);
+
+ EXPECT_EQ(arr1[0], 4);
+ EXPECT_EQ(arr1[1], 5);
+ EXPECT_EQ(arr1[2], 6);
+ EXPECT_EQ(arr2[0], 1);
+ EXPECT_EQ(arr2[1], 2);
+ EXPECT_EQ(arr2[2], 3);
+}
+
+} // namespace cpp
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/stdio/scanf_core/parser_test.cpp b/libc/test/src/stdio/scanf_core/parser_test.cpp
index c81edbd8c0963..daf3756d95026 100644
--- a/libc/test/src/stdio/scanf_core/parser_test.cpp
+++ b/libc/test/src/stdio/scanf_core/parser_test.cpp
@@ -1,10 +1,15 @@
-//===-- Unittests for the scanf Parser -----------------------------------===//
+//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unit tests for the scanf Parser.
+///
+//===----------------------------------------------------------------------===//
#include "src/__support/CPP/bit.h"
#include "src/__support/CPP/bitset.h"
@@ -516,6 +521,50 @@ TEST(LlvmLibcScanfParserTest, EvalBracketArgBackwardsRange) {
ASSERT_SFORMAT_EQ(expected, format_arr[0]);
}
+TEST(LlvmLibcScanfParserTest, EvalBracketArgNonAsciiRange) {
+ LIBC_NAMESPACE::scanf_core::FormatSection format_arr[10];
+ const char *str = "%[\x80-\x85]";
+ char arg1 = 'a';
+ evaluate(format_arr, str, &arg1);
+
+ LIBC_NAMESPACE::scanf_core::FormatSection expected;
+ expected.has_conv = true;
+
+ expected.raw_string = str;
+ expected.conv_name = '[';
+ expected.output_ptr = &arg1;
+
+ LIBC_NAMESPACE::cpp::bitset<256> scan_set;
+
+ scan_set.set_range(0x80, 0x85);
+
+ expected.scan_set = scan_set;
+
+ ASSERT_SFORMAT_EQ(expected, format_arr[0]);
+}
+
+TEST(LlvmLibcScanfParserTest, EvalBracketArgNonAsciiSingleChar) {
+ LIBC_NAMESPACE::scanf_core::FormatSection format_arr[10];
+ const char *str = "%[\xff]";
+ char arg1 = 'a';
+ evaluate(format_arr, str, &arg1);
+
+ LIBC_NAMESPACE::scanf_core::FormatSection expected;
+ expected.has_conv = true;
+
+ expected.raw_string = str;
+ expected.conv_name = '[';
+ expected.output_ptr = &arg1;
+
+ LIBC_NAMESPACE::cpp::bitset<256> scan_set;
+
+ scan_set.set(0xff);
+
+ expected.scan_set = scan_set;
+
+ ASSERT_SFORMAT_EQ(expected, format_arr[0]);
+}
+
TEST(LlvmLibcScanfParserTest, EvalThreeArgs) {
LIBC_NAMESPACE::scanf_core::FormatSection format_arr[10];
const char *str = "%d%f%s";
More information about the libc-commits
mailing list