# HG changeset patch
# User Petter Tomner <tomner@kth.se>
# Date 1640689010 -3600
#      Tue Dec 28 11:56:50 2021 +0100
# Node ID df5a5418ac27d27f1d609440eba7c1d70211f30f
# Parent  3feb1a5f196336493e9398d8dbd3129af204002a
interpreter: checkelement_value in Array.h to avoid make_unique

Add checkelement_value to Array to be able to get an element value
without calling make_unique, like const T& operator[](size_t idx),
but this works with non-const Array:s.

Also inline index computations. Benifitial for operator look-up.

Adding branch hint macros OCTAVE_LIKELY and OCTAVE_UNLIKELY,
using __builtin_expect for gcc and clang.

libinterp/octave-value/
	* ov-typeinfo.cc: Use checkelement_value

liboctave/array/
	* Array.cc: Inline compute index
	* Array.h: New checkelem_value, compute_index_inline

/
	* oct-conf-post-public.in.h: Branch hint macros

diff -r 3feb1a5f1963 -r df5a5418ac27 build-aux/mk-octave-config-h.sh
--- a/build-aux/mk-octave-config-h.sh	Sat Dec 25 16:57:16 2021 +0100
+++ b/build-aux/mk-octave-config-h.sh	Tue Dec 28 11:56:50 2021 +0100
@@ -2,7 +2,7 @@
 
 ########################################################################
 ##
-## Copyright (C) 2016-2022 The Octave Project Developers
+## Copyright (C) 2016-2021 The Octave Project Developers
 ##
 ## See the file COPYRIGHT.md in the top-level directory of this
 ## distribution or <https://octave.org/copyright/>.
@@ -43,7 +43,7 @@
 
 ////////////////////////////////////////////////////////////////////////
 //
-// Copyright (C) 2016-2022 The Octave Project Developers
+// Copyright (C) 2016-2021 The Octave Project Developers
 //
 // See the file COPYRIGHT.md in the top-level directory of this
 // distribution or <https://octave.org/copyright/>.
@@ -100,22 +100,215 @@
 #define octave_octave_config_h 1
 
 #if ! defined (OCTAVE_AUTOCONFIG_H_INCLUDED)
