[libc-commits] [libc] [libc][wctype] Upstream custom slice implementation from PtrHash-cc prototype to LLVM libc (PR #174779)

Muhammad Bassiouni via libc-commits libc-commits at lists.llvm.org
Fri Jan 9 10:14:06 PST 2026


https://github.com/bassiounix updated https://github.com/llvm/llvm-project/pull/174779

>From 81dbf6bb866481eb72f37070075934b31c40d583 Mon Sep 17 00:00:00 2001
From: bassiounix <muhammad.m.bassiouni at gmail.com>
Date: Wed, 7 Jan 2026 16:42:29 +0200
Subject: [PATCH 1/9] [libc][wctype] Upstream custom slice implementation from
 PtrHash-cc prototype to LLVM libc

---
 .../wctype/conversion/utils/CMakeLists.txt    |  11 ++
 .../__support/wctype/conversion/utils/slice.h | 113 ++++++++++++++++++
 2 files changed, 124 insertions(+)
 create mode 100644 libc/src/__support/wctype/conversion/utils/CMakeLists.txt
 create mode 100644 libc/src/__support/wctype/conversion/utils/slice.h

diff --git a/libc/src/__support/wctype/conversion/utils/CMakeLists.txt b/libc/src/__support/wctype/conversion/utils/CMakeLists.txt
new file mode 100644
index 0000000000000..edd6270f47126
--- /dev/null
+++ b/libc/src/__support/wctype/conversion/utils/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_header_library(
+  slice
+  HDRS
+    slice.h
+  DEPENDS
+    libc.hdr.types.size_t
+    libc.src.__support.CPP.algorithm
+    libc.src.__support.CPP.expected
+    libc.src.__support.CPP.span
+    libc.src.__support.libc_assert
+)
diff --git a/libc/src/__support/wctype/conversion/utils/slice.h b/libc/src/__support/wctype/conversion/utils/slice.h
new file mode 100644
index 0000000000000..f630ad21d73c2
--- /dev/null
+++ b/libc/src/__support/wctype/conversion/utils/slice.h
@@ -0,0 +1,113 @@
+//===-- Internal utils for wctype conversion code - slice -------*- 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
+//
+//===----------------------------------------------------------------------===//
+// Similar to cpp::span with additional functionality
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_WCTYPE_CONVERSION_UTILS_SLICE_H
+#define LLVM_LIBC_SRC___SUPPORT_WCTYPE_CONVERSION_UTILS_SLICE_H
+
+#include "hdr/types/size_t.h"
+#include "src/__support/CPP/algorithm.h"
+#include "src/__support/CPP/expected.h"
+#include "src/__support/CPP/span.h"
+#include "src/__support/libc_assert.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+namespace internal_wctype_conversion_utils {
+
+enum class Ordering {
+  /// An ordering where a compared value is less than another.
+  Less = -1,
+  /// An ordering where a compared value is equal to another.
+  Equal = 0,
+  /// An ordering where a compared value is greater than another.
+  Greater = 1,
+};
+
+template <typename T> struct Slice : public cpp::span<T> {
+  LIBC_INLINE constexpr Slice() : cpp::span<T>() {}
+
+  LIBC_INLINE constexpr Slice(T *ptr, size_t len) : cpp::span<T>(ptr, len) {}
+  LIBC_INLINE constexpr Slice(T const *ptr, size_t len)
+      : cpp::span<T>(ptr, len) {}
+
+  template <typename U, size_t N>
+  LIBC_INLINE constexpr Slice<U>(cpp::array<U, N> &arr) : cpp::span<T>(arr) {}
+
+  LIBC_INLINE constexpr Slice(const Slice<T> &) = default;
+  LIBC_INLINE constexpr Slice(Slice<T> &&) = default;
+
+  LIBC_INLINE constexpr Slice(const cpp::span<T> &s) : cpp::span<T>(s) {}
+  LIBC_INLINE constexpr Slice(cpp::span<T> &&s) : cpp::span<T>(s) {}
+
+  LIBC_INLINE constexpr Slice &operator=(const Slice<T> &n) = default;
+  LIBC_INLINE constexpr Slice &operator=(Slice<T> &&n) = default;
+
+  LIBC_INLINE constexpr Slice &operator=(const cpp::span<T> &n) {
+    this->operator=(n);
+    return *this;
+  }
+  LIBC_INLINE constexpr Slice &operator=(cpp::span<T> &&n) {
+    this->operator=(n);
+    return *this;
+  }
+
+  template <typename Fn>
+  LIBC_INLINE constexpr cpp::expected<size_t, size_t>
+  binary_search_by(Fn func) const {
+    auto size = this->size();
+    if (size == 0) {
+      return cpp::unexpected<size_t>(0);
+    }
+
+    auto base = 0;
+
+    while (size > 1) {
+      auto half = size / 2;
+      auto mid = base + half;
+      auto cmp = func(this->operator[](mid));
+      base = (cmp == Ordering::Greater) ? base : mid;
+      size -= half;
+    }
+
+    auto cmp = func(this->operator[](base));
+    if (cmp == Ordering::Equal) {
+      LIBC_ASSERT(base < this->size());
+      return base;
+    } else {
+      auto result = base + static_cast<size_t>(cmp == Ordering::Less);
+      LIBC_ASSERT(result <= this->size());
+      return cpp::unexpected(result);
+    }
+  }
+
+  LIBC_INLINE constexpr Slice<T> range(size_t start, size_t end) const {
+    return Slice<T>(this->data() + start, end - start);
+  }
+
+  LIBC_INLINE constexpr bool contains(T elm) const {
+    for (auto it : *this) {
+      if (elm == it) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  LIBC_INLINE constexpr void copy_from_slice(Slice<T> other) const {
+    for (size_t i = 0; i < cpp::min(this->size(), other.size()); i++) {
+      this->data()[i] = other.data()[i];
+    }
+  }
+};
+
+} // namespace internal_wctype_conversion_utils
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_WCTYPE_CONVERSION_UTILS_SLICE_H

>From 957172402986bebf946b589cae5be20eae3a10ea Mon Sep 17 00:00:00 2001
From: bassiounix <muhammad.m.bassiouni at gmail.com>
Date: Wed, 7 Jan 2026 20:22:03 +0200
Subject: [PATCH 2/9] fix nesting

---
 libc/src/__support/wctype/conversion/utils/slice.h | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/libc/src/__support/wctype/conversion/utils/slice.h b/libc/src/__support/wctype/conversion/utils/slice.h
index f630ad21d73c2..69f8e58fc568e 100644
--- a/libc/src/__support/wctype/conversion/utils/slice.h
+++ b/libc/src/__support/wctype/conversion/utils/slice.h
@@ -18,7 +18,9 @@
 
 namespace LIBC_NAMESPACE_DECL {
 
-namespace internal_wctype_conversion_utils {
+namespace wctype_internal {
+
+namespace conversion_utils {
 
 enum class Ordering {
   /// An ordering where a compared value is less than another.
@@ -106,7 +108,10 @@ template <typename T> struct Slice : public cpp::span<T> {
   }
 };
 
-} // namespace internal_wctype_conversion_utils
+
+} // namespace conversion_utils
+
+} // namespace wctype_internal
 
 } // namespace LIBC_NAMESPACE_DECL
 

>From a306d1f2b22665df3db58f9103b719761907ba14 Mon Sep 17 00:00:00 2001
From: bassiounix <muhammad.m.bassiouni at gmail.com>
Date: Wed, 7 Jan 2026 20:28:12 +0200
Subject: [PATCH 3/9] format

---
 libc/src/__support/wctype/conversion/utils/slice.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/libc/src/__support/wctype/conversion/utils/slice.h b/libc/src/__support/wctype/conversion/utils/slice.h
index 69f8e58fc568e..fa5831f053529 100644
--- a/libc/src/__support/wctype/conversion/utils/slice.h
+++ b/libc/src/__support/wctype/conversion/utils/slice.h
@@ -108,7 +108,6 @@ template <typename T> struct Slice : public cpp::span<T> {
   }
 };
 
-
 } // namespace conversion_utils
 
 } // namespace wctype_internal

