Mark all of bssl::Span as constexpr

Pretty much all of std::span and base::span are constexpr. der::Input
similarly has constexpr bits. So we can use bssl::Span in der::Input,
align bssl::Span in constexpr-ness.

Also fix const-ness of first() and last().

Bug: chromium:770501
Change-Id: Ic0031cd955d8ac0af9c3cb928411f23a34820347
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/61945
Commit-Queue: Bob Beck <bbe@google.com>
Auto-Submit: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: Bob Beck <bbe@google.com>
diff --git a/include/openssl/span.h b/include/openssl/span.h
index 34b39c0..aa8f801 100644
--- a/include/openssl/span.h
+++ b/include/openssl/span.h
@@ -114,36 +114,37 @@
 
   template <typename C, typename = EnableIfContainer<C>,
             typename = std::enable_if_t<std::is_const<T>::value, C>>
-  Span(const C &container) : data_(container.data()), size_(container.size()) {}
+  constexpr Span(const C &container)
+      : data_(container.data()), size_(container.size()) {}
 
   template <typename C, typename = EnableIfContainer<C>,
             typename = std::enable_if_t<!std::is_const<T>::value, C>>
-  explicit Span(C &container)
+  constexpr explicit Span(C &container)
       : data_(container.data()), size_(container.size()) {}
 
-  T *data() const { return data_; }
-  size_t size() const { return size_; }
-  bool empty() const { return size_ == 0; }
+  constexpr T *data() const { return data_; }
+  constexpr size_t size() const { return size_; }
+  constexpr bool empty() const { return size_ == 0; }
 
-  T *begin() const { return data_; }
-  const T *cbegin() const { return data_; }
-  T *end() const { return data_ + size_; }
-  const T *cend() const { return end(); }
+  constexpr T *begin() const { return data_; }
+  constexpr const T *cbegin() const { return data_; }
+  constexpr T *end() const { return data_ + size_; }
+  constexpr const T *cend() const { return end(); }
 
-  T &front() const {
+  constexpr T &front() const {
     if (size_ == 0) {
       abort();
     }
     return data_[0];
   }
-  T &back() const {
+  constexpr T &back() const {
     if (size_ == 0) {
       abort();
     }
     return data_[size_ - 1];
   }
 
-  T &operator[](size_t i) const {
+  constexpr T &operator[](size_t i) const {
     if (i >= size_) {
       abort();
     }
@@ -151,7 +152,7 @@
   }
   T &at(size_t i) const { return (*this)[i]; }
 
-  Span subspan(size_t pos = 0, size_t len = npos) const {
+  constexpr Span subspan(size_t pos = 0, size_t len = npos) const {
     if (pos > size_) {
       // absl::Span throws an exception here. Note std::span and Chromium
       // base::span additionally forbid pos + len being out of range, with a
@@ -163,14 +164,14 @@
     return Span(data_ + pos, std::min(size_ - pos, len));
   }
 
-  Span first(size_t len) {
+  constexpr Span first(size_t len) const {
     if (len > size_) {
       abort();
     }
     return Span(data_, len);
   }
 
-  Span last(size_t len) {
+  constexpr Span last(size_t len) const {
     if (len > size_) {
       abort();
     }
@@ -186,27 +187,28 @@
 const size_t Span<T>::npos;
 
 template <typename T>
-Span<T> MakeSpan(T *ptr, size_t size) {
+constexpr Span<T> MakeSpan(T *ptr, size_t size) {
   return Span<T>(ptr, size);
 }
 
 template <typename C>
-auto MakeSpan(C &c) -> decltype(MakeSpan(c.data(), c.size())) {
+constexpr auto MakeSpan(C &c) -> decltype(MakeSpan(c.data(), c.size())) {
   return MakeSpan(c.data(), c.size());
 }
 
 template <typename T>
-Span<const T> MakeConstSpan(T *ptr, size_t size) {
+constexpr Span<const T> MakeConstSpan(T *ptr, size_t size) {
   return Span<const T>(ptr, size);
 }
 
 template <typename C>
-auto MakeConstSpan(const C &c) -> decltype(MakeConstSpan(c.data(), c.size())) {
+constexpr auto MakeConstSpan(const C &c)
+    -> decltype(MakeConstSpan(c.data(), c.size())) {
   return MakeConstSpan(c.data(), c.size());
 }
 
 template <typename T, size_t size>
-Span<const T> MakeConstSpan(T (&array)[size]) {
+constexpr Span<const T> MakeConstSpan(T (&array)[size]) {
   return array;
 }
 
diff --git a/ssl/span_test.cc b/ssl/span_test.cc
index 7db3d70..481b0fc 100644
--- a/ssl/span_test.cc
+++ b/ssl/span_test.cc
@@ -86,5 +86,17 @@
   EXPECT_EQ(s.end(), v.data() + v.size());
 }
 
+TEST(SpanTest, ConstExpr) {
+  static constexpr int v[] = {1, 2, 3, 4};
+  constexpr bssl::Span<const int> span1(v);
+  static_assert(span1.size() == 4u, "wrong size");
+  constexpr bssl::Span<const int> span2 = MakeConstSpan(v);
+  static_assert(span2.size() == 4u, "wrong size");
+  static_assert(span2.subspan(1).size() == 3u, "wrong size");
+  static_assert(span2.first(1).size() == 1u, "wrong size");
+  static_assert(span2.last(1).size() == 1u, "wrong size");
+  static_assert(span2[0] == 1, "wrong value");
+}
+
 }  // namespace
 BSSL_NAMESPACE_END