template<class R, class T>
  concept output_range =
    range<R> && output_iterator<iterator_t<R>, T>;
template<class T>
  concept input_range =
    range<T> && input_iterator<iterator_t<T>>;
template<class T>
  concept forward_range =
    input_range<T> && forward_iterator<iterator_t<T>>;
template<class T>
  concept bidirectional_range =
    forward_range<T> && bidirectional_iterator<iterator_t<T>>;
template<class T>
  concept random_access_range =
    bidirectional_range<T> && random_access_iterator<iterator_t<T>>;
template<class T>
  concept contiguous_range =
    random_access_range<T> && contiguous_iterator<iterator_t<T>> &&
    requires(T& t) {
      { ranges::data(t) } -> same_as<add_pointer_t<range_reference_t<T>>>;
    };