>From 394b3fa5d4cb29e8989a06522997b8214b6c707a Mon Sep 17 00:00:00 2001
From: bassiounix <muhammad.m.bassiouni at gmail.com>
Date: Fri, 9 Jan 2026 18:16:47 +0200
Subject: [PATCH 4/9] call explicit operator

---
 libc/src/__support/wctype/conversion/utils/slice.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libc/src/__support/wctype/conversion/utils/slice.h b/libc/src/__support/wctype/conversion/utils/slice.h
index fa5831f053529..4b90c2504db15 100644
--- a/libc/src/__support/wctype/conversion/utils/slice.h
+++ b/libc/src/__support/wctype/conversion/utils/slice.h
@@ -51,11 +51,11 @@ template <typename T> struct Slice : public cpp::span<T> {
   LIBC_INLINE constexpr Slice &operator=(Slice<T> &&n) = default;
 
   LIBC_INLINE constexpr Slice &operator=(const cpp::span<T> &n) {
-    this->operator=(n);
+    cpp::span<T>::operator=(n);
     return *this;
   }
   LIBC_INLINE constexpr Slice &operator=(cpp::span<T> &&n) {
-    this->operator=(n);
+    cpp::span<T>::operator=(n);
     return *this;
   }
 

>From 42b6d9dba0c4f0878061e012d3e591b81f69735f Mon Sep 17 00:00:00 2001
From: bassiounix <muhammad.m.bassiouni at gmail.com>
Date: Fri, 9 Jan 2026 18:19:45 +0200
Subject: [PATCH 5/9] Add bounds checking asserts

---
 libc/src/__support/wctype/conversion/utils/slice.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libc/src/__support/wctype/conversion/utils/slice.h b/libc/src/__support/wctype/conversion/utils/slice.h
index 4b90c2504db15..d7fd7bd8dcc7d 100644
--- a/libc/src/__support/wctype/conversion/utils/slice.h
+++ b/libc/src/__support/wctype/conversion/utils/slice.h
@@ -89,6 +89,7 @@ template <typename T> struct Slice : public cpp::span<T> {
   }
 
   LIBC_INLINE constexpr Slice<T> range(size_t start, size_t end) const {
+    LIBC_ASSERT(start <= end && end <= this->size());
     return Slice<T>(this->data() + start, end - start);
   }
 

>From 9de4f4d7b48f19648f12dc60a46af3bc8413068e Mon Sep 17 00:00:00 2001
From: bassiounix <muhammad.m.bassiouni at gmail.com>
Date: Fri, 9 Jan 2026 19:20:38 +0200
Subject: [PATCH 6/9] add docs comment

---
 .../src/__support/wctype/conversion/utils/slice.h | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/libc/src/__support/wctype/conversion/utils/slice.h b/libc/src/__support/wctype/conversion/utils/slice.h
index d7fd7bd8dcc7d..90a5268342d06 100644
--- a/libc/src/__support/wctype/conversion/utils/slice.h
+++ b/libc/src/__support/wctype/conversion/utils/slice.h
@@ -59,6 +59,21 @@ template <typename T> struct Slice : public cpp::span<T> {
     return *this;
   }
 
+  // Binary searches this slice with a comparator function.
+  //
+  // The comparator function should return an order code that indicates whether
+  // its argument is `Less`, `Equal` or `Greater` the desired target.
+  // If the slice is not sorted or if the comparator function does not
+  // implement an order consistent with the sort order of the underlying
+  // slice, the returned result is unspecified and meaningless.
+  //
+  // If the value is found then `cpp::expected<size_t>` is returned,
+  // containing the index of the matching element. If there are multiple
+  // matches, then any one of the matches could be returned. The index is chosen
+  // deterministically.
+  // If the value is not found then `cpp::unexpected<size_t>` is returned,
+  // containing the index where a matching element could be inserted while
+  // maintaining sorted order.
   template <typename Fn>
   LIBC_INLINE constexpr cpp::expected<size_t, size_t>
   binary_search_by(Fn func) const {

>From cd09aabdb2565f7ed7f07cccb108a5e7fbb23295 Mon Sep 17 00:00:00 2001
From: bassiounix <muhammad.m.bassiouni at gmail.com>
Date: Fri, 9 Jan 2026 20:00:56 +0200
Subject: [PATCH 7/9] make type size_t

---
 libc/src/__support/wctype/conversion/utils/slice.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/src/__support/wctype/conversion/utils/slice.h b/libc/src/__support/wctype/conversion/utils/slice.h
index 90a5268342d06..4aa6fb919e761 100644
--- a/libc/src/__support/wctype/conversion/utils/slice.h
+++ b/libc/src/__support/wctype/conversion/utils/slice.h
@@ -82,7 +82,7 @@ template <typename T> struct Slice : public cpp::span<T> {
       return cpp::unexpected<size_t>(0);
     }
 
-    auto base = 0;
+    size_t base = 0;
 
     while (size > 1) {
       auto half = size / 2;

>From 84e97b7648506a08fddf27711e9db3cc1a841b1c Mon Sep 17 00:00:00 2001
From: bassiounix <muhammad.m.bassiouni at gmail.com>
Date: Fri, 9 Jan 2026 20:01:16 +0200
Subject: [PATCH 8/9] rename method to `slice_form_range`

---
 libc/src/__support/wctype/conversion/utils/slice.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/libc/src/__support/wctype/conversion/utils/slice.h b/libc/src/__support/wctype/conversion/utils/slice.h
index 4aa6fb919e761..7eaa2da2d5c5c 100644
--- a/libc/src/__support/wctype/conversion/utils/slice.h
+++ b/libc/src/__support/wctype/conversion/utils/slice.h
@@ -103,7 +103,8 @@ template <typename T> struct Slice : public cpp::span<T> {
     }
   }
 
-  LIBC_INLINE constexpr Slice<T> range(size_t start, size_t end) const {
+  LIBC_INLINE constexpr Slice<T> slice_form_range(size_t start,
+                                                  size_t end) const {
     LIBC_ASSERT(start <= end && end <= this->size());
     return Slice<T>(this->data() + start, end - start);
   }

>From 41bd7d3007da05d21357894d19758ba574345454 Mon Sep 17 00:00:00 2001
From: bassiounix <muhammad.m.bassiouni at gmail.com>
Date: Fri, 9 Jan 2026 20:14:50 +0200
Subject: [PATCH 9/9] remove explicit U

---
 libc/src/__support/wctype/conversion/utils/slice.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/src/__support/wctype/conversion/utils/slice.h b/libc/src/__support/wctype/conversion/utils/slice.h
index 7eaa2da2d5c5c..a3e08bc1b5c5d 100644
--- a/libc/src/__support/wctype/conversion/utils/slice.h
+++ b/libc/src/__support/wctype/conversion/utils/slice.h
@@ -39,7 +39,7 @@ template <typename T> struct Slice : public cpp::span<T> {
       : cpp::span<T>(ptr, len) {}
 
   template <typename U, size_t N>
-  LIBC_INLINE constexpr Slice<U>(cpp::array<U, N> &arr) : cpp::span<T>(arr) {}
+  LIBC_INLINE constexpr Slice(cpp::array<U, N> &arr) : cpp::span<T>(arr) {}
 
   LIBC_INLINE constexpr Slice(const Slice<T> &) = default;
   LIBC_INLINE constexpr Slice(Slice<T> &&) = default;



More information about the libc-commits mailing list