diff -r 9cbec01f1aae liboctave/util/tiny_vector.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/util/tiny_vector.h	Sun Feb 26 11:47:08 2023 -0500
@@ -0,0 +1,437 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 1996-2021 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if ! defined (tiny_vector_h)
+#define tiny_vector_h 1
+
+#include <vector>
+#include <cstddef>
+#include <initializer_list>
+
+namespace octave
+{
+  // tiny_vector is a vector container where the initial N elements
+  // are stored in the tiny_vector object itself. After N + 1 elements
+  // has been added, all the elements are stored on the heap.
+  //
+  // In this way, usage of malloc/free can be limited to cases where there
+  // is a need for a big vector.
+  //
+  // Constructors etc. resembles std::vector
+  //
+  template <class T, size_t N = sizeof (std::vector<T>) / sizeof (T)>
+  class tiny_vector
+  {
+  public:
+    static constexpr size_t n_tiny = N;
+
+    tiny_vector () {};
+
+    tiny_vector (size_t count)
+    {
+      if (count > n_tiny)
+        {
+          new (&m_data.m_vec) std::vector<T> (count);
+          m_tag = -1;
+        }
+      else
+        {
+          for (unsigned i = 0; i < count; i++)
+            new (&m_data.m_arr[i]) T;
+          m_tag = count;
+        }
+    }
+
+    tiny_vector (size_t count, const T& val)
+    {
+      if (count > n_tiny)
+        {
+          new (&m_data.m_vec) std::vector<T> (count, val);
+
+          m_tag = -1;
+        }
+      else
+        {
+          for (unsigned i = 0; i < count; i++)
+            new (&m_data.m_arr[i]) T (val);
+          m_tag = count;
+        }
+    }
+
+    tiny_vector (typename std::initializer_list<T>::const_iterator beg,
+                 typename std::initializer_list<T>::const_iterator end)
+    {
+      size_t count = end - beg;
+      if (count > n_tiny)
+        {
+          new (&m_data.m_vec) std::vector<T> (beg, end);
+          // Set the tag to indicate vector usage
+          m_tag = -1;
+        }
+      else
+        {
+          for (unsigned i = 0; i < count; i++)
+            new (&m_data.m_arr[i]) T (*beg++);
+          m_tag = count;
+        }
+    }
+
+    tiny_vector (const tiny_vector &tovv)
+    {
+      if (tovv.m_tag >= 0)
+        {
+          for (int i = 0; i < tovv.m_tag; i++)
+            new (&m_data.m_arr[i]) T(tovv.m_data.m_arr[i]);
+          m_tag = tovv.m_tag;
+        }
+      else
+        {
+          new (&m_data.m_vec) std::vector<T> (tovv.m_data.m_vec);
+          // Set the tag to indicate vector usage
+          m_tag = -1;
+        }
+    }
+
+    template<class iter> //TODO: Fix to T::const_iterator
+    tiny_vector (const iter begin,
+                 const iter end)
+    {
+      // The iterators does not have to support taking the difference
+      // so we just use vector for this
+      new (&m_data.m_vec) std::vector<T> (begin, end);
+      // Set the tag to indicate vector usage
+      m_tag = -1;
+    }
+
+    ~tiny_vector ()
+    {
+      if (m_tag < 0)
+        {
+          m_data.m_vec.~vector ();
+        }
+      else
+        {
+          for (int i = 0; i < m_tag; i++)
+            m_data.m_arr [i].~T ();
+        }
+    }
+
+    bool empty () const
+    {
+      if (m_tag >= 0)
+        return m_tag == 0;
+      else
+        return m_data.m_vec.empty ();
+    }
+
+    size_t size () const
+    {
+      if (m_tag >= 0)
+        return m_tag;
+      else
+        return m_data.m_vec.size ();
+    }
+
+    void clear ()
+    {
+      if (m_tag >= 0)
+        {
+          // Destroy old elements
+          for (int i = 0; i < m_tag; i++)
+            m_data.m_arr[i].~T ();
+
+          m_tag = 0;
+        }
+      else
+        return m_data.m_vec.clear ();
+    }
+
+    const T* begin () const
+    {
+      if (m_tag >= 0)
+        return &m_data.m_arr[0];
+      else
+        return m_data.m_vec.data ();
+    }
+
+    T* begin ()
+    {
+      if (m_tag >= 0)
+        return &m_data.m_arr[0];
+      else
+        return m_data.m_vec.data ();
+    }
+
+    const T* end () const
+    {
+      if (m_tag >= 0)
+        return &m_data.m_arr[m_tag];
+      else
+        return m_data.m_vec.data () + m_data.m_vec.size ();
+    }
+
+    T* end ()
+    {
+      if (m_tag >= 0)
+        return &m_data.m_arr[m_tag];
+      else
+        return m_data.m_vec.data () + m_data.m_vec.size ();
+    }
+
+    tiny_vector& operator=(tiny_vector &&tovv)
+    {
+      if (m_tag >= 0 && tovv.m_tag >= 0)
+        {
+          // Destroy old elements
+          for (int i = 0; i < m_tag; i++)
+            m_data.m_arr[i].~T ();
+
+          // Construct elements
+          for (int i = 0; i < tovv.m_tag; i++)
+            new (&m_data.m_arr[i]) T(tovv.m_data.m_arr[i]);
+
+          m_tag = tovv.m_tag;
+
+          return *this;
+        }
+      else if (m_tag < 0 && tovv.m_tag < 0)
+        {
+          m_data.m_vec = tovv.m_data.m_vec;
+          m_tag = -1;
+          return *this;
+        }
+      else if (m_tag >= 0 && tovv.m_tag < 0)
+        {
+          // Destroy elements
+          for (int i = 0; i < m_tag; i++)
+            m_data.m_arr[i].~T ();
+
+          // Construct the vector in the union
+          new (&m_data.m_vec) std::vector<T> (tovv.m_data.m_vec);
+
+          //Mark for vector usage
+          m_tag = -1;
+
+          return *this;
+        }
+      else // (m_tag < 0 && tovv.m_tag >= 0)
+        {
+          m_data.m_vec.resize (tovv.m_tag);
+          for (int i = 0; i < tovv.m_tag; i++)
+            m_data.m_vec[i] = tovv.m_data.m_arr[i];
+
+          return *this;
+        }
+    }
+
+    tiny_vector& operator=(const tiny_vector &tovv)
+    {
+      if (m_tag >= 0 && tovv.m_tag >= 0)
+        {
+          // Destroy old elements
+          for (int i = 0; i < m_tag; i++)
+            m_data.m_arr[i].~T ();
+
+          // Construct elements
+          for (int i = 0; i < tovv.m_tag; i++)
+            new (&m_data.m_arr[i]) T(tovv.m_data.m_arr[i]);
+
+          m_tag = tovv.m_tag;
+
+          return *this;
+        }
+      else if (m_tag < 0 && tovv.m_tag < 0)
+        {
+          m_data.m_vec = tovv.m_data.m_vec;
+          return *this;
+        }
+      else if (m_tag >= 0 && tovv.m_tag < 0)
+        {
+          // Destroy elements
+          for (int i = 0; i < m_tag; i++)
+            m_data.m_arr[i].~T ();
+
+          //Mark for vector usage
+          m_tag = -1;
+
+          // Construct the vector in the union
+          new (&m_data.m_vec) std::vector<T> (tovv.m_data.m_vec);
+
+          return *this;
+        }
+      else // (m_tag < 0 && tovv.m_tag >= 0)
+        {
+          m_data.m_vec.resize (tovv.m_tag);
+          for (int i = 0; i < tovv.m_tag; i++)
+            m_data.m_vec[i] = tovv.m_data.m_arr[i];
+
+          return *this;
+        }
+    }
+
+    T& operator[](std::size_t idx)
+    {
+      if (m_tag >= 0)
+        {
+      // Poor compiler can't figure out that m_tag is supposed to be
+      // -1 when idx is bigger than the array.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Warray-bounds"
+        return m_data.m_arr[idx];
+#pragma GCC diagnostic pop
+        }
+      else
+        return m_data.m_vec[idx];
+    }
+
+    const T& operator[](std::size_t idx) const
+    {
+      if (m_tag >= 0)
+        {
+      // Poor compiler can't figure out that m_tag is supposed to be
+      // -1 when idx is bigger than the array.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Warray-bounds"
+          return m_data.m_arr[idx];
+#pragma GCC diagnostic pop
+        }
+      else
+        {
+          return m_data.m_vec[idx];
+        }
+    }
+
+    T& front ()
+    {
+      if (m_tag >= 0)
+        return m_data.m_arr[0];
+      else
+        return m_data.m_vec.front ();
+    }
+
+    const T& front () const
+    {
+      if (m_tag >= 0)
+        return m_data.m_arr[0];
+      else
+        return m_data.m_vec.front ();
+    }
+
+    void push_back (const T &v)
+    {
+      if (m_tag >= 0 && m_tag < static_cast<int> (n_tiny))
+        {
+          new (&m_data.m_arr[m_tag++]) T (v);
+          return;
+        }
+      if (m_tag == n_tiny)
+        switch_to_vec ();
+      m_data.m_vec.push_back (v);
+    }
+
+    void push_back (T &&v)
+    {
+      if (m_tag >= 0 && m_tag < static_cast<int> (n_tiny))
+        {
+          new (&m_data.m_arr[m_tag++]) T (v);
+          return;
+        }
+      if (m_tag == n_tiny)
+        switch_to_vec ();
+      m_data.m_vec.push_back (v);
+    }
+
+    void resize (size_t count, const T& ref = T ())
+    {
+      if (m_tag >= 0)
+        {
+          size_t n = static_cast <size_t> (m_tag);
+          // Check that we don't need to switch to vector
+          if (count <= n_tiny)
+            {
+              if (count < n)
+                {
+                  // Destroy elements
+                  for (unsigned i = count; i < n; i++)
+                    m_data.m_arr[i].~octave_value ();
+                }
+              else if (count > n)
+                {
+                  // Construct elements
+                  for (unsigned i = n; i < count; i++)
+                    new (&m_data.m_arr[i]) T (ref);
+                }
+              // Nothing to do on same size
+
+              m_tag = count;
+              return;
+            }
+          // Switch to vector so that the new size fits
+          switch_to_vec();
+        }
+
+      m_data.m_vec.resize (count, ref);
+      return;
+    }
+
+  private:
+    union vec_or_arr
+    {
+      T m_arr[n_tiny];
+      std::vector<T> m_vec;
+
+      vec_or_arr () {};
+      ~vec_or_arr () {};
+    };
+
+    // The tag tracks how many elements there are in the array for non-negative
+    // numbers. For negative numbers, the std::vector is in use
+    int m_tag = 0;
+
+    // The data object
+    vec_or_arr m_data;
+
+    void switch_to_vec ()
+    {
+      std::vector<T> tmp;
+      for (int i = 0; i < m_tag; i++)
+        {
+          tmp.push_back (m_data.m_arr[i]);
+          // Destroy ov:s in the array
+          m_data.m_arr[i].~T ();
+        }
+      // Construct the vector in the union
+      new (&m_data.m_vec) std::vector<T>;
+      // Copy the data
+      m_data.m_vec = tmp;
+      // Set the tag to indicate vector usage
+      m_tag = -1;
+    }
+  };
+} // namespace octave
+
+
+#endif
+
