changeset 23728:b40b7243a782

new class for caching file contents for debug and echo * liboctave/util/file-info.h, liboctave/util/file-info.cc: New files. Move get_file_line function here from bp-table.h and bp-table.cc. * liboctave/util/module.mk: Update. * ov-usr-fcn.h, ov-usr-fcn.cc (octave_user_code::m_file_info, octave_user_code::get_code_line, octave_user_code::get_code_lines): New data member and functions. Change all uses of get_file_line to access code lines from info cached in function object.
author John W. Eaton <jwe@octave.org>
date Wed, 05 Jul 2017 09:44:01 -0400
parents 154c876e241b
children 06b3d1d54054
files libinterp/corefcn/debug.cc libinterp/corefcn/input.cc libinterp/octave-value/ov-usr-fcn.cc libinterp/octave-value/ov-usr-fcn.h libinterp/parse-tree/bp-table.cc libinterp/parse-tree/bp-table.h libinterp/parse-tree/pt-eval.cc libinterp/parse-tree/pt-eval.h liboctave/util/file-info.cc liboctave/util/file-info.h liboctave/util/module.mk
diffstat 11 files changed, 317 insertions(+), 118 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/debug.cc	Wed Jul 05 20:26:14 2017 +0200
+++ b/libinterp/corefcn/debug.cc	Wed Jul 05 09:44:01 2017 -0400
@@ -556,7 +556,7 @@
         {
           octave_stdout << " [" << file_name << "]" << std::endl;
 
-          std::string line = get_file_line (file_name, l);
+          std::string line = dbg_fcn->get_code_line (l);
 
           if (! line.empty ())
             octave_stdout << l << ": " << line << std::endl;
@@ -805,7 +805,8 @@
           int l_max = l + n/2;
           do_dbtype (octave_stdout, name, l_min, l-1);
 
-          std::string line = get_file_line (name, l);
+          std::string line = dbg_fcn->get_code_line (l);
+
           if (! line.empty ())
             octave_stdout << l << "-->\t" << line << std::endl;
 
--- a/libinterp/corefcn/input.cc	Wed Jul 05 20:26:14 2017 +0200
+++ b/libinterp/corefcn/input.cc	Wed Jul 05 09:44:01 2017 -0400
@@ -543,14 +543,14 @@
 }
 
 static void
