Commit 48dd75b2 authored by Simon Giesecke's avatar Simon Giesecke
Browse files

Bug 1653335 - Add/fix constructors and deduction guides for Span. r=froydnj

parent dea5b543
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -68,11 +68,15 @@ template <class T>
Span<T> MakeSpan(Range<T>& aRange) {
  return aRange;
}
template <typename T>
Span(Range<T>&) -> Span<T>;

template <class T>
Span<const T> MakeSpan(const Range<T>& aRange) {
  return aRange;
}
template <typename T>
Span(const Range<T>&) -> Span<const T>;

}  // namespace mozilla

+60 −12
Original line number Diff line number Diff line
@@ -438,10 +438,17 @@ class Span {
  // a zero-terminated string. 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.
  Span(char* aStr) = delete;
  Span(const char* aStr) = delete;
  Span(char16_t* aStr) = delete;
  Span(const char16_t* aStr) = delete;
  // (This must be a template because otherwise it will prevent the previous
  // array constructor to match because an array decays to a pointer. This only
  // exists to point to the above explanation, since there's no other
  // constructor that would match.)
  template <
      typename T,
      typename = std::enable_if_t<
          std::is_pointer_v<T> &&
          (std::is_same_v<std::remove_const_t<std::decay_t<T>>, char> ||
           std::is_same_v<std::remove_const_t<std::decay_t<T>>, char16_t>)>>
  Span(T& aStr) = delete;

  /**
   * Constructor for std::array.
@@ -490,13 +497,15 @@ class Span {
   */
  template <
      class Container,
      class = std::enable_if_t<
      class Dummy = std::enable_if_t<
          !std::is_const_v<Container> &&
              !span_details::is_span<Container>::value &&
              !span_details::is_std_array<Container>::value &&
              std::is_convertible_v<typename Container::pointer, pointer> &&
              std::is_convertible_v<typename Container::pointer,
                                decltype(std::declval<Container>().data())>>>
  constexpr MOZ_IMPLICIT Span(Container& cont)
                                    decltype(std::declval<Container>().data())>,
          Container>>
  constexpr MOZ_IMPLICIT Span(Container& cont, Dummy* = nullptr)
      : Span(cont.data(), ReleaseAssertedCast<index_type>(cont.size())) {}

  /**
@@ -513,6 +522,39 @@ class Span {
  constexpr MOZ_IMPLICIT Span(const Container& cont)
      : Span(cont.data(), ReleaseAssertedCast<index_type>(cont.size())) {}

  // NB: the SFINAE here uses .Elements() as a incomplete/imperfect proxy for
  // the requirement on Container to be a contiguous sequence container.
  /**
   * Constructor for contiguous Mozilla containers.
   */
  template <
      class Container,
      class = std::enable_if_t<
          !std::is_const_v<Container> &&
          !span_details::is_span<Container>::value &&
          !span_details::is_std_array<Container>::value &&
          std::is_convertible_v<typename Container::elem_type*, pointer> &&
          std::is_convertible_v<
              typename Container::elem_type*,
              decltype(std::declval<Container>().Elements())>>>
  constexpr MOZ_IMPLICIT Span(Container& cont, void* = nullptr)
      : Span(cont.Elements(), ReleaseAssertedCast<index_type>(cont.Length())) {}

  /**
   * Constructor for contiguous Mozilla containers (const version).
   */
  template <
      class Container,
      class = std::enable_if_t<
          std::is_const_v<element_type> &&
          !span_details::is_span<Container>::value &&
          std::is_convertible_v<typename Container::elem_type*, pointer> &&
          std::is_convertible_v<
              typename Container::elem_type*,
              decltype(std::declval<Container>().Elements())>>>
  constexpr MOZ_IMPLICIT Span(const Container& cont, void* = nullptr)
      : Span(cont.Elements(), ReleaseAssertedCast<index_type>(cont.Length())) {}

  /**
   * Constructor from other Span.
   */
@@ -780,7 +822,7 @@ Span(span_details::span_iterator<Span<T, OtherExtent>, IsConst> aBegin,
    -> Span<std::conditional_t<IsConst, std::add_const_t<T>, T>>;

template <typename T, size_t Extent>
Span(T (&aArr)[Extent]) -> Span<T, Extent>;
Span(T (&)[Extent]) -> Span<T, Extent>;

template <class Container>
Span(Container&) -> Span<typename Container::value_type>;
@@ -788,6 +830,12 @@ Span(Container&) -> Span<typename Container::value_type>;
template <class Container>
Span(const Container&) -> Span<const typename Container::value_type>;

template <typename T, size_t Extent>
Span(mozilla::Array<T, Extent>&) -> Span<T, Extent>;

template <typename T, size_t Extent>
Span(const mozilla::Array<T, Extent>&) -> Span<const T, Extent>;

// [Span.comparison], Span comparison operators
template <class ElementType, size_t FirstExtent, size_t SecondExtent>
inline constexpr bool operator==(const Span<ElementType, FirstExtent>& l,
+7 −0
Original line number Diff line number Diff line
@@ -61,6 +61,13 @@ static_assert(std::is_convertible_v<nsTArray<const int>, Span<const int>>,
static_assert(!std::is_convertible_v<nsTArray<const int>, Span<int>>,
              "nsTArray should not drop const in conversion");

static_assert(std::is_convertible_v<const std::vector<int>, Span<const int>>,
              "const std::vector should convert into const");
static_assert(std::is_convertible_v<std::vector<int>, Span<const int>>,
              "std::vector should convert into const");
static_assert(!std::is_convertible_v<const std::vector<int>, Span<int>>,
              "std::vector should not drop const in conversion");

/**
 * Rust slice-compatible nullptr replacement value.
 */