Bug 1448591 - Make MakeStringSpan(nullptr) return an empty span. r?froydnj. draft
authorHenri Sivonen <hsivonen@hsivonen.fi>
Sat, 24 Mar 2018 21:36:00 +0200
changeset 776539 24684502f3f94142bc45a46f9615a36729a0f263
parent 776503 0e0617333d86f6d5881e6733034c335dd6394ea3
push id104901
push userbmo:hsivonen@hsivonen.fi
push dateTue, 03 Apr 2018 09:17:06 +0000
reviewersfroydnj
bugs1448591
milestone61.0a1
Bug 1448591 - Make MakeStringSpan(nullptr) return an empty span. r?froydnj. MozReview-Commit-ID: EyuLeWjEL7w
mfbt/Span.h
mfbt/tests/gtest/TestSpan.cpp
--- a/mfbt/Span.h
+++ b/mfbt/Span.h
@@ -407,17 +407,18 @@ private:
  *
  * In addition to having constructors and MakeSpan() functions that take
  * various well-known types, a Span for an arbitrary type can be constructed
  * (via constructor or MakeSpan()) from a pointer and a length or a pointer
  * and another pointer pointing just past the last element.
  *
  * A Span<const char> or Span<const char16_t> can be obtained for const char*
  * or const char16_t pointing to a zero-terminated string using the
- * MakeStringSpan() function. Corresponding implicit constructor does not exist
+ * MakeStringSpan() function (which treats a nullptr argument equivalently
+ * to the empty string). Corresponding implicit constructor does not exist
  * in order to avoid accidental construction in cases where const char* or
  * const char16_t* do not point to a zero-terminated string.
  *
  * Span has methods that follow the Mozilla naming style and methods that
  * don't. The methods that follow the Mozilla naming style are meant to be
  * used directly from Mozilla code. The methods that don't are meant for
  * integration with C++11 range-based loops and with meta-programming that
  * expects the same methods that are found on the standard-library
@@ -1056,30 +1057,38 @@ MakeSpan(const Container& cont)
 template<class Ptr>
 Span<typename Ptr::element_type>
 MakeSpan(Ptr& aPtr, size_t aLength)
 {
   return Span<typename Ptr::element_type>(aPtr, aLength);
 }
 
 /**
- * Create span from C string.
+ * Create span from a zero-terminated C string. nullptr is
+ * treated as the empty string.
  */
 inline Span<const char>
 MakeStringSpan(const char* aZeroTerminated)
 {
+  if (!aZeroTerminated) {
+    return Span<const char>();
+  }
   return Span<const char>(aZeroTerminated, std::strlen(aZeroTerminated));
 }
 
 /**
- * Create span from UTF-16 C string.
+ * Create span from a zero-terminated UTF-16 C string. nullptr is
+ * treated as the empty string.
  */
 inline Span<const char16_t>
 MakeStringSpan(const char16_t* aZeroTerminated)
 {
+  if (!aZeroTerminated) {
+    return Span<const char16_t>();
+  }
   return Span<const char16_t>(aZeroTerminated, span_details::strlen16(aZeroTerminated));
 }
 
 } // namespace mozilla
 
 #ifdef _MSC_VER
 #if _MSC_VER < 1910
 #undef constexpr
--- a/mfbt/tests/gtest/TestSpan.cpp
+++ b/mfbt/tests/gtest/TestSpan.cpp
@@ -1190,16 +1190,21 @@ SPAN_TEST(from_xpcom_collections)
     ASSERT_EQ(s.data(), v.Elements());
     ASSERT_EQ(s[2], 3);
   }
 }
 
 SPAN_TEST(from_cstring)
 {
   {
+    const char* str = nullptr;
+    auto cs = MakeStringSpan(str);
+    ASSERT_EQ(cs.size(), 0U);
+  }
+  {
     const char* str = "abc";
 
     auto cs = MakeStringSpan(str);
     ASSERT_EQ(cs.size(), 3U);
     ASSERT_EQ(cs.data(), str);
     ASSERT_EQ(cs[2], 'c');
 
 #ifdef CONFIRM_COMPILATION_ERRORS
@@ -1229,16 +1234,21 @@ SPAN_TEST(from_cstring)
     Span<char> scca(arr); // error
     Span<const char> sccca(arr); // error
 
     Span<const char> scccea;
     scccea = arr; // error
 #endif
   }
   {
+    const char16_t* str = nullptr;
+    auto cs = MakeStringSpan(str);
+    ASSERT_EQ(cs.size(), 0U);
+  }
+  {
     char16_t arr[4] = {'a', 'b', 'c', 0};
     const char16_t* str = arr;
 
     auto cs = MakeStringSpan(str);
     ASSERT_EQ(cs.size(), 3U);
     ASSERT_EQ(cs.data(), str);
     ASSERT_EQ(cs[2], 'c');