[libc-commits] [libc] 5541e6b - [libc] Add a span facility

Guillaume Chatelet via libc-commits libc-commits at lists.llvm.org
Mon Aug 22 00:27:24 PDT 2022


Author: Guillaume Chatelet
Date: 2022-08-22T07:27:00Z
New Revision: 5541e6bc0596df4cab6009d6577c2003dc7b11a5

URL: https://github.com/llvm/llvm-project/commit/5541e6bc0596df4cab6009d6577c2003dc7b11a5
DIFF: https://github.com/llvm/llvm-project/commit/5541e6bc0596df4cab6009d6577c2003dc7b11a5.diff

LOG: [libc] Add a span facility

This is intended to replace ArrayRef.

Differential Revision: https://reviews.llvm.org/D132254

Added: 
    libc/src/__support/CPP/span.h
    libc/test/src/__support/CPP/span_test.cpp

Modified: 
    libc/src/__support/CPP/CMakeLists.txt
    libc/test/src/__support/CPP/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/libc/src/__support/CPP/CMakeLists.txt b/libc/src/__support/CPP/CMakeLists.txt
index 9937c951c5d69..a3734c382afb3 100644
--- a/libc/src/__support/CPP/CMakeLists.txt
+++ b/libc/src/__support/CPP/CMakeLists.txt
@@ -52,6 +52,14 @@ add_header_library(
     .uint
 )
 