-get_debug_input (const std::string& prompt)
+get_debug_input (octave::interpreter& interp, const std::string& prompt)
 {
   octave::unwind_protect frame;
 
   bool silent = octave::tree_evaluator::quiet_breakpoint_flag;
   octave::tree_evaluator::quiet_breakpoint_flag = false;
 
-  octave::call_stack& cs = octave::__get_call_stack__ ("get_debug_input");
+  octave::call_stack& cs = interp.get_call_stack ();
 
   octave_user_code *caller = cs.caller_user_code ();
   std::string nm;
@@ -607,8 +607,10 @@
 
               if (! silent)
                 {
-                  std::string line_buf
-                    = get_file_line (nm, curr_debug_line);
+                  std::string line_buf;
+
+                  if (caller)
+                    line_buf = caller->get_code_line (curr_debug_line);
 
                   if (! line_buf.empty ())
                     buf << "\n" << curr_debug_line << ": " << line_buf;
@@ -648,7 +650,7 @@
 
   octave::parser curr_parser;
 
-  octave::tree_evaluator& tw = octave::__get_evaluator__ ("get_debug_input");
+  octave::tree_evaluator& tw = interp.get_evaluator ();
 
   while (Vdebugging)
     {
@@ -896,7 +898,7 @@
 }
 
 octave_value
-do_keyboard (const octave_value_list& args)
+do_keyboard (octave::interpreter& interp, const octave_value_list& args)
 {
   octave_value retval;
 
@@ -913,7 +915,7 @@
 
   frame.protect_var (Vdebugging);
 
-  octave::call_stack& cs = octave::__get_call_stack__ ("do_keyboard");
+  octave::call_stack& cs = interp.get_call_stack ();
 
   frame.add_method (cs, &octave::call_stack::restore_frame,
                     cs.current_frame ());
@@ -931,11 +933,19 @@
   if (nargin > 0)
     prompt = args(0).string_value ();
 
-  get_debug_input (prompt);
+  get_debug_input (interp, prompt);
 
   return retval;
 }
 
+octave_value
+do_keyboard (const octave_value_list& args)
+{
+  octave::interpreter& interp = octave::__get_interpreter__ ("do_keyboard");
+
+  return do_keyboard (interp, args);
+}
+
 DEFMETHOD (keyboard, interp, args, ,
            doc: /* -*- texinfo -*-
 @deftypefn  {} {} keyboard ()
@@ -972,7 +982,7 @@
 
   octave::tree_evaluator::current_frame = cs.current_frame ();
 
-  do_keyboard (args);
+  do_keyboard (interp, args);
 
   return ovl ();
 }
--- a/libinterp/octave-value/ov-usr-fcn.cc	Wed Jul 05 20:26:14 2017 +0200
+++ b/libinterp/octave-value/ov-usr-fcn.cc	Wed Jul 05 09:44:01 2017 -0400
@@ -26,6 +26,7 @@
 
 #include <sstream>
 
+#include "file-info.h"
 #include "str-vec.h"
 
 #include "builtin-defun-decls.h"
@@ -60,6 +61,29 @@
 // Whether to optimize subsasgn method calls.
 static bool Voptimize_subsasgn_calls = true;
 
+octave_user_code::~octave_user_code (void)
+{
+  delete m_file_info;
+}
+
+std::string
+octave_user_code::get_code_line (size_t line)
+{
+  if (! m_file_info)
+    m_file_info = new octave::file_info (fcn_file_name ());
+
+  return m_file_info->get_line (line);
+}
+
+std::deque<std::string>
+octave_user_code::get_code_lines (size_t line, size_t num_lines)
+{
+  if (! m_file_info)
+    m_file_info = new octave::file_info (fcn_file_name ());
+
+  return m_file_info->get_lines (line, num_lines);
+}
+
 std::map<std::string, octave_value>
 octave_user_code::subfunctions (void) const
 {
--- a/libinterp/octave-value/ov-usr-fcn.h	Wed Jul 05 20:26:14 2017 +0200
+++ b/libinterp/octave-value/ov-usr-fcn.h	Wed Jul 05 09:44:01 2017 -0400
@@ -43,6 +43,7 @@
 
 namespace octave
 {
+  class file_info;
   class tree_parameter_list;
   class tree_statement_list;
   class tree_evaluator;
@@ -61,7 +62,9 @@
 
   octave_user_code (const std::string& nm,
                     const std::string& ds = "")
-    : octave_function (nm, ds) { }
+    : octave_function (nm, ds), curr_unwind_protect_frame (0),
+      m_file_info (0)
+  { }
 
 public:
 
@@ -74,13 +77,33 @@
 
   octave_user_code& operator = (const octave_user_code& f) = delete;
 
-  ~octave_user_code (void) = default;
+  ~octave_user_code (void);
 
   bool is_user_code (void) const { return true; }
 
+  octave::unwind_protect *
+  unwind_protect_frame (void)
+  {
+    return curr_unwind_protect_frame;
+  }
+
+  std::string get_code_line (size_t line);
+
+  std::deque<std::string> get_code_lines (size_t line, size_t num_lines);
+
+
   virtual std::map<std::string, octave_value> subfunctions (void) const;
 
   virtual octave::tree_statement_list * body (void) = 0;
+
+protected:
+
+  // pointer to the current unwind_protect frame of this function.
+  octave::unwind_protect *curr_unwind_protect_frame;
+
+  // Cached text of function or script code with line offsets
+  // calculated.
+  octave::file_info *m_file_info;
 };
 
 // Scripts.
--- a/libinterp/parse-tree/bp-table.cc	Wed Jul 05 20:26:14 2017 +0200
+++ b/libinterp/parse-tree/bp-table.cc	Wed Jul 05 09:44:01 2017 -0400
@@ -35,7 +35,6 @@
 #include <iostream>
 
 #include "file-ops.h"
-#include "file-stat.h"
 #include "singleton-cleanup.h"
 
 #include "bp-table.h"
@@ -64,105 +63,6 @@
 std::set<std::string> bp_table::caught_that_stop;
 std::set<std::string> bp_table::warnings_that_stop;
 
-// Read entire file called fname and return the contents as a string
-static std::string
-snarf_file (const std::string& fname)
-{
-  std::string retval;
-
-  octave::sys::file_stat fs (fname);
-
-  if (fs)
-    {
-      size_t sz = fs.size ();
-
-      std::ifstream file (fname.c_str (), std::ios::in | std::ios::binary);
-
-      if (file)
-        {
-          std::string buf (sz+1, 0);
-
-          file.read (&buf[0], sz+1);
-
-          if (! file.eof ())
-            error ("error reading file %s", fname.c_str ());
-
-          // Expected to read the entire file.
-          retval = buf;
-        }
-    }
-
-  return retval;
-}
-
-static std::deque<size_t>
-get_line_offsets (const std::string& buf)
-{
-  // FIXME: This could maybe be smarter.  Is deque the right thing to use here?
-
-  std::deque<size_t> offsets;
-
-  offsets.push_back (0);
-
-  size_t len = buf.length ();
-
-  for (size_t i = 0; i < len; i++)
-    {
-      char c = buf[i];
-
-      if (c == '\r' && ++i < len)
-        {
-          c = buf[i];
-
-          if (c == '\n')
-            offsets.push_back (i+1);
-          else
-            offsets.push_back (i);
-        }
-      else if (c == '\n')
-        offsets.push_back (i+1);
-    }
-
-  offsets.push_back (len);
-
-  return offsets;
-}
-
-std::string
-get_file_line (const std::string& fname, size_t line)
-{
-  std::string retval;
-
-  static std::string last_fname;
-
-  static std::string buf;
-
-  static std::deque<size_t> offsets;
-
-  if (fname != last_fname)
-    {
-      buf = snarf_file (fname);
-
-      offsets = get_line_offsets (buf);
-    }
-
-  if (line > 0)
-    line--;
-
-  if (line < offsets.size () - 1)
-    {
-      size_t bol = offsets[line];
-      size_t eol = offsets[line+1];
-
-      while (eol > 0 && eol > bol && (buf[eol-1] == '\n' || buf[eol-1] == '\r'))
-        eol--;
-
-      retval = buf.substr (bol, eol - bol);
-    }
-
-  return retval;
-}
-
 // Return a pointer to the user-defined function FNAME.  If FNAME is
 // empty, search backward for the first user-defined function in the
 // current call stack.
--- a/libinterp/parse-tree/bp-table.h	Wed Jul 05 20:26:14 2017 +0200
+++ b/libinterp/parse-tree/bp-table.h	Wed Jul 05 09:44:01 2017 -0400
@@ -198,8 +198,6 @@
   bool do_have_breakpoints (void) { return (! bp_set.empty ()); }
 };
 
-extern std::string get_file_line (const std::string& fname, size_t line);
-
 extern octave_user_code * get_user_code (const std::string& fname = "");
 
 #endif
--- a/libinterp/parse-tree/pt-eval.cc	Wed Jul 05 20:26:14 2017 +0200
+++ b/libinterp/parse-tree/pt-eval.cc	Wed Jul 05 09:44:01 2017 -0400
@@ -3034,9 +3034,20 @@
   {
     std::string prefix = command_editor::decode_prompt_string (m_PS4);
 
-    for (size_t i = m_echo_file_pos; i <= line; i++)
-      octave_stdout << prefix << get_file_line (m_echo_file_name, i)
-                    << std::endl;
+    octave_function *curr_fcn = m_call_stack.current ();
+
+    if (curr_fcn && curr_fcn->is_user_code ())
+      {
+        octave_user_code *code = dynamic_cast<octave_user_code *> (curr_fcn);
+
+        size_t num_lines = line - m_echo_file_pos + 1;
+
+        std::deque<std::string> lines
+          = code->get_code_lines (m_echo_file_pos, num_lines);
+
+        for (auto& elt : lines)
+          octave_stdout << prefix << elt << std::endl;
+      }
   }
 }
 
--- a/libinterp/parse-tree/pt-eval.h	Wed Jul 05 20:26:14 2017 +0200
+++ b/libinterp/parse-tree/pt-eval.h	Wed Jul 05 09:44:01 2017 -0400
@@ -446,6 +446,8 @@
     bool m_echo_state;
 
     std::string m_echo_file_name;
+
+    // Next line to echo, counting from 1.
     size_t m_echo_file_pos;
 
     std::map<std::string, bool> m_echo_files;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/util/file-info.cc	Wed Jul 05 09:44:01 2017 -0400
@@ -0,0 +1,139 @@
+/*
+
+Copyright (C) 2017 John W. Eaton
+Copyright (C) 2001-2017 Ben Sapp
+
+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
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include <deque>
+#include <fstream>
+#include <iostream>
+
+#include "file-info.h"
+#include "file-stat.h"
+#include "lo-error.h"
+
+namespace octave
+{
+  std::string file_info::get_line (size_t line) const
+  {
+    std::string retval;
+
+    if (line == 0)
+      return retval;
+
+    if (line < m_offsets.size ())
+      {
+        size_t bol = m_offsets[line-1];
+        size_t eol = m_offsets[line];
+
+        while (eol > 0 && eol > bol
+               && (m_file_buf[eol-1] == '\n' || m_file_buf[eol-1] == '\r'))
+          eol--;
+
+        retval = m_file_buf.substr (bol, eol - bol);
+      }
+
+    return retval;
+  }
+
+  std::deque<std::string>
+  file_info::get_lines (size_t line, size_t num_lines) const
+  {
+    std::deque<std::string> retval;
+
+    for (size_t i = line; i < line+num_lines; i++)
+      retval.push_back (get_line (i));
+
+    return retval;
+  }
+
+  // Read entire file called fname and return the contents as a string
+
+  std::string file_info::snarf_file (const std::string& fname)
+  {
+    std::string retval;
+
+    sys::file_stat fs (fname);
+
+    if (! fs)
+      (*current_liboctave_error_handler) ("no such file, '%s'", fname.c_str ());
+
+    size_t sz = fs.size ();
+
+    std::ifstream file (fname.c_str (), std::ios::in | std::ios::binary);
+
+    if (file)
+      {
+        std::string buf (sz+1, 0);
+
+        file.read (&buf[0], sz+1);
+
+        if (! file.eof ())
+          (*current_liboctave_error_handler)
+            ("error reading file %s", fname.c_str ());
+
+        // Expected to read the entire file.
+        retval = buf;
+      }
+
+    return retval;
+  }
+
+  std::vector<size_t> file_info::get_line_offsets (const std::string& buf)
+  {
+    std::deque<size_t> tmp_offsets;
+
+    tmp_offsets.push_back (0);
+
+    size_t len = buf.length ();
+
+    for (size_t i = 0; i < len; i++)
+      {
+        char c = buf[i];
+
+        if (c == '\r' && ++i < len)
+          {
+            c = buf[i];
+
+            if (c == '\n')
+              tmp_offsets.push_back (i+1);
+            else
+              tmp_offsets.push_back (i);
+          }
+        else if (c == '\n')
+          tmp_offsets.push_back (i+1);
+      }
+
+    tmp_offsets.push_back (len-1);
+
+    size_t n = tmp_offsets.size ();
+
+    std::vector<size_t> retval (n);
+    size_t i = 0;
+    for (auto& elt : tmp_offsets)
+      retval[i++] = elt;
+
+    return retval;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/util/file-info.h	Wed Jul 05 09:44:01 2017 -0400
@@ -0,0 +1,89 @@
+/*
+
+Copyright (C) 2017 John W. Eaton
+Copyright (C) 2001-2017 Ben Sapp
+
+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
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#if ! defined (octave_file_info_h)
+#define octave_file_info_h 1
+
+#include "octave-config.h"
+
+#include <deque>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "oct-time.h"
+
+namespace octave
+{
+  class file_info
+  {
+  public:
+
+    file_info (void)
+      : m_file_buf (), m_offsets (), m_timestamp (static_cast<time_t> (0))
+    { }
+
+    file_info (const std::string& fname)
+      : m_file_buf (snarf_file (fname)),
+        m_offsets (get_line_offsets (m_file_buf)),
+        m_timestamp ()
+    { }
+
+    file_info (const file_info&) = default;
+
+    file_info& operator = (const file_info&) = default;
+
+    ~file_info (void) = default;
+
+    std::string get_line (size_t line) const;
+
+    std::deque<std::string> get_lines (size_t line, size_t num_lines) const;
+
+    size_t num_lines (void) const { return m_offsets.size (); }
+
+    std::string text (void) const { return m_file_buf; }
+
+    std::vector<size_t> line_offsets (void) const { return m_offsets; }
+
+    sys::time timestamp (void) const { return m_timestamp; }
+
+    size_t size (void) const { return m_file_buf.length (); }
+
+  private:
+
+    // File contents as a string.
+    std::string m_file_buf;
+
+    // Offsets to line beginnings.
+    std::vector<size_t> m_offsets;
+
+    sys::time m_timestamp;
+
+    // Read entire file called fname and return the contents as a string
+    static std::string snarf_file (const std::string& fname);
+
+    static std::vector<size_t> get_line_offsets (const std::string& buf);
+  };
+}
+
+#endif
--- a/liboctave/util/module.mk	Wed Jul 05 20:26:14 2017 +0200
+++ b/liboctave/util/module.mk	Wed Jul 05 09:44:01 2017 -0400
@@ -6,6 +6,7 @@
   %reldir%/cmd-edit.h \
   %reldir%/cmd-hist.h \
   %reldir%/data-conv.h \
+  %reldir%/file-info.h \
   %reldir%/functor.h \
   %reldir%/glob-match.h \
   %reldir%/lo-array-errwarn.h \
@@ -66,6 +67,7 @@
   %reldir%/cmd-edit.cc \
   %reldir%/cmd-hist.cc \
   %reldir%/data-conv.cc \
+  %reldir%/file-info.cc \
   %reldir%/glob-match.cc \
   %reldir%/kpse.cc \
   %reldir%/lo-array-errwarn.cc \