[libc] Add slice/take/drop methods to ArrayRef

Add various methods from llvm::ArrayRef. Refactor implementation to remove code duplication.

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

GitOrigin-RevId: f6b656853644a058534bffb0708c2e95347bd233
diff --git a/utils/CPP/ArrayRef.h b/utils/CPP/ArrayRef.h
index bad415e..7a2ea09 100644
--- a/utils/CPP/ArrayRef.h
+++ b/utils/CPP/ArrayRef.h
@@ -20,74 +20,82 @@
 // on the implementations of the types with the same names in
 // llvm/ADT/ArrayRef.h. The implementations in this file are of a limited
 // functionality, but can be extended in an as needed basis.
-
-template <typename T> class ArrayRef {
+namespace internal {
+template <typename T> class ArrayRefBase {
 public:
-  using iterator = const T *;
+  using iterator = T *;
+  using pointer = T *;
+  using reference = T &;
 
-private:
-  const T *Data = nullptr;
-  size_t Length = 0;
-
-public:
-  ArrayRef() = default;
+  ArrayRefBase() = default;
 
   // From Array.
   template <size_t N>
-  ArrayRef(const Array<T, N> &Arr) : Data(Arr.Data), Length(N) {}
+  ArrayRefBase(Array<T, N> &Arr) : Data(Arr.Data), Length(N) {}
 
-  // Construct an ArrayRef from a single element.
-  explicit ArrayRef(const T &OneElt) : Data(&OneElt), Length(1) {}
+  // Construct an ArrayRefBase from a single element.
+  explicit ArrayRefBase(T &OneElt) : Data(&OneElt), Length(1) {}
 
-  // Construct an ArrayRef from a pointer and length.
-  ArrayRef(const T *data, size_t length) : Data(data), Length(length) {}
+  // Construct an ArrayRefBase from a pointer and length.
+  ArrayRefBase(pointer Data, size_t Length) : Data(Data), Length(Length) {}
 
-  // Construct an ArrayRef from a range.
-  ArrayRef(const T *begin, const T *end) : Data(begin), Length(end - begin) {}
+  // Construct an ArrayRefBase from a range.
+  ArrayRefBase(iterator Begin, iterator End)
+      : Data(Begin), Length(End - Begin) {}
 
-  // Construct an ArrayRef from a C array.
+  // Construct an ArrayRefBase from a C array.
   template <size_t N>
-  constexpr ArrayRef(const T (&Arr)[N]) : Data(Arr), Length(N) {}
+  constexpr ArrayRefBase(T (&Arr)[N]) : Data(Arr), Length(N) {}
 
   iterator begin() const { return Data; }
   iterator end() const { return Data + Length; }
 
   bool empty() const { return Length == 0; }
 
-  const T *data() const { return Data; }
+  pointer data() const { return Data; }
 
   size_t size() const { return Length; }
 
-  const T &operator[](size_t Index) const { return Data[Index]; }
+  reference operator[](size_t Index) const { return Data[Index]; }
+
+  // slice(n, m) - Chop off the first N elements of the array, and keep M
+  // elements in the array.
+  ArrayRefBase<T> slice(size_t N, size_t M) const {
+    return ArrayRefBase<T>(data() + N, M);
+  }
+  // slice(n) - Chop off the first N elements of the array.
+  ArrayRefBase<T> slice(size_t N) const { return slice(N, size() - N); }
+
+  // Drop the first \p N elements of the array.
+  ArrayRefBase<T> drop_front(size_t N = 1) const {
+    return slice(N, size() - N);
+  }
+
+  // Drop the last \p N elements of the array.
+  ArrayRefBase<T> drop_back(size_t N = 1) const { return slice(0, size() - N); }
+
+  // Return a copy of *this with only the first \p N elements.
+  ArrayRefBase<T> take_front(size_t N = 1) const {
+    if (N >= size())
+      return *this;
+    return drop_back(size() - N);
+  }
+
+  // Return a copy of *this with only the last \p N elements.
+  ArrayRefBase<T> take_back(size_t N = 1) const {
+    if (N >= size())
+      return *this;
+    return drop_front(size() - N);
+  }
+
+private:
+  pointer Data = nullptr;
+  size_t Length = 0;
 };
+} // namespace internal
 
-template <typename T> class MutableArrayRef : public ArrayRef<T> {
-public:
-  using iterator = T *;
-
-  // From Array.
-  template <size_t N> MutableArrayRef(Array<T, N> &Arr) : ArrayRef<T>(Arr) {}
-
-  // Construct from a single element.
-  explicit MutableArrayRef(T &OneElt) : ArrayRef<T>(OneElt) {}
-
-  // Construct from a pointer and length.
-  MutableArrayRef(T *data, size_t length) : ArrayRef<T>(data, length) {}
-
-  // Construct from a range.
-  MutableArrayRef(T *begin, T *end) : ArrayRef<T>(begin, end) {}
-
-  // Construct from a C array.
-  template <size_t N>
-  constexpr MutableArrayRef(T (&Arr)[N]) : ArrayRef<T>(Arr) {}
-
-  T *data() const { return const_cast<T *>(ArrayRef<T>::data()); }
-
-  iterator begin() const { return data(); }
-  iterator end() const { return data() + this->size(); }
-
-  T &operator[](size_t Index) const { return data()[Index]; }
-};
+template <typename T> using ArrayRef = internal::ArrayRefBase<const T>;
+template <typename T> using MutableArrayRef = internal::ArrayRefBase<T>;
 
 } // namespace cpp
 } // namespace __llvm_libc