# HG changeset patch
# User Markus Mützel <markus.muetzel@gmx.de>
# Date 1638212564 -3600
#      Mon Nov 29 20:02:44 2021 +0100
# Branch stable
# Node ID 9e80b7ac8e0993b4f6b09ea07ae1d4ebff69c678
# Parent  f3f3e3793fb5d2b10260016c4b545dce31b1ce89
range: Use specialization of init function for octave_int<T> types (bug #61300).

* liboctave/array/Range.h (range<T>::init): Revert to previous base
implementation. Use specialization for octave_int<T> types.
* liboctave/array/Range.cc (xinit<T>): Overload for octave_int<T> types.
(range<T>::init): Implement specializations for octave_int<T> types.

diff -r f3f3e3793fb5 -r 9e80b7ac8e09 liboctave/array/Range.cc
--- a/liboctave/array/Range.cc	Mon Nov 29 10:03:47 2021 -0800
+++ b/liboctave/array/Range.cc	Mon Nov 29 20:02:44 2021 +0100
@@ -253,6 +253,23 @@
   }
 
   template <typename T>
+  void
+  xinit (octave_int<T> base, octave_int<T> limit, octave_int<T> inc,
+         octave_int<T>& final_val, octave_idx_type& nel)
+  {
+      // We need an integer division that is truncating decimals instead of
+      // rounding.  So, use underlying C++ types instead of octave_int<T>.
+      // FIXME: The numerator might underflow or overflow. Add checks for that.
+      nel = ((inc == octave_int<T> (0)
+             || (limit > base && inc < octave_int<T> (0))
+             || (limit < base && inc > octave_int<T> (0)))
+            ? 0
+            : (limit.value () - base.value () + inc.value ()) / inc.value ());
+
+      final_val = base + (nel - 1) * inc;
+    }
+
+  template <typename T>
   bool
   xis_storable (T base, T limit, octave_idx_type nel)
   {
@@ -288,6 +305,62 @@
   }
 
   template <>
+  void
+  range<octave_int8>::init (void)
+  {
+    return xinit (m_base, m_limit, m_increment, m_final, m_numel);
+  }
+
+  template <>
+  void
+  range<octave_int16>::init (void)
+  {
+    return xinit (m_base, m_limit, m_increment, m_final, m_numel);
+  }
+
+  template <>
+  void
+  range<octave_int32>::init (void)
+  {
+    return xinit (m_base, m_limit, m_increment, m_final, m_numel);
+  }
+
+  template <>
+  void
+  range<octave_int64>::init (void)
+  {
+    return xinit (m_base, m_limit, m_increment, m_final, m_numel);
+  }
+
+  template <>
+  void
+  range<octave_uint8>::init (void)
+  {
+    return xinit (m_base, m_limit, m_increment, m_final, m_numel);
+  }
+
+  template <>
+  void
+  range<octave_uint16>::init (void)
+  {
+    return xinit (m_base, m_limit, m_increment, m_final, m_numel);
+  }
+
+  template <>
+  void
+  range<octave_uint32>::init (void)
+  {
+    return xinit (m_base, m_limit, m_increment, m_final, m_numel);
+  }
+
+  template <>
+  void
+  range<octave_uint64>::init (void)
+  {
+    return xinit (m_base, m_limit, m_increment, m_final, m_numel);
+  }
+
+  template <>
   bool
   range<double>::is_storable (void) const
   {
diff -r f3f3e3793fb5 -r 9e80b7ac8e09 liboctave/array/Range.h
--- a/liboctave/array/Range.h	Mon Nov 29 10:03:47 2021 -0800
+++ b/liboctave/array/Range.h	Mon Nov 29 20:02:44 2021 +0100
@@ -323,15 +323,11 @@
 
     void init (void)
     {
-      // We need an integer division that is truncating decimals instead of
-      // rounding.  So, use underlying C++ types instead of octave_int<T>.
-      // FIXME: The numerator might underflow or overflow. Add checks for that.
       m_numel = ((m_increment == T (0)
                   || (m_limit > m_base && m_increment < T (0))
                   || (m_limit < m_base && m_increment > T (0)))
-                 ? 0
-                 : (m_limit.value () - m_base.value () + m_increment.value ())
-                   / m_increment.value ());
+                 ? T (0)
+                 : (m_limit - m_base + m_increment) / m_increment.value ());
 
       m_final = m_base + (m_numel - 1) * m_increment;
     }
@@ -344,6 +340,14 @@
 
   template <> OCTAVE_API void range<double>::init (void);
   template <> OCTAVE_API void range<float>::init (void);
+  template <> OCTAVE_API void range<octave_int8>::init (void);
+  template <> OCTAVE_API void range<octave_int16>::init (void);
+  template <> OCTAVE_API void range<octave_int32>::init (void);
+  template <> OCTAVE_API void range<octave_int64>::init (void);
+  template <> OCTAVE_API void range<octave_uint8>::init (void);
+  template <> OCTAVE_API void range<octave_uint16>::init (void);
+  template <> OCTAVE_API void range<octave_uint32>::init (void);
+  template <> OCTAVE_API void range<octave_uint64>::init (void);
 
   template <> OCTAVE_API bool range<double>::is_storable (void) const;
   template <> OCTAVE_API bool range<float>::is_storable (void) const;
