VCCC  2024.05
VisualCamp Common C++ library
join_with_view.hpp
Go to the documentation of this file.
1 //
2 // Created by yonggyulee on 2/13/24.
3 //
4 
5 #ifndef VCCC_RANGES_VIEWS_JOIN_WITH_VIEW_HPP_
6 #define VCCC_RANGES_VIEWS_JOIN_WITH_VIEW_HPP_
7 
8 #include <type_traits>
9 #include <utility>
10 
21 #include "vccc/__ranges/begin.hpp"
25 #include "vccc/__ranges/end.hpp"
35 #include "vccc/__ranges/view.hpp"
45 #include "vccc/variant.hpp"
46 
47 namespace vccc {
48 namespace ranges {
49 namespace detail {
50 
51 template<typename RRef, typename Pattern>
52 using join_with_compatible = conjunction<
53  common_with<range_value_t<RRef>, range_value_t<Pattern>>,
54  common_reference_with<range_reference_t<RRef>, range_reference_t<Pattern>>,
55  common_reference_with<range_rvalue_reference_t<RRef>, range_rvalue_reference_t<Pattern>>
56  >;
57 
59 class join_with_view_base : public view_interface<Derived> {
60  struct cache_wrapper {
61  template <typename I>
62  constexpr cache_wrapper(const I& i) noexcept(
63  std::is_nothrow_constructible<non_propagating_cache<cache_wrapper>, decltype(*i)>::value)
64  : val(*i) {}
65 
66  std::remove_cv_t<range_reference_t<V>> val;
67  };
68  protected:
69  non_propagating_cache<cache_wrapper> inner_base_{};
70 };
71 
72 template<typename V, typename Pattern, typename Derived>
73 class join_with_view_base<V, Pattern, Derived, false> : public join_with_view_base<V, Pattern, Derived, true> {
74  protected:
75  non_propagating_cache<iterator_t<V>> outer_it_{};
76 };
77 
78 
79 template<typename Base, typename InnerBase, typename PatternBase>
80 struct join_with_view_iterator_concept {
81  using iterator_concept =
82  std::conditional_t<
83  conjunction<
84  has_typename_type<range_reference<Base>>,
85  std::is_reference<range_reference_t<Base>>,
86  bidirectional_range<Base>,
87  bidirectional_range<InnerBase>,
88  bidirectional_range<PatternBase>,
89  common_range<InnerBase>,
90  common_range<PatternBase>
92  std::conditional_t<
93  conjunction<
94  has_typename_type<range_reference<Base>>,
95  std::is_reference<range_reference_t<Base>>,
96  forward_range<InnerBase>,
97  forward_range<PatternBase>
100  >>;
101 };
102 
103 template<typename Base, typename InnerBase, typename PatternBase,
104  typename IterConcept = join_with_view_iterator_concept<Base, InnerBase, PatternBase>>
105 struct join_with_view_iterator_category
106  : join_with_view_iterator_concept<Base, InnerBase, PatternBase>
107 {
108  // iterator_category is defined iif IterConcept denotes forward_iterator_tag
109 #if __cplusplus < 202002L
110  using iterator_category = iterator_ignore;
111 #endif
112 };
113 
114 template<typename Base, typename InnerBase, typename PatternBase>
115 struct join_with_view_iterator_category<Base, InnerBase, PatternBase, forward_iterator_tag>
116  : join_with_view_iterator_concept<Base, InnerBase, PatternBase>
117 {
118  private:
119  using OuterC = typename cxx20_iterator_traits<iterator_t<Base>>::iterator_category;
120  using InnerC = typename cxx20_iterator_traits<iterator_t<InnerBase>>::iterator_category;
121  using PatternC = typename cxx20_iterator_traits<iterator_t<PatternBase>>::iterator_category;
122 
123  public:
124  using iterator_category =
125  std::conditional_t<
126  negation<std::is_reference<
127  common_reference_t<range_reference_t<InnerBase>, range_reference_t<PatternBase>>
128  >>::value,
130  std::conditional_t<
131  conjunction<
132  derived_from<OuterC, bidirectional_iterator_tag>,
133  derived_from<InnerC, bidirectional_iterator_tag>,
134  derived_from<PatternC, bidirectional_iterator_tag>,
135  common_range<range_reference_t<Base>>,
136  common_range<PatternBase>
137  >::value,
139  std::conditional_t<
140  conjunction<
141  derived_from<OuterC, forward_iterator_tag>,
142  derived_from<InnerC, forward_iterator_tag>,
143  derived_from<PatternC, forward_iterator_tag>
144  >::value,
147  >>>;
148 };
149 
151 class join_with_view_iterator_base : public join_with_view_iterator_category<Base, InnerBase, PatternBase> {};
152 
153 template<typename Base, typename InnerBase, typename PatternBase>
154 class join_with_view_iterator_base<Base, InnerBase, PatternBase, true>
155  : public join_with_view_iterator_category<Base, InnerBase, PatternBase>
156 {
157  protected:
158  join_with_view_iterator_base() = default;
159 
160  constexpr explicit join_with_view_iterator_base(iterator_t<Base>&& outer_it)
161  : outer_it_(std::move(outer_it)) {}
162 
163  iterator_t<Base> outer_it_{};
164 };
165 
166 } // namespace detail
167 
170 
171 // Part of implementations are taken from MSVC
172 template<typename V, typename Pattern>
173 class join_with_view : public detail::join_with_view_base<V, Pattern, join_with_view<V, Pattern>> {
174  public:
175  static_assert(input_range<V>::value, "Constraints not satisfied");
176  static_assert(forward_range<Pattern>::value, "Constraints not satisfied");
177  static_assert(view<V>::value, "Constraints not satisfied");
178  static_assert(input_range<range_reference_t<V>>::value, "Constraints not satisfied");
179  static_assert(view<Pattern>::value, "Constraints not satisfied");
180  static_assert(detail::join_with_compatible<range_reference_t<V>, Pattern>::value, "Constraints not satisfied");
181 
182  template<bool Const> class iterator;
183  template<bool Const> friend class iterator;
184  template<bool Const> class sentinel;
185  template<bool Const> friend class sentinel;
186 
187  template<bool Const>
188  class iterator
189  : public detail::join_with_view_iterator_base<
190  maybe_const<Const, V>,
191  range_reference_t<maybe_const<Const, V>>,
192  maybe_const<Const, Pattern>>
193  {
194  using iterator_base = detail::join_with_view_iterator_base<
198 
199  friend class join_with_view;
200  template<bool OtherConst> friend class sentinel;
201 
202  using Parent = maybe_const<Const, join_with_view>;
203  using Base = maybe_const<Const, V>;
204  using InnerBase = range_reference_t<Base>;
205  using PatternBase = maybe_const<Const, Pattern>;
206 
207  using OuterIter = iterator_t<Base>;
208  using InnerIter = iterator_t<InnerBase>;
209  using PatternIter = iterator_t<PatternBase>;
210 
211  public:
217 #if __cplusplus < 202002L
218  using pointer = void;
220 #endif
221 
222  iterator() = default;
223 
224  template<bool AntiConst, std::enable_if_t<conjunction<
225  bool_constant<((Const != AntiConst) && Const)>,
229  >::value, int> = 0>
231  : iterator_base(std::move(i.outer_it_)), parent_(i.parent_) {
232  switch (i.inner_it_.index()) {
233  case 0:
234  inner_it_.template emplace<0>(std::move(
235  vccc::detail::variant_raw_get(i.inner_it_._base().union_, in_place_index<0>)));
236  break;
237  case 1:
238  inner_it_.template emplace<1>(std::move(
239  vccc::detail::variant_raw_get(i.inner_it_._base().union_, in_place_index<1>)));
240  break;
241  default:
242  throw bad_variant_access{};
243  }
244  }
245 
246  constexpr decltype(auto) operator*() const {
248  return inner_it_.visit([](auto&& it) -> reference { return *it; });
249  }
250 
251  constexpr iterator& operator++() {
252  inner_it_.visit([](auto& it) { ++it; });
253  satisfy();
254  return *this;
255  }
256 
257  template<typename IB = InnerBase, std::enable_if_t<conjunction<
258  std::is_reference<IB>,
261  >::value == false, int> = 0>
262  constexpr void operator++(int) {
263  ++*this;
264  }
265 
266  template<typename IB = InnerBase, std::enable_if_t<conjunction<
267  std::is_reference<IB>,
270  >::value, int> = 0>
271  constexpr iterator operator++(int) {
272  auto tmp = *this;
273  ++*this;
274  return tmp;
275  }
276 
277  template<typename IB = InnerBase, std::enable_if_t<conjunction<
278  std::is_reference<IB>,
284  >::value, int> = 0>
285  constexpr iterator& operator--() {
286  using namespace vccc::rel_ops;
287 
288  auto& outer_it = get_outer();
289  if (outer_it == ranges::end(parent_->base_)) {
290  --outer_it;
291  inner_it_.template emplace<1>(ranges::end(get_inner()));
292  }
293 
294  for (;;) {
295  if (inner_it_.index() == 0) {
296  auto& it = vccc::detail::variant_raw_get(inner_it_._base().union_, in_place_index<0>);
297  if (it == ranges::begin(parent_->pattern_)) {
298  --outer_it;
299  inner_it_.template emplace<1>(ranges::end(get_inner()));
300  } else {
301  break;
302  }
303  } else if (inner_it_.index() == 1) {
304  auto& it = vccc::detail::variant_raw_get(inner_it_._base().union_, in_place_index<1>);
305  if (it == ranges::begin(get_inner())) {
306  inner_it_.template emplace<0>(ranges::end(parent_->pattern_));
307  } else {
308  break;
309  }
310  } else {
311  throw bad_variant_access{};
312  }
313  }
314 
315  inner_it_.visit([](auto& it) { --it; });
316  return *this;
317  }
318 
319 
320  template<typename IB = InnerBase, std::enable_if_t<conjunction<
321  std::is_reference<IB>,
327  >::value, int> = 0>
328  constexpr iterator operator--(int) {
329  auto tmp = *this;
330  --*this;
331  return tmp;
332  }
333 
334  template<typename IB = InnerBase, std::enable_if_t<conjunction<
335  std::is_reference<IB>,
338  >::value, int> = 0>
339  friend constexpr bool operator==(const iterator& x, const iterator& y) {
340  if (x.outer_it_ != y.outer_it_) {
341  return false;
342  }
343 
344  return x.inner_it_ == y.inner_it_;
345  }
346 
347  template<typename IB = InnerBase, std::enable_if_t<conjunction<
348  std::is_reference<IB>,
351  >::value, int> = 0>
352  friend constexpr bool operator!=(const iterator& x, const iterator& y) {
353  return !(x == y);
354  }
355 
356  friend constexpr decltype(auto) iter_move(const iterator& i) {
358  return i.inner_it_.visit([](auto&& i) -> R {
359  return ranges::iter_move(std::forward<decltype(i)>(i));
360  });
361  }
362 
363  template<typename IS = indirectly_swappable<iterator_t<InnerBase>, iterator_t<PatternBase>>, std::enable_if_t<IS::value, int> = 0>
364  friend constexpr void iter_swap(const iterator& x, const iterator& y) {
365  vccc::visit(ranges::iter_swap, x.inner_it_, y.inner_it_);
366  }
367 
368  private:
370  constexpr iterator(Parent& parent, iterator_t<Base> outer_it)
371  : iterator_base(std::move(outer_it)), parent_(vccc::addressof(parent))
372  {
373  using namespace vccc::rel_ops;
374  if (this->outer_it_ != ranges::end(parent_->base_)) {
375  inner_it_.template emplace<1>(ranges::begin(update_inner()));
376  satisfy();
377  }
378  }
379 
381  constexpr iterator(Parent& parent)
382  : parent_(vccc::addressof(parent))
383  {
384  using namespace vccc::rel_ops;
385  if (*parent_->outer_it_ != ranges::end(parent_->base_)) {
386  inner_it_.template emplace<1>(ranges::begin(update_inner()));
387  satisfy();
388  }
389  }
390 
392  constexpr iterator_t<Base>& get_outer() noexcept {
393  return this->outer_it_;
394  }
395 
397  constexpr iterator_t<Base>& get_outer() noexcept {
398  return *parent_->outer_it_;
399  }
400 
402  constexpr const iterator_t<Base>& get_outer() const noexcept {
403  return this->outer_it_;
404  }
405 
407  constexpr const iterator_t<Base>& get_outer() const noexcept {
408  return *parent_->outer_it_;
409  }
410 
412  constexpr decltype(auto) update_inner() {
413  return *get_outer();
414  }
415 
417  constexpr decltype(auto) update_inner() {
418  return parent_->inner_base_.emplace_deref(get_outer()).val;
419  }
420 
422  constexpr decltype(auto) get_inner() noexcept {
423  return *get_outer();
424  }
425 
427  constexpr decltype(auto) get_inner() noexcept {
428  return *parent_->inner_base_.val;
429  }
430 
431  constexpr void satisfy() {
432  using namespace vccc::rel_ops;
433 
434  for (;;) {
435  if (inner_it_.index() == 0) {
436  if (vccc::detail::variant_raw_get(inner_it_._base().union_, in_place_index<0>) != ranges::end(parent_->pattern_)) {
437  break;
438  }
439 
440  inner_it_.template emplace<1>(ranges::begin(update_inner()));
441  } else {
442  if (vccc::detail::variant_raw_get(inner_it_._base().union_, in_place_index<1>) != ranges::end(get_inner())) {
443  break;
444  }
445 
446  auto& outer_it = get_outer();
447  ++outer_it;
448  if (outer_it == ranges::end(parent_->base_)) {
449  emplace_first_or_not();
450  break;
451  }
452 
453  inner_it_.template emplace<0>(ranges::begin(parent_->pattern_));
454  }
455  }
456  }
457 
459  constexpr void emplace_first_or_not() {
460  inner_it_.template emplace<0>();
461  }
462 
464  constexpr void emplace_first_or_not() { /* no op */ }
465 
466  Parent* parent_{};
467  variant<iterator_t<PatternBase>, iterator_t<InnerBase>> inner_it_{};
468  };
469 
470  template<bool Const>
471  class sentinel {
472  friend class join_with_view;
473 
474  using Parent = maybe_const<Const, join_with_view>;
475  using Base = maybe_const<Const, V>;
476 
477  public:
478  sentinel() = default;
479 
480  template<bool AntiConst, std::enable_if_t<conjunction<
481  bool_constant<((Const != AntiConst) && Const)>,
483  >::value, int> = 0>
485  : end_(std::move(i.end_)) {}
486 
487  friend constexpr bool operator==(const iterator<Const>& x, const sentinel& y) {
488  return y.equal(x);
489  }
490 
491  friend constexpr bool operator!=(const iterator<Const>& x, const sentinel& y) {
492  return !(x == y);
493  }
494 
495  friend constexpr bool operator==(const sentinel& y, const iterator<Const>& x) {
496  return y.equal(x);
497  }
498 
499  friend constexpr bool operator!=(const sentinel& y, const iterator<Const>& x) {
500  return !(x == y);
501  }
502 
503  private:
504  constexpr explicit sentinel(Parent& parent)
505  : end_(ranges::end(parent.base_)) {}
506 
507  constexpr bool equal(const iterator<Const>& x) const {
508  using namespace vccc::rel_ops;
509  return x.get_outer() == end_;
510  }
511 
512  sentinel_t<Base> end_{};
513  };
514 
515  join_with_view() = default;
516 
517  constexpr explicit join_with_view(V base, Pattern pattern)
518  : base_(std::move(base)), pattern_(std::move(pattern)) {}
519 
520  template<typename R, std::enable_if_t<conjunction<
523  >::value, int> = 0>
525  : base_(views::all(std::forward<R>(r))), pattern_(views::single(std::move(e))) {}
526 
527 
529  constexpr V base() const& {
530  return base_;
531  }
532 
533  constexpr V base() && {
534  return std::move(base_);
535  }
536 
538  constexpr auto begin() {
539  using Const = conjunction<
542  std::is_reference<range_reference_t<V2>>
543  >;
544  return iterator<Const::value>{*this, ranges::begin(base_)};
545  }
546 
548  constexpr iterator<false> begin() {
549  this->outer_it_.emplace(ranges::begin(base_));
550  return iterator<false>{*this};
551  }
552 
553  template<typename V2 = V, std::enable_if_t<conjunction<
556  std::is_reference<range_reference_t<const V2>>
557  >::value, int> = 0>
558  constexpr iterator<true> begin() const {
559  return iterator<true>{*this, ranges::begin(base_)};
560  }
561 
562  template<typename V2 = V, std::enable_if_t<conjunction<
564  std::is_reference<range_reference_t<V2>>,
568  >::value, int> = 0>
569  constexpr auto end() {
571  return iterator<simple::value>{*this, ranges::end(base_)};
572  }
573 
574  template<typename V2 = V, std::enable_if_t<conjunction<
576  std::is_reference<range_reference_t<V2>>,
580  >::value == false, int> = 0>
581  constexpr auto end() {
583  return sentinel<simple::value>{*this};
584  }
585 
586  template<typename V2 = V, std::enable_if_t<conjunction<
589  std::is_reference<range_reference_t<const V2>>
590  >::value, int> = 0>
591  constexpr auto end() const {
592  return end_impl(conjunction<
596  >{});
597  }
598 
599  private:
600  constexpr auto end_impl(std::true_type) const {
601  return iterator<true>{*this, ranges::end(base_)};
602  }
603  constexpr auto end_impl(std::false_type) const {
604  return sentinel<true>{*this};
605  }
606 
607  V base_;
608  Pattern pattern_;
609 };
610 
611 #if __cplusplus >= 201703L
612 
613 template<typename R, typename P>
614 join_with_view(R&&, P&&) -> join_with_view<views::all_t<R>, views::all_t<P>>;
615 
616 template<typename R>
617 join_with_view(R&&, range_value_t<range_reference_t<R>>)
618  -> join_with_view<views::all_t<R>, single_view<range_value_t<range_reference_t<R>>>>;
619 
620 #endif
621 
623 
624 } // namespace ranges
625 } // namespace vccc
626 
627 #endif // VCCC_RANGES_VIEWS_JOIN_WITH_VIEW_HPP_
Definition: bad_variant_access.hpp:15
Definition: join_with_view.hpp:193
constexpr iterator & operator--()
Definition: join_with_view.hpp:285
common_type_t< range_difference_t< Base >, range_difference_t< InnerBase >, range_difference_t< PatternBase > > difference_type
Definition: join_with_view.hpp:216
void pointer
Definition: join_with_view.hpp:218
constexpr friend void iter_swap(const iterator &x, const iterator &y)
Definition: join_with_view.hpp:364
constexpr void operator++(int)
Definition: join_with_view.hpp:262
constexpr iterator(iterator< AntiConst > i)
Definition: join_with_view.hpp:230
constexpr friend bool operator==(const iterator &x, const iterator &y)
Definition: join_with_view.hpp:339
constexpr friend bool operator!=(const iterator &x, const iterator &y)
Definition: join_with_view.hpp:352
common_type_t< range_value_t< InnerBase >, range_value_t< PatternBase > > value_type
Definition: join_with_view.hpp:212
friend class sentinel
Definition: join_with_view.hpp:200
common_reference_t< range_reference_t< InnerBase >, range_reference_t< PatternBase > > reference
Definition: join_with_view.hpp:219
constexpr iterator operator--(int)
Definition: join_with_view.hpp:328
friend class join_with_view
Definition: join_with_view.hpp:199
constexpr iterator operator++(int)
Definition: join_with_view.hpp:271
constexpr iterator & operator++()
Definition: join_with_view.hpp:251
constexpr decltype(auto) friend iter_move(const iterator &i)
Definition: join_with_view.hpp:356
Definition: join_with_view.hpp:471
constexpr sentinel(sentinel< AntiConst > i)
Definition: join_with_view.hpp:484
constexpr friend bool operator==(const sentinel &y, const iterator< Const > &x)
Definition: join_with_view.hpp:495
constexpr friend bool operator==(const iterator< Const > &x, const sentinel &y)
Definition: join_with_view.hpp:487
constexpr friend bool operator!=(const iterator< Const > &x, const sentinel &y)
Definition: join_with_view.hpp:491
constexpr friend bool operator!=(const sentinel &y, const iterator< Const > &x)
Definition: join_with_view.hpp:499
Definition: join_with_view.hpp:173
constexpr V base() const &
Definition: join_with_view.hpp:529
constexpr join_with_view(V base, Pattern pattern)
Definition: join_with_view.hpp:517
constexpr V base() &&
Definition: join_with_view.hpp:533
constexpr auto end()
Definition: join_with_view.hpp:569
constexpr join_with_view(R &&r, range_value_t< range_reference_t< V >> e)
Definition: join_with_view.hpp:524
constexpr auto end() const
Definition: join_with_view.hpp:591
constexpr iterator< true > begin() const
Definition: join_with_view.hpp:558
constexpr iterator< false > begin()
Definition: join_with_view.hpp:548
constexpr auto begin()
Definition: join_with_view.hpp:538
constexpr std::size_t index() const noexcept
Definition: variant.hpp:662
constexpr decltype(auto) visit(Visitor &&vis) &
Definition: variant.hpp:707
constexpr VCCC_INLINE_OR_STATIC detail::equal_niebloid equal
Two ranges are considered equal if they have the same number of elements and every pair of correspond...
Definition: equal.hpp:142
constexpr VCCC_INLINE_OR_STATIC detail_iter_move::iter_move_niebloid iter_move
Definition: iter_move.hpp:92
constexpr VCCC_INLINE_OR_STATIC detail_iter_swap::iter_swap_niebloid iter_swap
Definition: iter_swap.hpp:90
std::forward_iterator_tag forward_iterator_tag
Definition: iterator_tag.hpp:17
std::input_iterator_tag input_iterator_tag
Definition: iterator_tag.hpp:15
std::bidirectional_iterator_tag bidirectional_iterator_tag
Definition: iterator_tag.hpp:18
constexpr T e
the mathematical constant
Definition: constants.hpp:37
std::enable_if_t< std::is_object< T >::value, T * > addressof(T &t) noexcept
Definition: addressof.hpp:33
constexpr VCCC_INLINE_OR_STATIC detail::single_niebloid single
Definition: single.hpp:104
typename sentinel< R >::type sentinel_t
Definition: sentinel_t.hpp:29
typename ranges::iterator< T >::type iterator_t
Definition: iterator_t.hpp:32
constexpr VCCC_INLINE_OR_STATIC detail::begin_niebloid begin
returns an iterator to the beginning of a range
Definition: begin.hpp:116
typename range_rvalue_reference< R >::type range_rvalue_reference_t
Used to obtain the rvalue reference type of the iterator type of range type R.
Definition: range_rvalue_reference_t.hpp:38
constexpr VCCC_INLINE_OR_STATIC detail::end_niebloid end
returns a sentinel indicating the end of a range
Definition: end.hpp:120
typename range_difference< R >::type range_difference_t
Used to obtain the difference type of the iterator type of range type R.
Definition: range_difference_t.hpp:41
typename range_reference< R >::type range_reference_t
Used to obtain the reference type of the iterator type of range type R.
Definition: range_reference_t.hpp:42
constexpr VCCC_INLINE_OR_STATIC detail::all_adaptor_closure all
a view that includes all elements of a range
Definition: all.hpp:82
typename range_value< R >::type range_value_t
Used to obtain the value type of the iterator type of range type R.
Definition: range_value_t.hpp:42
std::integral_constant< bool, v > bool_constant
Definition: bool_constant.hpp:19
typename common_reference< T... >::type common_reference_t
Definition: common_reference.hpp:54
typename common_type< T... >::type common_type_t
Definition: common_type.hpp:229
std::conditional_t< Const, const V, V > maybe_const
Definition: maybe_const.hpp:16
constexpr R visit(Visitor &&vis, Variants &&... vars)
Definition: visit.hpp:93
Definition: matrix.hpp:495
Definition: cxx20_rel_ops.hpp:17
Definition: directory.h:12
constexpr VCCC_INLINE_OR_STATIC detail::element_niebloid< 1 > value
Definition: key_value.hpp:35
Definition: conjunction.hpp:22
specifies that a variable of the type can be constructed from or bound to a set of argument types
Definition: constructible_from.hpp:31
Models std::convertible_to
Definition: convertible_to.hpp:38
specifies that operator == is an equivalence relation
Definition: equality_comparable.hpp:30
specifies that an input_iterator is a forward iterator, supporting equality comparison and multi-pass
Definition: forward_iterator.hpp:53
specifies a range whose iterator type satisfies bidirectional_iterator
Definition: bidirectional_range.hpp:49
Definition: common_range.hpp:41
specifies a range whose iterator type satisfies forward_iterator
Definition: forward_range.hpp:47
specifies a range whose iterator type satisfies input_iterator
Definition: input_range.hpp:46
Definition: simple_view.hpp:28
specifies that a range is a view, that is, it has constant time copy/move/assignment
Definition: view.hpp:31