+
+#  if defined (__cplusplus)
+#    include <cinttypes>
+#  else
+#    include <inttypes.h>
+#  endif
+
+#  define OCTAVE_NAMESPACE_BEGIN namespace octave {
+#  define OCTAVE_NAMESPACE_END }
+
+#  if defined (__GNUC__)
+#    if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
+#      define OCTAVE_DEPRECATED(ver, msg) __attribute__ ((__deprecated__ ("[" #ver "]: " msg)))
+#    else
+#      define OCTAVE_DEPRECATED(ver, msg) __attribute__ ((__deprecated__))
+#    endif
+#    define OCTAVE_NORETURN __attribute__ ((__noreturn__))
+#    define OCTAVE_UNUSED __attribute__ ((__unused__))
+
+#    define HAVE_OCTAVE_DEPRECATED_ATTR 1
+#    define HAVE_OCTAVE_NORETURN_ATTR 1
+#    define HAVE_OCTAVE_UNUSED_ATTR 1
+#  else
+#    define OCTAVE_DEPRECATED(ver, msg)
+#    define OCTAVE_NORETURN
+#    define OCTAVE_UNUSED
+
+/* #    undef HAVE_OCTAVE_DEPRECATED_ATTR */
+/* #    undef HAVE_OCTAVE_NORETURN_ATTR */
+/* #    undef HAVE_OCTAVE_UNUSED_ATTR */
+#  endif
+
+#  if defined (__MINGW32__)
+    /* MinGW requires special handling due to different format specifiers
+     * on different platforms.  The macro __MINGW_PRINTF_FORMAT maps to
+     * either gnu_printf or ms_printf depending on where we are compiling
+     * to avoid warnings on format specifiers that are legal.
+     * See: https://bugzilla.mozilla.org/show_bug.cgi?id=1331349  */
+#    if defined (__cplusplus)
+#      include <cstdio>
+#    else
+#      include <stdio.h>
+#    endif
+
+#    define OCTAVE_FORMAT_PRINTF(stringIndex, firstToCheck) \
+       __attribute__ ((format (__MINGW_PRINTF_FORMAT, stringIndex, firstToCheck)))
+
+#    define HAVE_OCTAVE_FORMAT_PRINTF_ATTR 1
+#  elif defined (__GNUC__)
+     /* The following attributes are used with gcc and clang compilers.  */
+#    define OCTAVE_FORMAT_PRINTF(index, first) \
+       __attribute__ ((__format__(printf, index, first)))
+
+#    define HAVE_OCTAVE_FORMAT_PRINTF_ATTR 1
+#  else
+#    define OCTAVE_FORMAT_PRINTF(index, first)
+
+/* #    undef HAVE_OCTAVE_FORMAT_PRINTF_ATTR */
+#  endif
+
+#  if ! defined (OCTAVE_FALLTHROUGH)
+#    if defined (__cplusplus) && __cplusplus > 201402L
+#      define OCTAVE_FALLTHROUGH [[fallthrough]]
+#    elif defined (__GNUC__) && __GNUC__ < 7
+#      define OCTAVE_FALLTHROUGH ((void) 0)
+#    else
+#      define OCTAVE_FALLTHROUGH __attribute__ ((__fallthrough__))
+#    endif
+#  endif
+
+/* Branch hint macros for use in if condititions.
+   Returns logical value of x. */
+#  if defined (__GNUC__)
+#    define OCTAVE_LIKELY(x) __builtin_expect(!!(x), 1)
+#  else
+#    define OCTAVE_LIKELY(x) !!(x)
+#  endif
+
+#  if defined (__GNUC__)
+#    define OCTAVE_UNLIKELY(x) __builtin_expect(!!(x), 0)
+#  else
+#    define OCTAVE_UNLIKELY(x) !!(x)
+#  endif
+
+#  define OCTAVE_PROVIDE_DEPRECATED_SYMBOLS 1
+
+#  if defined (__cplusplus)
+template <typename T>
+static inline void
+octave_unused_parameter (const T&)
+{ }
+#  else
+#    define octave_unused_parameter(param) (void) param;
+#  endif
+
+#  if defined (OCTAVE_ENABLE_LIB_VISIBILITY_FLAGS)
+#    if defined (_WIN32) || defined (__CYGWIN__)
+#      if defined (__GNUC__)
+         /* GCC */
+#        define OCTAVE_EXPORT __attribute__ ((dllexport))
+#        define OCTAVE_IMPORT __attribute__ ((dllimport))
+#      else
+         /* MSVC */
+#        define OCTAVE_EXPORT __declspec(dllexport)
+#        define OCTAVE_IMPORT __declspec(dllimport)
+#      endif
+#    else
+       /* All other platforms. */
+#      define OCTAVE_EXPORT __attribute__ ((visibility ("default")))
+#      define OCTAVE_IMPORT
+#    endif
+#  else
+#      define OCTAVE_EXPORT
+#      define OCTAVE_IMPORT
+#  endif
+
+/* API macro for liboctave */
+#if defined (OCTAVE_DLL)
+#  define OCTAVE_API OCTAVE_EXPORT
+#else
+#  define OCTAVE_API OCTAVE_IMPORT
+#endif
+
+/* API macro for libinterp */
+#if defined (OCTINTERP_DLL)
+#  define OCTINTERP_API OCTAVE_EXPORT
+#else
+#  define OCTINTERP_API OCTAVE_IMPORT
+#endif
+
+/* API macro for the Array class in liboctave and liboctinterp */
+#if (defined (OCTAVE_DLL) || defined (OCTINTERP_DLL))
+#  define OCTARRAY_API OCTAVE_EXPORT
+#else
+#  define OCTARRAY_API OCTAVE_IMPORT
+#endif
+
+/* API macro for libinterp/graphics */
+#if defined (OCTGRAPHICS_DLL)
+#  define OCTGRAPHICS_API OCTAVE_EXPORT
+#else
+#  define OCTGRAPHICS_API OCTAVE_IMPORT
+#endif
+
+/* API macro for libgui */
+#if defined (OCTGUI_DLL)
+#  define OCTGUI_API OCTAVE_EXPORT
+#else
+#  define OCTGUI_API OCTAVE_IMPORT
+#endif
 EOF
 