+add_header_library(
+  span
+  HDRS
+    span.h
+  DEPENDS
+    .type_traits
+)
+
 add_header_library(
   string_view
   HDRS

diff  --git a/libc/src/__support/CPP/span.h b/libc/src/__support/CPP/span.h
new file mode 100644
index 0000000000000..6dac9d123983c
--- /dev/null
+++ b/libc/src/__support/CPP/span.h
@@ -0,0 +1,97 @@
+//===-- Standalone implementation std::span ---------------------*- 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_SUPPORT_CPP_SPAN_H
+#define LLVM_LIBC_SRC_SUPPORT_CPP_SPAN_H
+
+#include <stddef.h> // For size_t
+
+#include "array.h"       // For array
+#include "type_traits.h" // For remove_cv_t
+
+namespace __llvm_libc::cpp {
+
+// A trimmed down implementation of std::span.
+// Missing features:
+// - No constant size spans (e.g. Span<int, 4>),
+// - Only handle pointer like types, no fancy interators nor object overriding
+//   the & operator,
+// - No implicit type conversion (e.g. Span<B>, initialized with As where A
+//   inherits from B),
+// - No reverse iterators
+template <typename T> class span {
+public:
+  using element_type = T;
+  using value_type = remove_cv_t<T>;
+  using size_type = size_t;
+  using 
diff erence_type = ptr
diff _t;
+  using pointer = T *;
+  using const_pointer = const T *;
+  using reference = T &;
+  using const_reference = const T &;
+  using iterator = T *;
+
+  static constexpr size_type dynamic_extent = -1;
+
+  constexpr span() : span_data(nullptr), span_size(0) {}
+
+  constexpr span(pointer first, size_type count)
+      : span_data(first), span_size(count) {}
+
+  constexpr span(pointer first, pointer end)
+      : span_data(first), span_size(end - first) {}
+
+  template <size_t N>
+  constexpr span(element_type (&arr)[N]) : span_data(arr), span_size(N) {}
+
+  template <size_t N>
+  constexpr span(array<T, N> &arr)
+      : span_data(arr.data()), span_size(arr.size()) {}
+
+  constexpr span(const span &s) = default;
+  constexpr span &operator=(const span &s) = default;
+  ~span() = default;
+  constexpr reference operator[](size_type index) const {
+    return data()[index];
+  }
+  constexpr iterator begin() const { return data(); }
+  constexpr iterator end() const { return data() + size(); }
+  constexpr reference front() const { return (*this)[0]; }
+  constexpr reference back() const { return (*this)[size() - 1]; }
+  constexpr pointer data() const { return span_data; }
+  constexpr size_type size() const { return span_size; }
+  constexpr size_type size_bytes() const { return sizeof(T) * size(); }
+  constexpr bool empty() const { return size() == 0; }
+
+  constexpr span<element_type> subspan(size_type offset,
+                                       size_type count = dynamic_extent) const {
+    return span<element_type>(data() + offset, count_to_size(offset, count));
+  }
+
+  constexpr span<element_type> first(size_type count) const {
+    return subspan(0, count);
+  }
+
+  constexpr span<element_type> last(size_type count) const {
+    return span<element_type>(data() + (size() - count), count);
+  }
+
+private:
+  constexpr size_type count_to_size(size_type offset, size_type count) const {
+    if (count == dynamic_extent) {
+      return size() - offset;
+    }
+    return count;
+  }
+
+  T *span_data;
+  size_t span_size;
+};
+
+} // namespace __llvm_libc::cpp
+
+#endif /* LLVM_LIBC_SRC_SUPPORT_CPP_SPAN_H */

diff  --git a/libc/test/src/__support/CPP/CMakeLists.txt b/libc/test/src/__support/CPP/CMakeLists.txt
index e958b4b85b973..1a766c99e23be 100644
--- a/libc/test/src/__support/CPP/CMakeLists.txt
+++ b/libc/test/src/__support/CPP/CMakeLists.txt
@@ -91,3 +91,13 @@ add_libc_unittest(
   DEPENDS
   libc.src.__support.CPP.optional
 )
+
+add_libc_unittest(
+  span_test
+  SUITE
+    libc_cpp_utils_unittests
+  SRCS
+    span_test.cpp
+  DEPENDS
+  libc.src.__support.CPP.span
+)

diff  --git a/libc/test/src/__support/CPP/span_test.cpp b/libc/test/src/__support/CPP/span_test.cpp
new file mode 100644
index 0000000000000..6cb775a662ac5
--- /dev/null
+++ b/libc/test/src/__support/CPP/span_test.cpp
@@ -0,0 +1,109 @@
+//===-- Unittests for span ------------------------------------------------===//
+//
+// 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/array.h"
+#include "src/__support/CPP/span.h"
+#include "utils/UnitTest/Test.h"
+
+using __llvm_libc::cpp::array;
+using __llvm_libc::cpp::span;
+
+TEST(LlvmLibcSpanTest, InitializeEmpty) {
+  span<int> s;
+  ASSERT_EQ(s.size(), size_t(0));
+  ASSERT_TRUE(s.empty());
+  ASSERT_TRUE(s.data() == nullptr);
+}
+
+TEST(LlvmLibcSpanTest, InitializeSingleton) {
+  int a = 42;
+  span<int> s(&a, 1);
+  ASSERT_EQ(s.size(), size_t(1));
+  ASSERT_FALSE(s.empty());
+  ASSERT_TRUE(s.data() == &a);
+  ASSERT_EQ(s.front(), 42);
+  ASSERT_EQ(s.back(), 42);
+}
+
+TEST(LlvmLibcSpanTest, InitializeCArray) {
+  int a[] = {1, 2, 3};
+  span<int> s(a);
+  ASSERT_EQ(s.size(), size_t(3));
+  ASSERT_FALSE(s.empty());
+  ASSERT_TRUE(s.data() == &a[0]);
+  ASSERT_EQ(s.front(), 1);
+  ASSERT_EQ(s.back(), 3);
+  ASSERT_EQ(s[0], 1);
+  ASSERT_EQ(s[1], 2);
+  ASSERT_EQ(s[2], 3);
+}
+
+TEST(LlvmLibcSpanTest, InitializeArray) {
+  array<int, 3> a = {1, 2, 3};
+  span<int> s(a);
+  ASSERT_EQ(s.size(), size_t(3));
+  ASSERT_FALSE(s.empty());
+  ASSERT_TRUE(s.data() == &a[0]);
+  ASSERT_EQ(s.front(), 1);
+  ASSERT_EQ(s.back(), 3);
+  ASSERT_EQ(s[0], 1);
+  ASSERT_EQ(s[1], 2);
+  ASSERT_EQ(s[2], 3);
+}
+
+TEST(LlvmLibcSpanTest, Modify) {
+  int a[] = {1, 2, 3};
+  span<int> s(a);
+  for (int &value : s)
+    ++value;
+  ASSERT_EQ(s.size(), size_t(3));
+  ASSERT_EQ(s[0], 2);
+  ASSERT_EQ(s[1], 3);
+  ASSERT_EQ(s[2], 4);
+}
+
+TEST(LlvmLibcSpanTest, SubSpan) {
+  int a[] = {1, 2, 3};
+  span<const int> s(a);
+  { // same span
+    const auto _ = s.subspan(0);
+    ASSERT_EQ(_.size(), size_t(3));
+    ASSERT_EQ(_[0], 1);
+    ASSERT_EQ(_[1], 2);
+    ASSERT_EQ(_[2], 3);
+  }
+  { // last element
+    const auto _ = s.subspan(2);
+    ASSERT_EQ(_.size(), size_t(1));
+    ASSERT_EQ(_[0], 3);
+  }
+  { // no element
+    const auto _ = s.subspan(3);
+    ASSERT_EQ(_.size(), size_t(0));
+  }
+  { // first element
+    const auto _ = s.subspan(0, 1);
+    ASSERT_EQ(_.size(), size_t(1));
+    ASSERT_EQ(_[0], 1);
+  }
+}
+
+TEST(LlvmLibcSpanTest, FirstAndLastSubSpan) {
+  int a[] = {1, 2, 3};
+  span<const int> s(a);
+
+  const auto first = s.first(2);
+  ASSERT_EQ(first.size(), size_t(2));
+  ASSERT_EQ(first[0], 1);
+  ASSERT_EQ(first[1], 2);
+
+  const auto last = s.last(2);
+  ASSERT_EQ(last.size(), size_t(2));
+  ASSERT_EQ(last[0], 2);
+  ASSERT_EQ(last[1], 3);
+}


        


More information about the libc-commits mailing list