Title
`join_view` should be `sized_range` when applied to ranges of `simd::vec`
Status
new
Section
[range.join.view] [range.join.with.view] [range.lazy.split.view]
Submitter
Hewill Kang

Created on 2025-10-02.00:00:00 last changed 1 week ago

Messages

Date: 2025-10-04.13:39:45

Proposed resolution:

This wording is relative to N5014.

  1. Modify [range.join.view] as indicated:

    [Drafting note: The proposed wording follows the tiny-range's way to check if `R::size()` is a constant expression instead of further checking `ranges::size(r)` for simplicity.]

    namespace std::ranges {
      template<auto> struct require-constant;  // exposition only
    
      template<class R>
      concept static-sized-range =             // exposition only
        sized_range<R> &&
        requires { typename require-constant<remove_reference_t<R>::size()>; };
    
      template<input_range V>
        requires view<V> && input_range<range_reference_t<V>>>
      class join_view : public view_interface<join_view<V>> {
      […]
      public:
        […]
        constexpr auto size()
          requires sized_range<V> && static-sized-range<InnerRng> {
          using CT = common_type_t<range_size_t<V>, range_size_t<InnerRng>>;
          return CT(ranges::size(base_)) * CT(remove_reference_t<InnerRng>::size());
        }
    
        constexpr auto size() const
          requires sized_range<const V> &&
                   static-sized-range<range_reference_t<const V>> {
          using InnerConstRng = range_reference_t<const V>;
          using CT = common_type_t<range_size_t<V>, range_size_t<InnerConstRng>>;
          return CT(ranges::size(base_)) * CT(remove_reference_t<InnerConstRng>::size());
        }
      };
      […]
    }
    
  2. Modify [range.join.with.view] as indicated:

    namespace std::ranges {
      […]
      template<input_range V, forward_range Pattern>
        requires view<V> && input_range<range_reference_t<V>>
              && view<Pattern>
              && concatable<range_reference_t<V>, Pattern>
      class join_with_view : public view_interface<join_with_view<V, Pattern>> {
      […]
      public:
        […]
        constexpr auto size()
          requires sized_range<V> && sized_range<Pattern> &&
                   static-sized-range<InnerRng> {
          using CT = common_type_t<
            range_size_t<V>, range_size_t<InnerRng>, range_size_t<Pattern>>;
          const auto base_size = ranges::size(base_);
          if (base_size == 0)
            return CT(0);
          return CT(base_size) * CT(remove_reference_t<InnerRng>::size()) +
                 CT(base_size - 1) * CT(ranges::size(pattern_));
        }
    
        constexpr auto size() const
          requires sized_range<const V> && sized_range<const Pattern> &&
                   static-sized-range<range_reference_t<const V>> {
          using InnerConstRng = range_reference_t<const V>;
          using CT = common_type_t<
            range_size_t<const V>, range_size_t<InnerConstRng>, range_size_t<const Pattern>>;
          const auto base_size = ranges::size(base_);
          if (base_size == 0)
            return CT(0);
          return CT(base_size) * CT(remove_reference_t<InnerConstRng>::size()) +
                 CT(base_size - 1) * CT(ranges::size(pattern_));
        }
      };
      […]
    }
    
  3. Modify [range.lazy.split.view] as indicated:

    namespace std::ranges {
      template<auto> struct require-constant;                       // exposition only
    
      template<class R>
      concept tiny-range =                                          // exposition only
        static-sized-range<R>sized_range<R> &&
        requires { typename require-constant<remove_reference_t<R>::size()>; } &&
        (remove_reference_t<R>::size() <= 1);
      
      […]
    }
    
Date: 2025-10-02.00:00:00

Consider:

Collecting a `simd::vec` into a `vector` for output is a common use case. P3480R6 makes `simd::vec` a range so we can simply flatten it with `views::join` (original example from the paper):

std::vector<std::simd::vec<float>> data;
auto range_of_float = data | std::views::join;

In this case, it makes sense for `join_view` to be `sized_range` because `simd::vec::size()` is a constant expression that can be multiplied by the original `vector` size to get the result size of the `join_view`.

In <ranges>, we use the tiny-range concept to consider types that can obtain static sizes specifically, and `simd::vec` seems to be a good fit.

History
Date User Action Args
2025-10-04 13:39:45adminsetmessages: + msg15120
2025-10-02 00:00:00admincreate