+octave_idx_type="`$SED -n 's/#define OCTAVE_IDX_TYPE \([_a-zA-Z][_a-zA-Z0-9]*\)/\1/p' $config_h_file`"
+
+if test -z "$octave_idx_type"; then
+  echo "mk-octave-config-h.sh: failed to find OCTAVE_IDX_TYPE in $config_h_file" 1>&2
+  exit 1
+fi
+
+octave_f77_int_type="`$SED -n 's/#define OCTAVE_F77_INT_TYPE \([_a-zA-Z][_a-zA-Z0-9]*\)/\1/p' $config_h_file`"
+
+if test -z "$octave_f77_int_type"; then
+  echo "mk-octave-config-h.sh: failed to find OCTAVE_F77_INT_TYPE in $config_h_file" 1>&2
+  exit 1
+fi
+
+cat << EOF
+
+typedef $octave_idx_type octave_idx_type;
+typedef $octave_f77_int_type octave_f77_int_type;
+
+#  define OCTAVE_HAVE_F77_INT_TYPE 1
+
+
+#  if defined (__cplusplus) && ! defined (OCTAVE_THREAD_LOCAL)
+#    define OCTAVE_THREAD_LOCAL
+#  endif
+
+EOF
+
+if grep "#define OCTAVE_ENABLE_FLOAT_TRUNCATE 1" $config_h_file > /dev/null; then
+  echo "#  define OCTAVE_FLOAT_TRUNCATE volatile"
+else
+  echo "#  define OCTAVE_FLOAT_TRUNCATE"
+fi
+
+echo ""
+
 $SED -n 's/#\(\(undef\|define\) OCTAVE_ENABLE_64.*$\)/#  \1/p' $config_h_file
 $SED -n 's/#\(\(undef\|define\) OCTAVE_ENABLE_BOUNDS_CHECK.*$\)/#  \1/p' $config_h_file
-$SED -n 's/#\(\(undef\|define\) OCTAVE_ENABLE_FLOAT_TRUNCATE.*$\)/#  \1/p' $config_h_file
-$SED -n 's/#\(\(undef\|define\) OCTAVE_ENABLE_LIB_VISIBILITY_FLAGS.*$\)/#  \1/p' $config_h_file
 $SED -n 's/#\(\(undef\|define\) OCTAVE_ENABLE_OPENMP.*$\)/#  \1/p' $config_h_file
-$SED -n 's/#\(\(undef\|define\) OCTAVE_F77_INT_TYPE.*$\)/#  \1/p' $config_h_file
 $SED -n 's/#\(\(undef\|define\) OCTAVE_HAVE_LONG_LONG_INT.*$\)/#  \1/p' $config_h_file
-$SED -n 's/#\(\(undef\|define\) OCTAVE_HAVE_OVERLOAD_CHAR_INT8_TYPES.*$\)/#  \1/p' $config_h_file
+$SED -n 's/#\(\(undef\|define\) OCTAVE_HAVE_UNSIGNED_LONG_LONG_INT.*$\)/#  \1/p' $config_h_file
 $SED -n 's/#\(\(undef\|define\) OCTAVE_HAVE_STD_PMR_POLYMORPHIC_ALLOCATOR.*$\)/#  \1/p' $config_h_file
