Clean up ArraySlice<>.

Remove constructors that take ranges (one of them created
ambiguity with the constructor taking just the length) and
add SubArray() to serve as a replacement API.

Remove the AsRange() function as the translation to the
IterationRange<> seems totally unnecessary, we can simply
return ArraySlice<> from the functions that used it.

Remove the At() function as the comparison with the
std::vector<>::at() is confusing given that we do not
use C++ exceptions.

Add some standard container API, i.e. nested types and
more functions.

Test: m test-art-host-gtest
Test: testrunner.py --host
Change-Id: Ifcd39222cf8f36b7ebf8029398ed7fc67aafcaf0
diff --git a/runtime/base/array_slice.h b/runtime/base/array_slice.h
index 32283d0..0da977d 100644
--- a/runtime/base/array_slice.h
+++ b/runtime/base/array_slice.h
@@ -17,7 +17,6 @@
 #ifndef ART_RUNTIME_BASE_ARRAY_SLICE_H_
 #define ART_RUNTIME_BASE_ARRAY_SLICE_H_
 
-#include "length_prefixed_array.h"
 #include "stride_iterator.h"
 #include "base/bit_utils.h"
 #include "base/casts.h"
@@ -27,9 +26,21 @@
 
 // An ArraySlice is an abstraction over an array or a part of an array of a particular type. It does
 // bounds checking and can be made from several common array-like structures in Art.
-template<typename T>
+template <typename T>
 class ArraySlice {
  public:
+  using value_type = T;
+  using reference = T&;
+  using const_reference = const T&;
+  using pointer = T*;
+  using const_pointer = const T*;
+  using iterator = StrideIterator<T>;
+  using const_iterator = StrideIterator<const T>;
+  using reverse_iterator = std::reverse_iterator<iterator>;
+  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+  using difference_type = ptrdiff_t;
+  using size_type = size_t;
+
   // Create an empty array slice.
   ArraySlice() : array_(nullptr), size_(0), element_size_(0) {}
 
@@ -44,85 +55,74 @@
     DCHECK(array_ != nullptr || length == 0);
   }
 
-  // Create an array slice of the elements between start_offset and end_offset of the array with
-  // each element being element_size bytes long. Both start_offset and end_offset are in
-  // element_size units.
-  ArraySlice(T* array,
-             uint32_t start_offset,
-             uint32_t end_offset,
-             size_t element_size = sizeof(T))
-      : array_(nullptr),
-        size_(end_offset - start_offset),
-        element_size_(element_size) {
-    DCHECK(array_ != nullptr || size_ == 0);
-    DCHECK_LE(start_offset, end_offset);
-    if (size_ != 0) {
-      uintptr_t offset = start_offset * element_size_;
-      array_ = *reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(array) + offset);
-    }
-  }
+  // Iterators.
+  iterator begin() { return iterator(&AtUnchecked(0), element_size_); }
+  const_iterator begin() const { return const_iterator(&AtUnchecked(0), element_size_); }
+  const_iterator cbegin() const { return const_iterator(&AtUnchecked(0), element_size_); }
+  StrideIterator<T> end() { return StrideIterator<T>(&AtUnchecked(size_), element_size_); }
+  const_iterator end() const { return const_iterator(&AtUnchecked(size_), element_size_); }
+  const_iterator cend() const { return const_iterator(&AtUnchecked(size_), element_size_); }
+  reverse_iterator rbegin() { return reverse_iterator(end()); }
+  const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
+  const_reverse_iterator crbegin() const { return const_reverse_iterator(cend()); }
+  reverse_iterator rend() { return reverse_iterator(begin()); }
+  const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
+  const_reverse_iterator crend() const { return const_reverse_iterator(cbegin()); }
 
-  // Create an array slice of the elements between start_offset and end_offset of the array with
-  // each element being element_size bytes long and having the given alignment. Both start_offset
-  // and end_offset are in element_size units.
-  ArraySlice(LengthPrefixedArray<T>* array,
-             uint32_t start_offset,
-             uint32_t end_offset,
-             size_t element_size = sizeof(T),
-             size_t alignment = alignof(T))
-      : array_(nullptr),
-        size_(end_offset - start_offset),
-        element_size_(element_size) {
-    DCHECK(array != nullptr || size_ == 0);
-    if (size_ != 0) {
-      DCHECK_LE(start_offset, end_offset);
-      DCHECK_LE(start_offset, array->size());
-      DCHECK_LE(end_offset, array->size());
-      array_ = &array->At(start_offset, element_size_, alignment);
-    }
-  }
+  // Size.
+  size_type size() const { return size_; }
+  bool empty() const { return size() == 0u; }
 
-  T& At(size_t index) {
+  // Element access. NOTE: Not providing at() and data().
+
+  reference operator[](size_t index) {
     DCHECK_LT(index, size_);
     return AtUnchecked(index);
   }
 
-  const T& At(size_t index) const {
+  const_reference operator[](size_t index) const {
     DCHECK_LT(index, size_);
     return AtUnchecked(index);
   }
 
-  T& operator[](size_t index) {
-    return At(index);
+  reference front() {
+    DCHECK(!empty());
+    return (*this)[0];
   }
 
-  const T& operator[](size_t index) const {
-    return At(index);
+  const_reference front() const {
+    DCHECK(!empty());
+    return (*this)[0];
   }
 
-  StrideIterator<T> begin() {
-    return StrideIterator<T>(&AtUnchecked(0), element_size_);
+  reference back() {
+    DCHECK(!empty());
+    return (*this)[size_ - 1u];
   }
 
-  StrideIterator<const T> begin() const {
-    return StrideIterator<const T>(&AtUnchecked(0), element_size_);
+  const_reference back() const {
+    DCHECK(!empty());
+    return (*this)[size_ - 1u];
   }
 
-  StrideIterator<T> end() {
-    return StrideIterator<T>(&AtUnchecked(size_), element_size_);
+  ArraySlice<T> SubArray(size_type pos) {
+    return SubArray(pos, size() - pos);
   }
 
-  StrideIterator<const T> end() const {
-    return StrideIterator<const T>(&AtUnchecked(size_), element_size_);
+  ArraySlice<const T> SubArray(size_type pos) const {
+    return SubArray(pos, size() - pos);
   }
 
-  IterationRange<StrideIterator<T>> AsRange() {
-    return size() != 0 ? MakeIterationRange(begin(), end())
-                       : MakeEmptyIterationRange(StrideIterator<T>(nullptr, 0));
+  ArraySlice<T> SubArray(size_type pos, size_type length) {
+    DCHECK_LE(pos, size());
+    DCHECK_LE(length, size() - pos);
+    return ArraySlice<T>(&AtUnchecked(pos), length, element_size_);
   }
 
-  size_t size() const {
-    return size_;
+  ArraySlice<const T> SubArray(size_type pos, size_type length) const {
+    DCHECK_LE(pos, size());
+    DCHECK_LE(length, size() - pos);
+    return ArraySlice<const T>(&AtUnchecked(pos), length, element_size_);
   }
 
   size_t ElementSize() const {