-$SED -n 's/#\(\(undef\|define\) OCTAVE_HAVE_UNSIGNED_LONG_LONG_INT.*$\)/#  \1/p' $config_h_file
-$SED -n 's/#\(\(undef\|define\) OCTAVE_IDX_TYPE.*$\)/#  \1/p' $config_h_file
+$SED -n 's/#\(\(undef\|define\) OCTAVE_HAVE_OVERLOAD_CHAR_INT8_TYPES.*$\)/#  \1/p' $config_h_file
 $SED -n 's/#\(\(undef\|define\) OCTAVE_SIZEOF_F77_INT_TYPE.*$\)/#  \1/p' $config_h_file
 $SED -n 's/#\(\(undef\|define\) OCTAVE_SIZEOF_IDX_TYPE.*$\)/#  \1/p' $config_h_file
 $SED -n 's/#\(\(undef\|define\) OCTAVE_SIZEOF_INT.*$\)/#  \1/p' $config_h_file
+
+cat << EOF
+
+#  if defined (OCTAVE_ENABLE_64)
+#    define OCTAVE_IDX_TYPE_FORMAT PRId64
+#  else
+#    define OCTAVE_IDX_TYPE_FORMAT PRId32
+#  endif
+
+EOF
+
 $SED -n 's/#\(\(undef\|define\) gid_t.*$\)/#  \1/p' $config_h_file
 $SED -n 's/#\(\(undef\|define\) uid_t.*$\)/#  \1/p' $config_h_file
 $SED -n 's/#\(\(undef\|define\) nlink_t.*$\)/#  \1/p' $config_h_file
@@ -184,14 +377,6 @@
 
 cat << EOF
 
-/* Enable inline functions or typedefs that provide access to
-   symbols that have been moved to the octave namespace so that
-   users of Octave may continue to access symbols using the
-   deprecated names.  */
-#  define OCTAVE_PROVIDE_DEPRECATED_SYMBOLS 1
-
-#  include "oct-conf-post-public.h"
-
 #endif
 
 #endif
diff -r 3feb1a5f1963 -r df5a5418ac27 libinterp/octave-value/ov-typeinfo.cc
--- a/libinterp/octave-value/ov-typeinfo.cc	Sat Dec 25 16:57:16 2021 +0100
+++ b/libinterp/octave-value/ov-typeinfo.cc	Tue Dec 28 11:56:50 2021 +0100
@@ -497,42 +497,42 @@
   type_info::unary_class_op_fcn
   type_info::lookup_unary_class_op (octave_value::unary_op op)
   {
-    void *f = m_unary_class_ops.checkelem (static_cast<int> (op));
+    void *f = m_unary_class_ops.checkelem_value (static_cast<int> (op));
     return reinterpret_cast<type_info::unary_class_op_fcn> (f);
   }
 
   type_info::unary_op_fcn
   type_info::lookup_unary_op (octave_value::unary_op op, int t)
   {
-    void *f = m_unary_ops.checkelem (static_cast<int> (op), t);
+    void *f = m_unary_ops.checkelem_value (static_cast<int> (op), t);
     return reinterpret_cast<type_info::unary_op_fcn> (f);
   }
 
   type_info::non_const_unary_op_fcn
   type_info::lookup_non_const_unary_op (octave_value::unary_op op, int t)
   {
-    void *f = m_non_const_unary_ops.checkelem (static_cast<int> (op), t);
+    void *f = m_non_const_unary_ops.checkelem_value (static_cast<int> (op), t);
     return reinterpret_cast<type_info::non_const_unary_op_fcn> (f);
   }
 
   type_info::binary_class_op_fcn
   type_info::lookup_binary_class_op (octave_value::binary_op op)
   {
-    void *f = m_binary_class_ops.checkelem (static_cast<int> (op));
+    void *f = m_binary_class_ops.checkelem_value (static_cast<int> (op));
     return reinterpret_cast<type_info::binary_class_op_fcn> (f);
   }
 
   type_info::binary_op_fcn
   type_info::lookup_binary_op (octave_value::binary_op op, int t1, int t2)
   {
-    void *f = m_binary_ops.checkelem (static_cast<int> (op), t1, t2);
+    void *f = m_binary_ops.checkelem_value (static_cast<int> (op), t1, t2);
     return reinterpret_cast<type_info::binary_op_fcn> (f);
   }
 
   type_info::binary_class_op_fcn
   type_info::lookup_binary_class_op (octave_value::compound_binary_op op)
   {
-    void *f = m_compound_binary_class_ops.checkelem (static_cast<int> (op));
+    void *f =m_compound_binary_class_ops.checkelem_value (static_cast<int> (op));
     return reinterpret_cast<type_info::binary_class_op_fcn> (f);
   }
 
@@ -540,14 +540,15 @@
   type_info::lookup_binary_op (octave_value::compound_binary_op op,
                                int t1, int t2)
   {
-    void *f = m_compound_binary_ops.checkelem (static_cast<int> (op), t1, t2);
+    void *f = m_compound_binary_ops.checkelem_value (static_cast<int> (op),
+                                                     t1, t2);
     return reinterpret_cast<type_info::binary_op_fcn> (f);
   }
 
   type_info::cat_op_fcn
   type_info::lookup_cat_op (int t1, int t2)
   {
-    void *f = m_cat_ops.checkelem (t1, t2);
+    void *f = m_cat_ops.checkelem_value (t1, t2);
     return reinterpret_cast<type_info::cat_op_fcn> (f);
   }
 
@@ -555,27 +556,28 @@
   type_info::lookup_assign_op (octave_value::assign_op op,
                                int t_lhs, int t_rhs)
   {
-    void *f = m_assign_ops.checkelem (static_cast<int> (op), t_lhs, t_rhs);
+    void *f = m_assign_ops.checkelem_value (static_cast<int> (op),
+                                            t_lhs, t_rhs);
     return reinterpret_cast<type_info::assign_op_fcn> (f);
   }
 
   type_info::assignany_op_fcn
   type_info::lookup_assignany_op (octave_value::assign_op op, int t_lhs)
   {
-    void *f = m_assignany_ops.checkelem (static_cast<int> (op), t_lhs);
+    void *f = m_assignany_ops.checkelem_value (static_cast<int> (op), t_lhs);
     return reinterpret_cast<type_info::assignany_op_fcn> (f);
   }
 
   int
   type_info::lookup_pref_assign_conv (int t_lhs, int t_rhs)
   {
-    return m_pref_assign_conv.checkelem (t_lhs, t_rhs);
+    return m_pref_assign_conv.checkelem_value (t_lhs, t_rhs);
   }
 
   octave_base_value::type_conv_fcn
   type_info::lookup_widening_op (int t, int t_result)
   {
-    void *f = m_widening_ops.checkelem (t, t_result);
+    void *f = m_widening_ops.checkelem_value (t, t_result);
     return reinterpret_cast<octave_base_value::type_conv_fcn> (f);
   }
 
diff -r 3feb1a5f1963 -r df5a5418ac27 liboctave/array/Array.cc
--- a/liboctave/array/Array.cc	Sat Dec 25 16:57:16 2021 +0100
+++ b/liboctave/array/Array.cc	Tue Dec 28 11:56:50 2021 +0100
@@ -204,14 +204,14 @@
 T&
 Array<T, Alloc>::checkelem (octave_idx_type i, octave_idx_type j)
 {
-  return elem (compute_index (i, j));
+  return elem (compute_index_inline (i, j));
 }
 
 template <typename T, typename Alloc>
 T&
 Array<T, Alloc>::checkelem (octave_idx_type i, octave_idx_type j, octave_idx_type k)
 {
-  return elem (compute_index (i, j, k));
+  return elem (compute_index_inline (i, j, k));
 }
 
 template <typename T, typename Alloc>
@@ -238,7 +238,7 @@
 typename Array<T, Alloc>::crefT
 Array<T, Alloc>::checkelem (octave_idx_type i, octave_idx_type j) const
 {
-  return elem (compute_index (i, j));
+  return elem (compute_index_inline (i, j));
 }
 
 template <typename T, typename Alloc>
@@ -246,7 +246,7 @@
 Array<T, Alloc>::checkelem (octave_idx_type i, octave_idx_type j,
                      octave_idx_type k) const
 {
-  return elem (compute_index (i, j, k));
+  return elem (compute_index_inline (i, j, k));
 }
 
 template <typename T, typename Alloc>
diff -r 3feb1a5f1963 -r df5a5418ac27 liboctave/array/Array.h
--- a/liboctave/array/Array.h	Sat Dec 25 16:57:16 2021 +0100
+++ b/liboctave/array/Array.h	Tue Dec 28 11:56:50 2021 +0100
@@ -520,6 +520,74 @@
   crefT xelem (const Array<octave_idx_type>& ra_idx) const
   { return xelem (compute_index_unchecked (ra_idx)); }
 
+private:
+  octave_idx_type
+  compute_index_inline (octave_idx_type i, octave_idx_type j,
+                        octave_idx_type k) const
+  {
+    // Unlike compute_index we don't check which dimension that triggers
+    // the error to make the code path smoother.
+    //
+    // compute_index is called when there is any error, to give the
+    // proper error message or when the array does not have 3 dimensions.
+    octave_idx_type dim_0 = m_dimensions (0);
+    octave_idx_type dim_1 = m_dimensions (1);
+
+    octave_idx_type idx = (k*dim_1 + j)*dim_0 + i;
+
+    bool ok = ((m_dimensions.ndims () == 3) && (i >= 0) && (i < dim_0) &&
+               (j >= 0) && (j < dim_1) && (k >= 0) && (k < m_dimensions (2)));
+
+    if (OCTAVE_LIKELY (ok))
+      return idx;
+    else
+      return compute_index (i, j, k); // Called on ndim not 3 or errors
+  }
+
+  octave_idx_type
+  compute_index_inline (octave_idx_type i, octave_idx_type j) const
+  {
+    // Unlike compute_index we don't check which dimension that triggers
+    // the error to make the code path smoother.
+    //
+    // compute_index is called when there is any error, to give the
+    // proper error message or when the array does not have 2 dimension.
+    octave_idx_type dim_0 = m_dimensions (0);
+    octave_idx_type dim_1 = m_dimensions (1);
+
+    octave_idx_type idx = j*dim_0 + i;
+
+    bool ok = ((i >= 0) && (i < dim_0) && (j >= 0) &&
+               (j < dim_1) && (m_dimensions.ndims () == 2));
+
+    if (OCTAVE_LIKELY (ok))
+      return idx;
+    else
+      return compute_index (i, j); // Called on ndim not 2 or errors
+  }
+
+public:
+  T checkelem_value (octave_idx_type i, octave_idx_type j,
+                     octave_idx_type k) const
+  {
+    octave_idx_type idx = compute_index_inline(i, j, k);
+    return m_slice_data[idx];//xelem (idx);
+  }
+
+  T checkelem_value (octave_idx_type i, octave_idx_type j) const
+  {
+    octave_idx_type idx = compute_index_inline(i, j);
+    return xelem (idx);
+  }
+
+  T checkelem_value (octave_idx_type i) const
+  {
+    if (i >= 0 && i < m_slice_len)
+      return xelem (i);
+    else
+      return checkelem (i);
+  }
+
   // FIXME: would be nice to fix this so that we don't unnecessarily force
   //        a copy, but that is not so easy, and I see no clean way to do it.
 
diff -r 3feb1a5f1963 -r df5a5418ac27 oct-conf-post-public.in.h
--- a/oct-conf-post-public.in.h	Sat Dec 25 16:57:16 2021 +0100
+++ b/oct-conf-post-public.in.h	Tue Dec 28 11:56:50 2021 +0100
@@ -104,6 +104,20 @@
 #  endif
 #endif
 
+/* Branch hint macros for use in if condititions.
+   Returns logical value of x. */
+#if defined (__GNUC__)
+#    define OCTAVE_LIKELY(x) __builtin_expect(!!(x),1)
+#else
+#    define OCTAVE_LIKELY(x) !!(x)
+#endif
+
+#if defined (__GNUC__)
+#  define OCTAVE_UNLIKELY(x) __builtin_expect(!!(x),0)
+#else
+#  define OCTAVE_UNLIKELY(x) !!(x)
+#endif
+
 #if defined (__cplusplus)
 template <typename T>
 static inline void
