public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [patch] pr10659   pretty-printing: Display vectors of vectors as matrix
@ 2010-05-27 17:46 Chris Moller
  2010-05-27 21:14 ` Phil Muldoon
  2010-05-27 21:20 ` Tom Tromey
  0 siblings, 2 replies; 7+ messages in thread
From: Chris Moller @ 2010-05-27 17:46 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 592 bytes --]

This patch adds the mechanism for gdb to respond to "matrix" hints from 
printers.py.  (Just to exercise the testcase, the patch includes a 
patched version of printers.py to src/gdb/testsuite/gdb.python.  It can 
be removed once the patched printers.py is generally available.)

Question:  pr10659.exp yields:

    +ERROR: no fileid for qcore
    +ERROR: Couldn't send python print 'test' to GDB.
    +UNRESOLVED: gdb.python/pr10659.exp: verify python support

The actual tests pass, but I haven't the slightest idea how to get rid 
of those errors or even if it's necessary to do so.

-cm


[-- Attachment #2: pr10659.patch --]
[-- Type: text/x-patch, Size: 31207 bytes --]

? testsuite/gdb.python/pr10659
Index: ChangeLog
===================================================================
RCS file: /cvs/src/src/gdb/ChangeLog,v
retrieving revision 1.11714
diff -u -r1.11714 ChangeLog
--- ChangeLog	3 May 2010 13:38:26 -0000	1.11714
+++ ChangeLog	27 May 2010 16:26:07 -0000
@@ -1,3 +1,9 @@
+2010-05-27  Chris Moller  <cmoller@redhat.com>
+
+	* python/py-prettyprint.c (print_children): Add formatting for
+	matrices. (apply_val_pretty_printer): Detect and deal with matrix
+	hints. 
+
 2010-05-03  Pierre Muller  <muller@ics.u-strasbg.fr>
 
 	PR pascal/11349.
Index: python/py-prettyprint.c
===================================================================
RCS file: /cvs/src/src/gdb/python/py-prettyprint.c,v
retrieving revision 1.8
diff -u -r1.8 py-prettyprint.c
--- python/py-prettyprint.c	15 Apr 2010 19:54:13 -0000	1.8
+++ python/py-prettyprint.c	27 May 2010 16:26:09 -0000
@@ -397,7 +397,7 @@
 		struct ui_file *stream, int recurse,
 		const struct value_print_options *options,
 		const struct language_defn *language,
-		int is_py_none)
+		int is_py_none, int is_matrix)
 {
   int is_map, is_array, done_flag, pretty;
   unsigned int i;
@@ -432,7 +432,8 @@
 
   /* Use the prettyprint_arrays option if we are printing an array,
      and the pretty option otherwise.  */
-  pretty = is_array ? options->prettyprint_arrays : options->pretty;
+  pretty = (is_array || is_matrix)
+    ? options->prettyprint_arrays : options->pretty;
 
   /* Manufacture a dummy Python frame to work around Python 2.4 bug,
      where it insists on having a non-NULL tstate->frame when
@@ -444,6 +445,9 @@
       goto done;
     }
   make_cleanup_py_decref (frame);
+  
+  if (is_matrix && recurse == 0)
+    fputs_filtered ("\n", stream);
 
   done_flag = 0;
   for (i = 0; i < options->print_max; ++i)
@@ -478,12 +482,23 @@
 	 3. Other.  Always print a ",".  */
       if (i == 0)
 	{
-         if (is_py_none)
-           fputs_filtered ("{", stream);
-         else
-           fputs_filtered (" = {", stream);
+	  if (is_matrix && recurse == 0)
+	    print_spaces_filtered (2 + 2 * recurse, stream);
+	  if (is_py_none)
+	    {
+	      if (is_matrix && strcmp (hint, "array"))
+		{
+		  fputs_filtered ("{\n", stream);
+		  print_spaces_filtered (4 + 2 * recurse, stream);
+		}
+	      else
+		fputs_filtered ("{", stream);
+	    }
+	  else
+	    fputs_filtered (" = {", stream);
        }
-
+      else if (is_matrix)
+	print_spaces_filtered (4 + 2 * recurse, stream);
       else if (! is_map || i % 2 == 0)
 	fputs_filtered (pretty ? "," : ", ", stream);
 
@@ -512,6 +527,7 @@
 
       if (is_map && i % 2 == 0)
 	fputs_filtered ("[", stream);
+      else if (is_matrix) ;	/* Force a do-nothing.  */
       else if (is_array)
 	{
 	  /* We print the index, not whatever the child method
@@ -586,7 +602,12 @@
 	  fputs_filtered ("\n", stream);
 	  print_spaces_filtered (2 * recurse, stream);
 	}
-      fputs_filtered ("}", stream);
+      if (is_matrix)
+      {
+	print_spaces_filtered (4 * recurse, stream);
+	fputs_filtered ("}\n", stream);
+      }
+      else fputs_filtered ("}", stream);
     }
 
  done:
@@ -608,6 +629,7 @@
   struct cleanup *cleanups;
   int result = 0;
   int is_py_none = 0;
+  static int is_matrix = 0;
   cleanups = ensure_python_env (gdbarch, language);
 
   /* Instantiate the printer.  */
@@ -629,18 +651,23 @@
 
   /* If we are printing a map, we want some special formatting.  */
   hint = gdbpy_get_display_hint (printer);
+  if (recurse == 0)
+    is_matrix = hint && !strcmp (hint, "matrix");
+
   make_cleanup (free_current_contents, &hint);
 
   /* Print the section */
-  is_py_none = print_string_repr (printer, hint, stream, recurse,
-				  options, language, gdbarch);
+  is_py_none = is_matrix ? 1 : print_string_repr (printer, hint, stream,
+						  recurse, options,
+						  language, gdbarch);
   print_children (printer, hint, stream, recurse, options, language,
-		  is_py_none);
+		  is_py_none, is_matrix);
 
   result = 1;
 
 
  done:
+  if (recurse == 0) is_matrix = 0;
   if (PyErr_Occurred ())
     gdbpy_print_stack ();
   do_cleanups (cleanups);
Index: testsuite/ChangeLog
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/ChangeLog,v
retrieving revision 1.2260
diff -u -r1.2260 ChangeLog
--- testsuite/ChangeLog	2 May 2010 09:08:58 -0000	1.2260
+++ testsuite/ChangeLog	27 May 2010 16:26:25 -0000
@@ -1,3 +1,10 @@
+2010-05-27  Chris Moller  <cmoller@redhat.com>
+
+	* gdb.python/Makefile.in (EXECUTABLES):  Added pr10659.
+	* gdb.python/pr10659.cc:  New file.
+	* gdb.python/pr10659.exp.  New file.
+	* gdb.python/printers.py: New file.
+
 2010-05-02  Jan Kratochvil  <jan.kratochvil@redhat.com>
 
 	* gdb.base/break-interp.exp: Remove $exec.debug safety removal.
Index: testsuite/gdb.python/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.python/Makefile.in,v
retrieving revision 1.6
diff -u -r1.6 Makefile.in
--- testsuite/gdb.python/Makefile.in	9 Apr 2010 09:41:43 -0000	1.6
+++ testsuite/gdb.python/Makefile.in	27 May 2010 16:26:27 -0000
@@ -2,7 +2,7 @@
 srcdir = @srcdir@
 
 EXECUTABLES = py-type py-value py-prettyprint py-template py-block \
-		py-symbol py-mi py-breakpoint
+		py-symbol py-mi py-breakpoint pr10659
 
 all info install-info dvi install uninstall installcheck check:
 	@echo "Nothing to be done for $@..."
Index: testsuite/gdb.python/pr10659.cc
===================================================================
RCS file: testsuite/gdb.python/pr10659.cc
diff -N testsuite/gdb.python/pr10659.cc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.python/pr10659.cc	27 May 2010 16:26:27 -0000
@@ -0,0 +1,43 @@
+#include <list>
+#include <vector>  // /usr/include/c++/4.4.1/bits/vector.tcc
+#include <iostream>
+
+using namespace std;
+
+int use_windows = 9999;
+
+int
+main(){
+  vector<int> test1(2,0);
+  test1[0]=8;
+  test1[1]=9;
+  
+  vector< vector<int> > test2(3, vector<int>(2,0));
+  test2[0][0]=0;
+  test2[0][1]=1;
+  test2[1][0]=2;
+  test2[1][1]=3;
+  test2[2][0]=4;
+  test2[2][1]=5;
+
+#define NR_ROWS    2
+#define NR_COLS    3
+#define NR_PLANES  4
+  vector<int> rows(NR_ROWS, 0);
+  vector< vector<int> > columns(NR_COLS, rows);
+  vector< vector < vector<int> > > test3(NR_PLANES, columns);
+
+  cout << "rows.size() = " << rows.size()
+       << ", columns.size() = " << columns.size()
+       << ", test3.size() = " << test3.size() << "\n";
+
+  for (int i = 0; i < rows.size(); i++) {
+    for (int j = 0; j < columns.size(); j++) {
+      for (int k = 0; k < test3.size(); k++) {
+	test3[k][j][i] = k * 100 + j * 10 + i;
+      }
+    }
+  }
+  
+  return 0;  // break
+}
Index: testsuite/gdb.python/pr10659.exp
===================================================================
RCS file: testsuite/gdb.python/pr10659.exp
diff -N testsuite/gdb.python/pr10659.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.python/pr10659.exp	27 May 2010 16:26:27 -0000
@@ -0,0 +1,41 @@
+#Copyright 2010 Free Software Foundation, Inc.
+
+# This program 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.
+#
+# This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+
+set nl             "\[\r\n\]+"
+
+if { [skip_python_tests] } { continue }
+
+set testfile pr10659
+set srcfile ${testfile}.cc
+if [prepare_for_testing $testfile.exp $testfile $srcfile {debug c++}] {
+    return -1
+}
+
+gdb_test "python execfile(\"$srcdir/$subdir/printers.py\")" ""
+gdb_test "python gdb.pretty_printers = \[lookup_function\]" ""
+
+if ![runto_main] then {
+    fail "Can't run to main"
+    return
+}
+
+gdb_breakpoint [gdb_get_line_number "break"]
+gdb_continue_to_breakpoint "break"
+
+gdb_test "p test1" "vector of length 2, capacity 2 =.*"
+gdb_test "p test2" "= $nl  {$nl    {.*"
+gdb_test "p test3" "= $nl  {$nl    {$nl      {.*"
+
+
Index: testsuite/gdb.python/printers.py
===================================================================
RCS file: testsuite/gdb.python/printers.py
diff -N testsuite/gdb.python/printers.py
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.python/printers.py	27 May 2010 16:26:27 -0000
@@ -0,0 +1,638 @@
+# Pretty-printers for libstc++.
+
+# Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+
+# This program 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.
+#
+# This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+
+import gdb
+import itertools
+import re
+
+print "in printers.py"
+
+class StdPointerPrinter:
+    "Print a smart pointer of some kind"
+
+    def __init__ (self, typename, val):
+        self.typename = typename
+        self.val = val
+
+    def to_string (self):
+        if self.val['_M_refcount']['_M_pi'] == 0:
+            return '%s (empty) %s' % (self.typename, self.val['_M_ptr'])
+        return '%s (count %d) %s' % (self.typename,
+                                     self.val['_M_refcount']['_M_pi']['_M_use_count'],
+                                     self.val['_M_ptr'])
+
+class UniquePointerPrinter:
+    "Print a unique_ptr"
+
+    def __init__ (self, val):
+        self.val = val
+
+    def to_string (self):
+        return self.val['_M_t']
+
+class StdListPrinter:
+    "Print a std::list"
+
+    class _iterator:
+        def __init__(self, nodetype, head):
+            self.nodetype = nodetype
+            self.base = head['_M_next']
+            self.head = head.address
+            self.count = 0
+
+        def __iter__(self):
+            return self
+
+        def next(self):
+            if self.base == self.head:
+                raise StopIteration
+            elt = self.base.cast(self.nodetype).dereference()
+            self.base = elt['_M_next']
+            count = self.count
+            self.count = self.count + 1
+            return ('[%d]' % count, elt['_M_data'])
+
+    def __init__(self, val):
+        self.val = val
+
+    def children(self):
+        itype = self.val.type.template_argument(0)
+        nodetype = gdb.lookup_type('std::_List_node<%s>' % itype).pointer()
+        return self._iterator(nodetype, self.val['_M_impl']['_M_node'])
+
+    def to_string(self):
+        if self.val['_M_impl']['_M_node'].address == self.val['_M_impl']['_M_node']['_M_next']:
+            return 'empty std::list'
+        return 'std::list'
+
+class StdListIteratorPrinter:
+    "Print std::list::iterator"
+
+    def __init__(self, val):
+        self.val = val
+
+    def to_string(self):
+        itype = self.val.type.template_argument(0)
+        nodetype = gdb.lookup_type('std::_List_node<%s>' % itype).pointer()
+        return self.val['_M_node'].cast(nodetype).dereference()['_M_data']
+
+class StdSlistPrinter:
+    "Print a __gnu_cxx::slist"
+
+    class _iterator:
+        def __init__(self, nodetype, head):
+            self.nodetype = nodetype
+            self.base = head['_M_head']['_M_next']
+            self.count = 0
+
+        def __iter__(self):
+            return self
+
+        def next(self):
+            if self.base == 0:
+                raise StopIteration
+            elt = self.base.cast(self.nodetype).dereference()
+            self.base = elt['_M_next']
+            count = self.count
+            self.count = self.count + 1
+            return ('[%d]' % count, elt['_M_data'])
+
+    def __init__(self, val):
+        self.val = val
+
+    def children(self):
+        itype = self.val.type.template_argument(0)
+        nodetype = gdb.lookup_type('__gnu_cxx::_Slist_node<%s>' % itype).pointer()
+        return self._iterator(nodetype, self.val)
+
+    def to_string(self):
+        if self.val['_M_head']['_M_next'] == 0:
+            return 'empty __gnu_cxx::slist'
+        return '__gnu_cxx::slist'
+
+class StdSlistIteratorPrinter:
+    "Print __gnu_cxx::slist::iterator"
+
+    def __init__(self, val):
+        self.val = val
+
+    def to_string(self):
+        itype = self.val.type.template_argument(0)
+        nodetype = gdb.lookup_type('__gnu_cxx::_Slist_node<%s>' % itype).pointer()
+        return self.val['_M_node'].cast(nodetype).dereference()['_M_data']
+
+class StdVectorPrinter:
+    "Print a std::vector"
+
+    class _iterator:
+        def __init__ (self, start, finish):
+            self.item = start
+            self.finish = finish
+            self.count = 0
+
+        def __iter__(self):
+            return self
+
+        def next(self):
+            if self.item == self.finish:
+                raise StopIteration
+            count = self.count
+            self.count = self.count + 1
+            elt = self.item.dereference()
+            self.item = self.item + 1
+            return ('[%d]' % count, elt)
+
+    def __init__(self, val):
+        self.val = val
+
+    def children(self):
+        return self._iterator(self.val['_M_impl']['_M_start'],
+                              self.val['_M_impl']['_M_finish'])
+
+    def to_string(self):
+        start = self.val['_M_impl']['_M_start']
+        finish = self.val['_M_impl']['_M_finish']
+        end = self.val['_M_impl']['_M_end_of_storage']
+        return ('std::vector of length %d, capacity %d'
+                % (int (finish - start), int (end - start)))
+
+    def display_hint(self):
+        itype0  = self.val.type.template_argument(0)
+        rc = 'array'
+        if itype0.tag:
+            if -1 != itype0.tag.find('vector'):
+                rc = 'matrix'
+        return rc
+    
+class StdVectorIteratorPrinter:
+    "Print std::vector::iterator"
+
+    def __init__(self, val):
+        self.val = val
+
+    def to_string(self):
+        return self.val['_M_current'].dereference()
+
+class StdStackOrQueuePrinter:
+    "Print a std::stack or std::queue"
+
+    def __init__ (self, typename, val):
+        self.typename = typename
+        self.visualizer = gdb.default_visualizer(val['c'])
+
+    def children (self):
+        return self.visualizer.children()
+
+    def to_string (self):
+        return '%s wrapping: %s' % (self.typename,
+                                    self.visualizer.to_string())
+
+    def display_hint (self):
+        if hasattr (self.visualizer, 'display_hint'):
+            return self.visualizer.display_hint ()
+        return None
+
+class RbtreeIterator:
+    def __init__(self, rbtree):
+        self.size = rbtree['_M_t']['_M_impl']['_M_node_count']
+        self.node = rbtree['_M_t']['_M_impl']['_M_header']['_M_left']
+        self.count = 0
+
+    def __iter__(self):
+        return self
+
+    def __len__(self):
+        return int (self.size)
+
+    def next(self):
+        if self.count == self.size:
+            raise StopIteration
+        result = self.node
+        self.count = self.count + 1
+        if self.count < self.size:
+            # Compute the next node.
+            node = self.node
+            if node.dereference()['_M_right']:
+                node = node.dereference()['_M_right']
+                while node.dereference()['_M_left']:
+                    node = node.dereference()['_M_left']
+            else:
+                parent = node.dereference()['_M_parent']
+                while node == parent.dereference()['_M_right']:
+                    node = parent
+                    parent = parent.dereference()['_M_parent']
+                if node.dereference()['_M_right'] != parent:
+                    node = parent
+            self.node = node
+        return result
+
+# This is a pretty printer for std::_Rb_tree_iterator (which is
+# std::map::iterator), and has nothing to do with the RbtreeIterator
+# class above.
+class StdRbtreeIteratorPrinter:
+    "Print std::map::iterator"
+
+    def __init__ (self, val):
+        self.val = val
+
+    def to_string (self):
+        valuetype = self.val.type.template_argument(0)
+        nodetype = gdb.lookup_type('std::_Rb_tree_node < %s >' % valuetype)
+        nodetype = nodetype.pointer()
+        return self.val.cast(nodetype).dereference()['_M_value_field']
+
+
+class StdMapPrinter:
+    "Print a std::map or std::multimap"
+
+    # Turn an RbtreeIterator into a pretty-print iterator.
+    class _iter:
+        def __init__(self, rbiter, type):
+            self.rbiter = rbiter
+            self.count = 0
+            self.type = type
+
+        def __iter__(self):
+            return self
+
+        def next(self):
+            if self.count % 2 == 0:
+                n = self.rbiter.next()
+                n = n.cast(self.type).dereference()['_M_value_field']
+                self.pair = n
+                item = n['first']
+            else:
+                item = self.pair['second']
+            result = ('[%d]' % self.count, item)
+            self.count = self.count + 1
+            return result
+
+    def __init__ (self, typename, val):
+        self.typename = typename
+        self.val = val
+        self.iter = RbtreeIterator (val)
+
+    def to_string (self):
+        return '%s with %d elements' % (self.typename, len (self.iter))
+
+    def children (self):
+        keytype = self.val.type.template_argument(0).const()
+        valuetype = self.val.type.template_argument(1)
+        nodetype = gdb.lookup_type('std::_Rb_tree_node< std::pair< %s, %s > >' % (keytype, valuetype))
+        nodetype = nodetype.pointer()
+        return self._iter (self.iter, nodetype)
+
+    def display_hint (self):
+        return 'map'
+
+class StdSetPrinter:
+    "Print a std::set or std::multiset"
+
+    # Turn an RbtreeIterator into a pretty-print iterator.
+    class _iter:
+        def __init__(self, rbiter, type):
+            self.rbiter = rbiter
+            self.count = 0
+            self.type = type
+
+        def __iter__(self):
+            return self
+
+        def next(self):
+            item = self.rbiter.next()
+            item = item.cast(self.type).dereference()['_M_value_field']
+            # FIXME: this is weird ... what to do?
+            # Maybe a 'set' display hint?
+            result = ('[%d]' % self.count, item)
+            self.count = self.count + 1
+            return result
+
+    def __init__ (self, typename, val):
+        self.typename = typename
+        self.val = val
+        self.iter = RbtreeIterator (val)
+
+    def to_string (self):
+        return '%s with %d elements' % (self.typename, len (self.iter))
+
+    def children (self):
+        keytype = self.val.type.template_argument(0)
+        nodetype = gdb.lookup_type('std::_Rb_tree_node< %s >' % keytype).pointer()
+        return self._iter (self.iter, nodetype)
+
+class StdBitsetPrinter:
+    "Print a std::bitset"
+
+    def __init__(self, val):
+        self.val = val
+
+    def to_string (self):
+        # If template_argument handled values, we could print the
+        # size.  Or we could use a regexp on the type.
+        return 'std::bitset'
+
+    def children (self):
+        words = self.val['_M_w']
+        wtype = words.type
+
+        # The _M_w member can be either an unsigned long, or an
+        # array.  This depends on the template specialization used.
+        # If it is a single long, convert to a single element list.
+        if wtype.code == gdb.TYPE_CODE_ARRAY:
+            tsize = wtype.target ().sizeof
+        else:
+            words = [words]
+            tsize = wtype.sizeof 
+
+        nwords = wtype.sizeof / tsize
+        result = []
+        byte = 0
+        while byte < nwords:
+            w = words[byte]
+            bit = 0
+            while w != 0:
+                if (w & 1) != 0:
+                    # Another spot where we could use 'set'?
+                    result.append(('[%d]' % (byte * tsize * 8 + bit), 1))
+                bit = bit + 1
+                w = w >> 1
+            byte = byte + 1
+        return result
+
+class StdDequePrinter:
+    "Print a std::deque"
+
+    class _iter:
+        def __init__(self, node, start, end, last, buffer_size):
+            self.node = node
+            self.p = start
+            self.end = end
+            self.last = last
+            self.buffer_size = buffer_size
+            self.count = 0
+
+        def __iter__(self):
+            return self
+
+        def next(self):
+            if self.p == self.last:
+                raise StopIteration
+
+            result = ('[%d]' % self.count, self.p.dereference())
+            self.count = self.count + 1
+
+            # Advance the 'cur' pointer.
+            self.p = self.p + 1
+            if self.p == self.end:
+                # If we got to the end of this bucket, move to the
+                # next bucket.
+                self.node = self.node + 1
+                self.p = self.node[0]
+                self.end = self.p + self.buffer_size
+
+            return result
+
+    def __init__(self, val):
+        self.val = val
+        self.elttype = val.type.template_argument(0)
+        size = self.elttype.sizeof
+        if size < 512:
+            self.buffer_size = int (512 / size)
+        else:
+            self.buffer_size = 1
+
+    def to_string(self):
+        start = self.val['_M_impl']['_M_start']
+        end = self.val['_M_impl']['_M_finish']
+
+        delta_n = end['_M_node'] - start['_M_node'] - 1
+        delta_s = start['_M_last'] - start['_M_cur']
+        delta_e = end['_M_cur'] - end['_M_first']
+
+        size = self.buffer_size * delta_n + delta_s + delta_e
+
+        return 'std::deque with %d elements' % long (size)
+
+    def children(self):
+        start = self.val['_M_impl']['_M_start']
+        end = self.val['_M_impl']['_M_finish']
+        return self._iter(start['_M_node'], start['_M_cur'], start['_M_last'],
+                          end['_M_cur'], self.buffer_size)
+
+    def display_hint (self):
+        return 'array'
+
+class StdDequeIteratorPrinter:
+    "Print std::deque::iterator"
+
+    def __init__(self, val):
+        self.val = val
+
+    def to_string(self):
+        return self.val['_M_cur'].dereference()
+
+class StdStringPrinter:
+    "Print a std::basic_string of some kind"
+
+    def __init__(self, encoding, val):
+        self.encoding = encoding
+        self.val = val
+
+    def to_string(self):
+        # Look up the target encoding as late as possible.
+        encoding = self.encoding
+        if encoding[0] is '@':
+            encoding = gdb.parameter(encoding[1:])
+        return self.val['_M_dataplus']['_M_p'].string(encoding)
+
+    def display_hint (self):
+        return 'string'
+
+class Tr1HashtableIterator:
+    def __init__ (self, hash):
+        self.count = 0
+        self.n_buckets = hash['_M_element_count']
+        if self.n_buckets == 0:
+            self.node = False
+        else:
+            self.bucket = hash['_M_buckets']
+            self.node = self.bucket[0]
+            self.update ()
+
+    def __iter__ (self):
+        return self
+
+    def update (self):
+        # If we advanced off the end of the chain, move to the next
+        # bucket.
+        while self.node == 0:
+            self.bucket = self.bucket + 1
+            self.node = self.bucket[0]
+
+       # If we advanced off the end of the bucket array, then
+       # we're done.
+        if self.count == self.n_buckets:
+            self.node = False
+        else:
+            self.count = self.count + 1
+
+    def next (self):
+        if not self.node:
+            raise StopIteration
+        result = self.node.dereference()['_M_v']
+        self.node = self.node.dereference()['_M_next']
+        self.update ()
+        return result
+
+class Tr1UnorderedSetPrinter:
+    "Print a tr1::unordered_set"
+
+    def __init__ (self, typename, val):
+        self.typename = typename
+        self.val = val
+
+    def to_string (self):
+        return '%s with %d elements' % (self.typename, self.val['_M_element_count'])
+
+    @staticmethod
+    def format_count (i):
+        return '[%d]' % i
+
+    def children (self):
+        counter = itertools.imap (self.format_count, itertools.count())
+        return itertools.izip (counter, Tr1HashtableIterator (self.val))
+
+class Tr1UnorderedMapPrinter:
+    "Print a tr1::unordered_map"
+
+    def __init__ (self, typename, val):
+        self.typename = typename
+        self.val = val
+
+    def to_string (self):
+        return '%s with %d elements' % (self.typename, self.val['_M_element_count'])
+
+    @staticmethod
+    def flatten (list):
+        for elt in list:
+            for i in elt:
+                yield i
+
+    @staticmethod
+    def format_one (elt):
+        return (elt['first'], elt['second'])
+
+    @staticmethod
+    def format_count (i):
+        return '[%d]' % i
+
+    def children (self):
+        counter = itertools.imap (self.format_count, itertools.count())
+        # Map over the hash table and flatten the result.
+        data = self.flatten (itertools.imap (self.format_one, Tr1HashtableIterator (self.val)))
+        # Zip the two iterators together.
+        return itertools.izip (counter, data)
+
+    def display_hint (self):
+        return 'map'
+
+def register_libstdcxx_printers (obj):
+    "Register libstdc++ pretty-printers with objfile Obj."
+
+    if obj == None:
+        obj = gdb
+
+    obj.pretty_printers.append (lookup_function)
+
+def lookup_function (val):
+    "Look-up and return a pretty-printer that can print val."
+
+    # Get the type.
+    type = val.type;
+
+    # If it points to a reference, get the reference.
+    if type.code == gdb.TYPE_CODE_REF:
+        type = type.target ()
+
+    # Get the unqualified type, stripped of typedefs.
+    type = type.unqualified ().strip_typedefs ()
+
+    # Get the type name.    
+    typename = type.tag
+    if typename == None:
+        return None
+
+    # Iterate over local dictionary of types to determine
+    # if a printer is registered for that type.  Return an
+    # instantiation of the printer if found.
+    for function in pretty_printers_dict:
+        if function.search (typename):
+            return pretty_printers_dict[function] (val)
+        
+    # Cannot find a pretty printer.  Return None.
+    return None
+
+def build_libstdcxx_dictionary ():
+    # libstdc++ objects requiring pretty-printing.
+    # In order from:
+    # http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a01847.html
+    pretty_printers_dict[re.compile('^std::basic_string<char,.*>$')] = lambda val: StdStringPrinter('@target-charset', val)
+    pretty_printers_dict[re.compile('^std::basic_string<wchar_t,.*>$')] = lambda val: StdStringPrinter('@target-wide-charset', val)
+    pretty_printers_dict[re.compile('^std::basic_string<char16_t,.*>$')] = lambda val: StdStringPrinter('UTF-16', val)
+    pretty_printers_dict[re.compile('^std::basic_string<char32_t,.*>$')] = lambda val: StdStringPrinter('UTF-32', val)
+    pretty_printers_dict[re.compile('^std::bitset<.*>$')] = StdBitsetPrinter
+    pretty_printers_dict[re.compile('^std::deque<.*>$')] = StdDequePrinter
+    pretty_printers_dict[re.compile('^std::list<.*>$')] = StdListPrinter
+    pretty_printers_dict[re.compile('^std::map<.*>$')] = lambda val: StdMapPrinter("std::map", val)
+    pretty_printers_dict[re.compile('^std::multimap<.*>$')] = lambda val: StdMapPrinter("std::multimap", val)
+    pretty_printers_dict[re.compile('^std::multiset<.*>$')] = lambda val: StdSetPrinter("std::multiset", val)
+    pretty_printers_dict[re.compile('^std::priority_queue<.*>$')] = lambda val: StdStackOrQueuePrinter("std::priority_queue", val)
+    pretty_printers_dict[re.compile('^std::queue<.*>$')] = lambda val: StdStackOrQueuePrinter("std::queue", val)
+    pretty_printers_dict[re.compile('^std::set<.*>$')] = lambda val: StdSetPrinter("std::set", val)
+    pretty_printers_dict[re.compile('^std::stack<.*>$')] = lambda val: StdStackOrQueuePrinter("std::stack", val)
+    pretty_printers_dict[re.compile('^std::unique_ptr<.*>$')] = UniquePointerPrinter
+    pretty_printers_dict[re.compile('^std::vector<.*>$')] = StdVectorPrinter
+    # vector<bool>
+
+    # These are the C++0x printers. They also exist in the standard namespace.
+    # For array - the default GDB pretty-printer seems reasonable.
+    pretty_printers_dict[re.compile('^std::(tr1::)?shared_ptr<.*>$')] = lambda val: StdPointerPrinter ('std::shared_ptr', val)
+    pretty_printers_dict[re.compile('^std::(tr1::)?weak_ptr<.*>$')] = lambda val: StdPointerPrinter ('std::weak_ptr', val)
+    pretty_printers_dict[re.compile('^std::(tr1::)?unordered_map<.*>$')] = lambda val: Tr1UnorderedMapPrinter ('std::tr1::unordered_map', val)
+    pretty_printers_dict[re.compile('^std::(tr1::)?unordered_set<.*>$')] = lambda val: Tr1UnorderedSetPrinter ('std::tr1::unordered_set', val)
+    pretty_printers_dict[re.compile('^std::(tr1::)?unordered_multimap<.*>$')] = lambda val: Tr1UnorderedMapPrinter ('std::tr1::unordered_multimap', val)
+    pretty_printers_dict[re.compile('^std::(tr1::)?unordered_multiset<.*>$')] = lambda val: Tr1UnorderedSetPrinter ('std::tr1::unordered_multiset', val)
+
+
+    # Extensions.
+    pretty_printers_dict[re.compile('^__gnu_cxx::slist<.*>$')] = StdSlistPrinter
+
+    if True:
+        # These shouldn't be necessary, if GDB "print *i" worked.
+        # But it often doesn't, so here they are.
+        pretty_printers_dict[re.compile('^std::_List_iterator<.*>$')] = lambda val: StdListIteratorPrinter(val)
+        pretty_printers_dict[re.compile('^std::_List_const_iterator<.*>$')] = lambda val: StdListIteratorPrinter(val)
+        pretty_printers_dict[re.compile('^std::_Rb_tree_iterator<.*>$')] = lambda val: StdRbtreeIteratorPrinter(val)
+        pretty_printers_dict[re.compile('^std::_Rb_tree_const_iterator<.*>$')] = lambda val: StdRbtreeIteratorPrinter(val)
+        pretty_printers_dict[re.compile('^std::_Deque_iterator<.*>$')] = lambda val: StdDequeIteratorPrinter(val)
+        pretty_printers_dict[re.compile('^std::_Deque_const_iterator<.*>$')] = lambda val: StdDequeIteratorPrinter(val)
+        pretty_printers_dict[re.compile('^__gnu_cxx::__normal_iterator<.*>$')] = lambda val: StdVectorIteratorPrinter(val)
+        pretty_printers_dict[re.compile('^__gnu_cxx::_Slist_iterator<.*>$')] = lambda val: StdSlistIteratorPrinter(val)
+
+pretty_printers_dict = {}
+
+build_libstdcxx_dictionary ()

[-- Attachment #3: sum.diff --]
[-- Type: text/x-patch, Size: 3098 bytes --]

--- virgin.sum	2010-05-27 11:46:39.803773758 -0400
+++ patched.sum	2010-05-27 12:27:16.134773259 -0400
@@ -1,4 +1,4 @@
-Test Run By moller on Fri Apr 30 11:22:14 2010
+Test Run By moller on Thu May 27 12:01:21 2010
 Native configuration is i686-pc-linux-gnu
 
 		=== gdb tests ===
@@ -5450,7 +5450,7 @@
 FAIL: gdb.base/longjmp.exp: next over call_longjmp (2)
 PASS: gdb.base/longjmp.exp: breakpoint at pattern 3 start
 PASS: gdb.base/longjmp.exp: continue to breakpoint at pattern 3 start
-FAIL: gdb.base/longjmp.exp: next over patt3 (the program exited)
+FAIL: gdb.base/longjmp.exp: next over patt3
 Running ../../../src/gdb/testsuite/gdb.base/macscp.exp ...
 PASS: gdb.base/macscp.exp: list main for support check
 PASS: gdb.base/macscp.exp: list main for WHERE
@@ -14351,7 +14351,6 @@
 PASS: gdb.mi/mi2-simplerun.exp: step at main
 PASS: gdb.mi/mi2-simplerun.exp: step to callee4
 PASS: gdb.mi/mi2-simplerun.exp: exec-finish
-FAIL: gdb.mi/mi2-simplerun.exp: continue to end (failed to resume)
 PASS: gdb.mi/mi2-simplerun.exp: continue to end
 Running ../../../src/gdb/testsuite/gdb.mi/mi2-stack.exp ...
 PASS: gdb.mi/mi2-stack.exp: breakpoint at callee4
@@ -15006,6 +15005,16 @@
 PASS: gdb.pascal/types.exp: pt 44.0
 PASS: gdb.pascal/types.exp: pt 10e20
 PASS: gdb.pascal/types.exp: pt 10E20
+Running ../../../src/gdb/testsuite/gdb.python/pr10659.exp ...
+ERROR: no fileid for qcore
+ERROR: Couldn't send python print 'test' to GDB.
+UNRESOLVED: gdb.python/pr10659.exp: verify python support
+PASS: gdb.python/pr10659.exp: python execfile("../../../src/gdb/testsuite/gdb.python/printers.py")
+PASS: gdb.python/pr10659.exp: python gdb.pretty_printers = [lookup_function]
+PASS: gdb.python/pr10659.exp: continue to breakpoint: break
+PASS: gdb.python/pr10659.exp: p test1
+PASS: gdb.python/pr10659.exp: p test2
+PASS: gdb.python/pr10659.exp: p test3
 Running ../../../src/gdb/testsuite/gdb.python/py-block.exp ...
 PASS: gdb.python/py-block.exp: continue to breakpoint: Block break here.
 PASS: gdb.python/py-block.exp: Check block not None
@@ -16340,7 +16349,7 @@
 PASS: gdb.threads/pthread_cond_wait.exp: successfully compiled posix threads test case
 PASS: gdb.threads/pthread_cond_wait.exp: breakpoint on break_me
 PASS: gdb.threads/pthread_cond_wait.exp: run to break_me
-PASS: gdb.threads/pthread_cond_wait.exp: backtrace in blocked thread
+FAIL: gdb.threads/pthread_cond_wait.exp: backtrace in blocked thread
 Running ../../../src/gdb/testsuite/gdb.threads/pthreads.exp ...
 PASS: gdb.threads/pthreads.exp: successfully compiled posix threads test case
 PASS: gdb.threads/pthreads.exp: set print sevenbit-strings
@@ -16888,10 +16897,11 @@
 
 		=== gdb Summary ===
 
-# of expected passes		16026
+# of expected passes		16031
 # of unexpected failures	38
 # of expected failures		45
 # of untested testcases		7
+# of unresolved testcases	1
 # of unsupported tests		62
-/home/moller/tinkering/fsfgdb/pr10659/build/gdb/testsuite/../../gdb/gdb version  7.1.50.20100430-cvs -nw -nx 
+/home/moller/tinkering/fsfgdb/pr10659/build/gdb/testsuite/../../gdb/gdb version  7.1.50.20100503-cvs -nw -nx 
 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [patch] pr10659   pretty-printing: Display vectors of vectors as matrix
  2010-05-27 17:46 [patch] pr10659 pretty-printing: Display vectors of vectors as matrix Chris Moller
@ 2010-05-27 21:14 ` Phil Muldoon
  2010-05-27 22:25   ` Chris Moller
  2010-05-27 21:20 ` Tom Tromey
  1 sibling, 1 reply; 7+ messages in thread
From: Phil Muldoon @ 2010-05-27 21:14 UTC (permalink / raw)
  To: Chris Moller; +Cc: gdb-patches

On 05/27/2010 05:43 PM, Chris Moller wrote:
> This patch adds the mechanism for gdb to respond to "matrix" hints from
> printers.py.  (Just to exercise the testcase, the patch includes a
> patched version of printers.py to src/gdb/testsuite/gdb.python.  It can
> be removed once the patched printers.py is generally available.)

This is not an official review, I just have some questions.

> @@ -397,7 +397,7 @@
> 		struct ui_file *stream, int recurse,
>  		const struct value_print_options *options,
>  		const struct language_defn *language,
> -		int is_py_none)
> +		int is_py_none, int is_matrix)
>  {

I'm not sure why it is necessary to pass the hint in here.  All of the
other hints are parsed internally within the function?


> -         if (is_py_none)
> -           fputs_filtered ("{", stream);
> -         else
> -           fputs_filtered (" = {", stream);
> +	  if (is_matrix && recurse == 0)
> +	    print_spaces_filtered (2 + 2 * recurse, stream);
> +	  if (is_py_none)
> +	    {
> +	      if (is_matrix && strcmp (hint, "array"))
> +		{

I looked at this, and I'm not sure what this means.  Either a hint is
a matrix or an array? Is this trying to deal with children?  I looked
at the modified vector printer and it can return either "array" or
"matrix" depending on the template argument.  


> +gdb_breakpoint [gdb_get_line_number "break"]
> +gdb_continue_to_breakpoint "break"
> +
> +gdb_test "p test1" "vector of length 2, capacity 2 =.*"
> +gdb_test "p test2" "= $nl  {$nl    {.*"
> +gdb_test "p test3" "= $nl  {$nl    {$nl      {.*"
> +

I cannot deduce from this test what the actual content of a vector
printed with the matrix hint should look like beyond the expected
bracket structure.

To be really picky, I'd at least like to see an example of the output
in comments or a more comprehensive test.  I've really gotten into
the idea that tests should also serve as an example of usage somehow.


> Index: testsuite/gdb.python/printers.py
> ===================================================================
> RCS file: testsuite/gdb.python/printers.py
> diff -N testsuite/gdb.python/printers.py

This file cannot exist in the GDB testsuite. It is already hosted
in GCC. You should post any changes to the vector printer there.  
For your testcase, I would write the test so it does not rely on this
file.

Cheers,

Phil

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [patch] pr10659   pretty-printing: Display vectors of vectors as matrix
  2010-05-27 17:46 [patch] pr10659 pretty-printing: Display vectors of vectors as matrix Chris Moller
  2010-05-27 21:14 ` Phil Muldoon
@ 2010-05-27 21:20 ` Tom Tromey
  2010-05-31 23:21   ` [patch] pr10659 pretty-printing: Display vectors of vectors as matrix--rev 2 Chris Moller
  1 sibling, 1 reply; 7+ messages in thread
From: Tom Tromey @ 2010-05-27 21:20 UTC (permalink / raw)
  To: Chris Moller; +Cc: gdb-patches

>>>>> "Chris" == Chris Moller <cmoller@redhat.com> writes:

Chris> This patch adds the mechanism for gdb to respond to "matrix" hints
Chris> from printers.py.

Thanks.

Chris> (Just to exercise the testcase, the patch includes
Chris> a patched version of printers.py to src/gdb/testsuite/gdb.python.  It
Chris> can be removed once the patched printers.py is generally available.)

This is not ok.  This part of the test suite ought to be independent
from the C++ compiler in use.  Instead, write some new code (C is fine)
and an associated printer to exercise the new code in GDB.  There are
other examples of this in gdb.python.

Chris> Question:  pr10659.exp yields:
Chris>    +ERROR: no fileid for qcore
Chris>    +ERROR: Couldn't send python print 'test' to GDB.
Chris>    +UNRESOLVED: gdb.python/pr10659.exp: verify python support
Chris> The actual tests pass, but I haven't the slightest idea how to get rid
Chris> of those errors or even if it's necessary to do so.

skip_python_tests requires a running gdb, so it must come after
prepare_for_testing.

Chris> +  pretty = (is_array || is_matrix)
Chris> +    ? options->prettyprint_arrays : options->pretty;

Wrong formatting.

Chris> +  if (is_matrix && recurse == 0)
Chris> +    fputs_filtered ("\n", stream);

I suspect this is not correct in the !pretty case.
Maybe for !pretty the matrix stuff should just be disabled, I don't see
what it would add.

Chris> +      else if (is_matrix) ;	/* Force a do-nothing.  */

Formatting.  Plus it is better to use empty braces with a comment
between, to emphasize the emptiness.

Chris> +  static int is_matrix = 0;

There has to be a better way.  Static locals like this are generally
bad.

One idea would be a new field in value_print_options.  This may be
slightly difficult depending on how recursion is done in some cases.

Chris> -  is_py_none = print_string_repr (printer, hint, stream, recurse,
Chris> -				  options, language, gdbarch);
Chris> +  is_py_none = is_matrix ? 1 : print_string_repr (printer, hint, stream,
Chris> +						  recurse, options,
Chris> +						  language, gdbarch);

What is the rationale for this change?

Chris> +  if (recurse == 0) is_matrix = 0;

Formatting.  Note also that this approach is not error-safe.  You need a
cleanup.  (Though with the value_print_options approach you won't,
because you can make a new local copy.)

Chris> RCS file: testsuite/gdb.python/printers.py
Chris> diff -N testsuite/gdb.python/printers.py
[...]
Chris> +print "in printers.py"

Debugging code.

Chris> +    def display_hint(self):
Chris> +        itype0  = self.val.type.template_argument(0)
Chris> +        rc = 'array'
Chris> +        if itype0.tag:
Chris> +            if -1 != itype0.tag.find('vector'):

This is not a suitable test.  Instead extract the regular expression
from the recognizer and use that.  Ideally, stuff the compiled form in a
global and use it in both places:

Chris> +    pretty_printers_dict[re.compile('^std::vector<.*>$')] = StdVectorPrinter

Tom

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [patch] pr10659   pretty-printing: Display vectors of vectors as matrix
  2010-05-27 21:14 ` Phil Muldoon
@ 2010-05-27 22:25   ` Chris Moller
  0 siblings, 0 replies; 7+ messages in thread
From: Chris Moller @ 2010-05-27 22:25 UTC (permalink / raw)
  To: Phil Muldoon; +Cc: gdb-patches

On 05/27/10 17:03, Phil Muldoon wrote:
> On 05/27/2010 05:43 PM, Chris Moller wrote:
>    
>> This patch adds the mechanism for gdb to respond to "matrix" hints from
>> printers.py.  (Just to exercise the testcase, the patch includes a
>> patched version of printers.py to src/gdb/testsuite/gdb.python.  It can
>> be removed once the patched printers.py is generally available.)
>>      
>
> This is not an official review, I just have some questions.
>
>    
>> @@ -397,7 +397,7 @@
>> 		struct ui_file *stream, int recurse,
>>   		const struct value_print_options *options,
>>   		const struct language_defn *language,
>> -		int is_py_none)
>> +		int is_py_none, int is_matrix)
>>   {
>>      
>
> I'm not sure why it is necessary to pass the hint in here.  All of the
> other hints are parsed internally within the function?
>    

You mean the is_matrix parm?  That refers to the outer-most type of the 
value.  A matrix in this context is defined as a vector of vectors (of 
vectors (of vectors...))--that's what printers.py identifies to return a 
"matrix" hint.  is_matrix is just a flag indicating that, even when 
dealing with a subordinate element, like a nested vector or value, the 
outer-most type was identified as a matrix.

>
>    
>> -         if (is_py_none)
>> -           fputs_filtered ("{", stream);
>> -         else
>> -           fputs_filtered (" = {", stream);
>> +	  if (is_matrix&&  recurse == 0)
>> +	    print_spaces_filtered (2 + 2 * recurse, stream);
>> +	  if (is_py_none)
>> +	    {
>> +	      if (is_matrix&&  strcmp (hint, "array"))
>> +		{
>>      
>
> I looked at this, and I'm not sure what this means.  Either a hint is
> a matrix or an array? Is this trying to deal with children?  I looked
> at the modified vector printer and it can return either "array" or
> "matrix" depending on the template argument.
>    

Again, is_matrix refers to the outer-most type.  This test identifies 
the current element as an array within a matrix the elements of which 
are not themselves arrays--i.e., they're simple scalars.  It's there so 
that the inner-most array will print as

    {a b c d ...}

rather than

    {
         a b c d ...
    }



>
>    
>> +gdb_breakpoint [gdb_get_line_number "break"]
>> +gdb_continue_to_breakpoint "break"
>> +
>> +gdb_test "p test1" "vector of length 2, capacity 2 =.*"
>> +gdb_test "p test2" "= $nl  {$nl    {.*"
>> +gdb_test "p test3" "= $nl  {$nl    {$nl      {.*"
>> +
>>      
>
> I cannot deduce from this test what the actual content of a vector
> printed with the matrix hint should look like beyond the expected
> bracket structure.
>
> To be really picky, I'd at least like to see an example of the output
> in comments or a more comprehensive test.  I've really gotten into
> the idea that tests should also serve as an example of usage somehow.
>
>    

All I was interested in verifying was the structure and since matrix 
output consists of lots of lines, I didn't want to write the huge regex 
necessary to represent it.  I will if necessary, but it would be easier 
to stick the formatted output in the testcase as a comment.

>    
>> Index: testsuite/gdb.python/printers.py
>> ===================================================================
>> RCS file: testsuite/gdb.python/printers.py
>> diff -N testsuite/gdb.python/printers.py
>>      
>
> This file cannot exist in the GDB testsuite. It is already hosted
> in GCC. You should post any changes to the vector printer there.
> For your testcase, I would write the test so it does not rely on this
> file.
>    

The test doesn't work without a patched version of printers.py, so I 
thought I'd just stick a copy here until the "official" version gets 
promulgated and take it out later.

Chris

> Cheers,
>
> Phil
>    

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [patch] pr10659   pretty-printing: Display vectors of vectors as matrix--rev 2
  2010-05-27 21:20 ` Tom Tromey
@ 2010-05-31 23:21   ` Chris Moller
  2010-06-02 22:58     ` Tom Tromey
  2010-06-30 12:26     ` Jan Kratochvil
  0 siblings, 2 replies; 7+ messages in thread
From: Chris Moller @ 2010-05-31 23:21 UTC (permalink / raw)
  To: tromey; +Cc: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 4375 bytes --]

On 05/27/10 17:14, Tom Tromey wrote:
>>>>>> "Chris" == Chris Moller<cmoller@redhat.com>  writes:
>>>>>>              
>
> Chris>  This patch adds the mechanism for gdb to respond to "matrix" hints
> Chris>  from printers.py.
>
> Thanks.
>
> Chris>  (Just to exercise the testcase, the patch includes
> Chris>  a patched version of printers.py to src/gdb/testsuite/gdb.python.  It
> Chris>  can be removed once the patched printers.py is generally available.)
>
> This is not ok.  This part of the test suite ought to be independent
> from the C++ compiler in use.  Instead, write some new code (C is fine)
> and an associated printer to exercise the new code in GDB.  There are
> other examples of this in gdb.python.
>    

I'm not altogether sure what you meant by this, but what I did was 
rename printers.py to pr10659.py and strip out everything but the 
vector/matrix code and tinker pr10659.exp to match.  This seems to be 
consistent with what py-prettyprint.* does--if I've guessed wrong, let 
me know.

(The real new printers.py has been moved to the right place in svn gcc 
and I'm creating the patch for that even as I type.)

> Chris>  Question:  pr10659.exp yields:
> Chris>     +ERROR: no fileid for qcore
> Chris>     +ERROR: Couldn't send python print 'test' to GDB.
> Chris>     +UNRESOLVED: gdb.python/pr10659.exp: verify python support
> Chris>  The actual tests pass, but I haven't the slightest idea how to get rid
> Chris>  of those errors or even if it's necessary to do so.
>
> skip_python_tests requires a running gdb, so it must come after
> prepare_for_testing.
>    

done

> Chris>  +  pretty = (is_array || is_matrix)
> Chris>  +    ? options->prettyprint_arrays : options->pretty;
>
> Wrong formatting.
>
> Chris>  +  if (is_matrix&&  recurse == 0)
> Chris>  +    fputs_filtered ("\n", stream);
>
> I suspect this is not correct in the !pretty case.
> Maybe for !pretty the matrix stuff should just be disabled, I don't see
> what it would add.
>    

A "matrix" hint turns on pretty mode--this seems to be consistent with 
what an "array" hint does.

> Chris>  +      else if (is_matrix) ;	/* Force a do-nothing.  */
>
> Formatting.  Plus it is better to use empty braces with a comment
> between, to emphasize the emptiness.
>    

done

> Chris>  +  static int is_matrix = 0;
>
> There has to be a better way.  Static locals like this are generally
> bad.
>
> One idea would be a new field in value_print_options.  This may be
> slightly difficult depending on how recursion is done in some cases.
>    

done, using an alloca copy of the options

> Chris>  -  is_py_none = print_string_repr (printer, hint, stream, recurse,
> Chris>  -				  options, language, gdbarch);
> Chris>  +  is_py_none = is_matrix ? 1 : print_string_repr (printer, hint, stream,
> Chris>  +						  recurse, options,
> Chris>  +						  language, gdbarch);
>
> What is the rationale for this change?
>    

print_string_repr() is what prints the "std::vector of length..." stuff which I need to suppress for printing matrices, and matrix formatting needs is_py_none set to 1.


> Chris>  +  if (recurse == 0) is_matrix = 0;
>
> Formatting.  Note also that this approach is not error-safe.  You need a
> cleanup.  (Though with the value_print_options approach you won't,
> because you can make a new local copy.)
>    

see above--replaced by an alloca copy of options and a new matrix flag.
> Chris>  RCS file: testsuite/gdb.python/printers.py
> Chris>  diff -N testsuite/gdb.python/printers.py
> [...]
> Chris>  +print "in printers.py"
>
> Debugging code.
>    

done

> Chris>  +    def display_hint(self):
> Chris>  +        itype0  = self.val.type.template_argument(0)
> Chris>  +        rc = 'array'
> Chris>  +        if itype0.tag:
> Chris>  +            if -1 != itype0.tag.find('vector'):
>
> This is not a suitable test.  Instead extract the regular expression
> from the recognizer and use that.  Ideally, stuff the compiled form in a
> global and use it in both places:
>
> Chris>  +    pretty_printers_dict[re.compile('^std::vector<.*>$')] = StdVectorPrinter
>    

done, but it's part of this patch only as testcase code--the real thing 
is going into gcc.  also, the latest version of printers.py from svn gcc 
was a little different in th pretty_printers_dict stuff and in 
StdVectorPrinter.__init__.  my patch is with respect to that.

> Tom
>    


[-- Attachment #2: pr10659.patch --]
[-- Type: text/x-patch, Size: 13490 bytes --]

Index: ChangeLog
===================================================================
RCS file: /cvs/src/src/gdb/ChangeLog,v
retrieving revision 1.11858
diff -u -r1.11858 ChangeLog
--- ChangeLog	31 May 2010 07:00:40 -0000	1.11858
+++ ChangeLog	31 May 2010 18:35:08 -0000
@@ -1,3 +1,9 @@
+2010-05-31  Chris Moller  <cmoller@redhat.com>
+
+	* python/py-prettyprint.c (print_children): Add formatting for
+	matrices. (apply_val_pretty_printer): Detect and deal with matrix
+	hints. 
+
 2010-05-31  Pierre Muller  <muller@ics.u-strasbg.fr>
 
 	* windows-nat.c (GetConsoleFontSize, GetCurrentConsoleFont):
Index: valprint.h
===================================================================
RCS file: /cvs/src/src/gdb/valprint.h,v
retrieving revision 1.25
diff -u -r1.25 valprint.h
--- valprint.h	1 Jan 2010 07:31:43 -0000	1.25
+++ valprint.h	31 May 2010 18:35:09 -0000
@@ -31,6 +31,9 @@
   /* Controls pretty printing of arrays.  */
   int prettyprint_arrays;
 
+  /* Affects pretty printing of matrices.  */
+  int prettyprint_matrix;
+
   /* Controls pretty printing of structures.  */
   int prettyprint_structs;
 
Index: python/py-prettyprint.c
===================================================================
RCS file: /cvs/src/src/gdb/python/py-prettyprint.c,v
retrieving revision 1.10
diff -u -r1.10 py-prettyprint.c
--- python/py-prettyprint.c	17 May 2010 21:23:25 -0000	1.10
+++ python/py-prettyprint.c	31 May 2010 18:35:10 -0000
@@ -433,7 +433,8 @@
 
   /* Use the prettyprint_arrays option if we are printing an array,
      and the pretty option otherwise.  */
-  pretty = is_array ? options->prettyprint_arrays : options->pretty;
+  pretty = (is_array || options->prettyprint_matrix) ?
+    options->prettyprint_arrays : options->pretty;
 
   /* Manufacture a dummy Python frame to work around Python 2.4 bug,
      where it insists on having a non-NULL tstate->frame when
@@ -445,6 +446,9 @@
       goto done;
     }
   make_cleanup_py_decref (frame);
+  
+  if (options->prettyprint_matrix && recurse == 0)
+    fputs_filtered ("\n", stream);
 
   done_flag = 0;
   for (i = 0; i < options->print_max; ++i)
@@ -479,12 +483,23 @@
 	 3. Other.  Always print a ",".  */
       if (i == 0)
 	{
-         if (is_py_none)
-           fputs_filtered ("{", stream);
-         else
-           fputs_filtered (" = {", stream);
+	  if (options->prettyprint_matrix && recurse == 0)
+	    print_spaces_filtered (2 + 2 * recurse, stream);
+	  if (is_py_none)
+	    {
+	      if (options->prettyprint_matrix && strcmp (hint, "array"))
+		{
+		  fputs_filtered ("{\n", stream);
+		  print_spaces_filtered (4 + 2 * recurse, stream);
+		}
+	      else
+		fputs_filtered ("{", stream);
+	    }
+	  else
+	    fputs_filtered (" = {", stream);
        }
-
+      else if (options->prettyprint_matrix)
+	print_spaces_filtered (4 + 2 * recurse, stream);
       else if (! is_map || i % 2 == 0)
 	fputs_filtered (pretty ? "," : ", ", stream);
 
@@ -513,6 +528,10 @@
 
       if (is_map && i % 2 == 0)
 	fputs_filtered ("[", stream);
+      else if (options->prettyprint_matrix)
+	{
+	  /* Force a do-nothing.  */
+	}
       else if (is_array)
 	{
 	  /* We print the index, not whatever the child method
@@ -587,7 +606,12 @@
 	  fputs_filtered ("\n", stream);
 	  print_spaces_filtered (2 * recurse, stream);
 	}
-      fputs_filtered ("}", stream);
+      if (options->prettyprint_matrix)
+      {
+	print_spaces_filtered (4 * recurse, stream);
+	fputs_filtered ("}\n", stream);
+      }
+      else fputs_filtered ("}", stream);
     }
 
  done:
@@ -609,6 +633,7 @@
   struct cleanup *cleanups;
   int result = 0;
   int is_py_none = 0;
+  struct value_print_options *options_copy;
   cleanups = ensure_python_env (gdbarch, language);
 
   /* Instantiate the printer.  */
@@ -630,12 +655,23 @@
 
   /* If we are printing a map, we want some special formatting.  */
   hint = gdbpy_get_display_hint (printer);
+  
+  if (recurse == 0)
+    {
+      options_copy = alloca (sizeof (struct value_print_options));
+      memcpy (options_copy, options, sizeof (struct value_print_options));
+      options_copy->prettyprint_matrix = hint && !strcmp (hint, "matrix");
+    }
+  else options_copy = (struct value_print_options *)options;
+
   make_cleanup (free_current_contents, &hint);
 
   /* Print the section */
-  is_py_none = print_string_repr (printer, hint, stream, recurse,
-				  options, language, gdbarch);
-  print_children (printer, hint, stream, recurse, options, language,
+  is_py_none = options_copy->prettyprint_matrix ?
+    1 : print_string_repr (printer, hint, stream,
+			   recurse, options_copy,
+			   language, gdbarch);
+  print_children (printer, hint, stream, recurse, options_copy, language,
 		  is_py_none);
 
   result = 1;
Index: testsuite/ChangeLog
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/ChangeLog,v
retrieving revision 1.2294
diff -u -r1.2294 ChangeLog
--- testsuite/ChangeLog	31 May 2010 03:31:16 -0000	1.2294
+++ testsuite/ChangeLog	31 May 2010 18:35:26 -0000
@@ -1,3 +1,10 @@
+2010-05-31  Chris Moller  <cmoller@redhat.com>
+
+	* gdb.python/Makefile.in (EXECUTABLES):  Added pr10659.
+	* gdb.python/pr10659.cc:  New file.
+	* gdb.python/pr10659.exp.  New file.
+	* gdb.python/pr10659.py: New file.
+
 2010-05-31  Jan Kratochvil  <jan.kratochvil@redhat.com>
 
 	Accept the new Linux kernel "t (tracing stop)" string.
Index: testsuite/gdb.python/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.python/Makefile.in,v
retrieving revision 1.6
diff -u -r1.6 Makefile.in
--- testsuite/gdb.python/Makefile.in	9 Apr 2010 09:41:43 -0000	1.6
+++ testsuite/gdb.python/Makefile.in	31 May 2010 18:35:28 -0000
@@ -2,7 +2,7 @@
 srcdir = @srcdir@
 
 EXECUTABLES = py-type py-value py-prettyprint py-template py-block \
-		py-symbol py-mi py-breakpoint
+		py-symbol py-mi py-breakpoint pr10659
 
 all info install-info dvi install uninstall installcheck check:
 	@echo "Nothing to be done for $@..."
Index: testsuite/gdb.python/pr10659.cc
===================================================================
RCS file: testsuite/gdb.python/pr10659.cc
diff -N testsuite/gdb.python/pr10659.cc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.python/pr10659.cc	31 May 2010 18:35:28 -0000
@@ -0,0 +1,43 @@
+#include <list>
+#include <vector>  // /usr/include/c++/4.4.1/bits/vector.tcc
+#include <iostream>
+
+using namespace std;
+
+int use_windows = 9999;
+
+int
+main(){
+  vector<int> test1(2,0);
+  test1[0]=8;
+  test1[1]=9;
+  
+  vector< vector<int> > test2(3, vector<int>(2,0));
+  test2[0][0]=0;
+  test2[0][1]=1;
+  test2[1][0]=2;
+  test2[1][1]=3;
+  test2[2][0]=4;
+  test2[2][1]=5;
+
+#define NR_ROWS    2
+#define NR_COLS    3
+#define NR_PLANES  4
+  vector<int> rows(NR_ROWS, 0);
+  vector< vector<int> > columns(NR_COLS, rows);
+  vector< vector < vector<int> > > test3(NR_PLANES, columns);
+
+  cout << "rows.size() = " << rows.size()
+       << ", columns.size() = " << columns.size()
+       << ", test3.size() = " << test3.size() << "\n";
+
+  for (int i = 0; i < rows.size(); i++) {
+    for (int j = 0; j < columns.size(); j++) {
+      for (int k = 0; k < test3.size(); k++) {
+	test3[k][j][i] = k * 100 + j * 10 + i;
+      }
+    }
+  }
+  
+  return 0;  // break
+}
Index: testsuite/gdb.python/pr10659.exp
===================================================================
RCS file: testsuite/gdb.python/pr10659.exp
diff -N testsuite/gdb.python/pr10659.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.python/pr10659.exp	31 May 2010 18:35:28 -0000
@@ -0,0 +1,82 @@
+#Copyright 2010 Free Software Foundation, Inc.
+
+# This program 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.
+#
+# This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+
+set nl             "\[\r\n\]+"
+
+set testfile pr10659
+set srcfile ${testfile}.cc
+if [prepare_for_testing $testfile.exp $testfile $srcfile {debug c++}] {
+    return -1
+}
+
+if { [skip_python_tests] } { continue }
+
+gdb_test "python execfile(\"$srcdir/$subdir/pr10659.py\")" ""
+gdb_test "python gdb.pretty_printers = \[lookup_function\]" ""
+
+if ![runto_main] then {
+    fail "Can't run to main"
+    return
+}
+
+gdb_breakpoint [gdb_get_line_number "break"]
+gdb_continue_to_breakpoint "break"
+
+gdb_test "p test1" "vector of length 2, capacity 2 =.*"
+
+gdb_test "p test2" "= $nl  {$nl    {.*"
+
+# Complete result is:
+#
+# (gdb) p test2
+# $2 =
+#   {
+#     {0      1    }
+#     {2      3    }
+#     {4      5    }
+#  }
+
+
+gdb_test "p test3" "= $nl  {$nl    {$nl      {.*"
+
+# Complete result is:
+#
+# (gdb) p test3
+# $3 =
+#   {
+#     {
+#       {0        1        }
+#       {10        11        }
+#       {20        21        }
+#     }
+#     {
+#       {100        101        }
+#       {110        111        }
+#       {120        121        }
+#     }
+#     {
+#       {200        201        }
+#       {210        211        }
+#       {220        221        }
+#     }
+#     {
+#       {300        301        }
+#       {310        311        }
+#       {320        321        }
+#     }
+#  }
+# 
+
+
Index: testsuite/gdb.python/pr10659.py
===================================================================
RCS file: testsuite/gdb.python/pr10659.py
diff -N testsuite/gdb.python/pr10659.py
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.python/pr10659.py	31 May 2010 18:35:28 -0000
@@ -0,0 +1,109 @@
+# Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+
+# This program 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.
+#
+# This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+
+import gdb
+import itertools
+import re
+
+vector_sig = 'std::vector'
+vector_regex = re.compile('^' + vector_sig + '<.*>$')
+
+class FakeVectorPrinter:
+    "Print a std::vector"
+
+    class _iterator:
+        def __init__ (self, start, finish):
+            self.item = start
+            self.finish = finish
+            self.count = 0
+
+        def __iter__(self):
+            return self
+
+        def next(self):
+            if self.item == self.finish:
+                raise StopIteration
+            count = self.count
+            self.count = self.count + 1
+            elt = self.item.dereference()
+            self.item = self.item + 1
+            return ('[%d]' % count, elt)
+
+    def __init__(self, typename, val):
+        self.typename = typename
+        self.val = val
+
+    def children(self):
+        return self._iterator(self.val['_M_impl']['_M_start'],
+                              self.val['_M_impl']['_M_finish'])
+
+    def to_string(self):
+        start = self.val['_M_impl']['_M_start']
+        finish = self.val['_M_impl']['_M_finish']
+        end = self.val['_M_impl']['_M_end_of_storage']
+        return ('std::vector of length %d, capacity %d'
+                % (int (finish - start), int (end - start)))
+
+    def display_hint(self):
+        itype0  = self.val.type.template_argument(0)
+        itag = itype0.tag
+        if itag and re.match(vector_regex, itag):
+            rc = 'matrix'
+        else:
+            rc = 'array'
+        return rc
+
+def register_libstdcxx_printers (obj):
+    "Register libstdc++ pretty-printers with objfile Obj."
+
+    if obj == None:
+        obj = gdb
+
+    obj.pretty_printers.append (lookup_function)
+
+def lookup_function (val):
+    "Look-up and return a pretty-printer that can print val."
+
+    # Get the type.
+    type = val.type;
+
+    # If it points to a reference, get the reference.
+    if type.code == gdb.TYPE_CODE_REF:
+        type = type.target ()
+
+    # Get the unqualified type, stripped of typedefs.
+    type = type.unqualified ().strip_typedefs ()
+
+    # Get the type name.    
+    typename = type.tag
+    if typename == None:
+        return None
+
+    # Iterate over local dictionary of types to determine
+    # if a printer is registered for that type.  Return an
+    # instantiation of the printer if found.
+    for function in fake_pretty_printers_dict:
+        if function.search (typename):
+            return fake_pretty_printers_dict[function] (val)
+        
+    # Cannot find a pretty printer.  Return None.
+    return None
+
+def build_libfakecxx_dictionary ():
+    fake_pretty_printers_dict[vector_regex] = lambda val: FakeVectorPrinter(vector_sig, val)
+
+fake_pretty_printers_dict = {}
+
+build_libfakecxx_dictionary ()

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [patch] pr10659   pretty-printing: Display vectors of vectors as matrix--rev 2
  2010-05-31 23:21   ` [patch] pr10659 pretty-printing: Display vectors of vectors as matrix--rev 2 Chris Moller
@ 2010-06-02 22:58     ` Tom Tromey
  2010-06-30 12:26     ` Jan Kratochvil
  1 sibling, 0 replies; 7+ messages in thread
From: Tom Tromey @ 2010-06-02 22:58 UTC (permalink / raw)
  To: Chris Moller; +Cc: gdb-patches

>>>>> "Chris" == Chris Moller <cmoller@redhat.com> writes:

Tom> This is not ok.  This part of the test suite ought to be independent
Tom> from the C++ compiler in use.  Instead, write some new code (C is fine)
Tom> and an associated printer to exercise the new code in GDB.  There are
Tom> other examples of this in gdb.python.

Chris> I'm not altogether sure what you meant by this, but what I did was
Chris> rename printers.py to pr10659.py and strip out everything but the
Chris> vector/matrix code and tinker pr10659.exp to match.  This seems to be
Chris> consistent with what py-prettyprint.* does--if I've guessed wrong, let
Chris> me know.

What I meant is that it is fragile for our test suite to rely on
internal details of std::vector.  Instead, our test suite ought to be as
independent of compilers and libraries as possible.  In this particular
case, there is no reason to rely on std::vector in the test case,
because it is not difficult to write some new test code and a new
printer to exercise the matrix code paths.  This is what is done
elsewhere in gdb.python.

Chris> +  if (is_matrix&&  recurse == 0)
Chris> +    fputs_filtered ("\n", stream);

Tom> I suspect this is not correct in the !pretty case.
Tom> Maybe for !pretty the matrix stuff should just be disabled, I don't see
Tom> what it would add.

Chris> A "matrix" hint turns on pretty mode--this seems to be consistent with
Chris> what an "array" hint does.

There is some confusing terminology here, in that multiple things are
called "pretty printing".

I think as a rule we should only emit newlines when asked for, either by
"set print array" or "set print pretty".  That is what I meant by the
above.

Chris> +  is_py_none = is_matrix ? 1 : print_string_repr (printer, hint, stream,
Chris> +						  recurse, options,
Chris> +						  language, gdbarch);

Tom> What is the rationale for this change?

Chris> print_string_repr() is what prints the "std::vector of length..."
Chris> stuff which I need to suppress for printing matrices, and matrix
Chris> formatting needs is_py_none set to 1.

I see.  I suppose it is ok to suppress the inner ones, but it doesn't
seem correct to suppress the outermost.

Chris> -  pretty = is_array ? options->prettyprint_arrays : options->pretty;
Chris> +  pretty = (is_array || options->prettyprint_matrix) ?
Chris> +    options->prettyprint_arrays : options->pretty;

Wrong formatting.  Also see above about the newline situation...

Chris> +  if (options->prettyprint_matrix && recurse == 0)
Chris> +    fputs_filtered ("\n", stream);

...e.g.

Chris> +      else fputs_filtered ("}", stream);

Formatting.

Chris> +      options_copy = alloca (sizeof (struct value_print_options));
Chris> +      memcpy (options_copy, options, sizeof (struct value_print_options));

Just introduce a new local and copy it unconditionally.

Chris> +  else options_copy = (struct value_print_options *)options;

As a rule, never cast away const.

Chris> +  is_py_none = options_copy->prettyprint_matrix ?
Chris> +    1 : print_string_repr (printer, hint, stream,
Chris> +			   recurse, options_copy,
Chris> +			   language, gdbarch);

Formatting.  Let me recommend reading through the GNU coding standards.
They have a decent section on how C code should be formatted.


Some other general notes..

As this is a general facility for matrix printing, I wonder how you
would handle situations like a 2-dimensional array.

A new printing hint requires an update to the manual.

Please look at how this impacts MI varobjs, if at all.

Tom

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [patch] pr10659   pretty-printing: Display vectors of vectors as matrix--rev 2
  2010-05-31 23:21   ` [patch] pr10659 pretty-printing: Display vectors of vectors as matrix--rev 2 Chris Moller
  2010-06-02 22:58     ` Tom Tromey
@ 2010-06-30 12:26     ` Jan Kratochvil
  1 sibling, 0 replies; 7+ messages in thread
From: Jan Kratochvil @ 2010-06-30 12:26 UTC (permalink / raw)
  To: Chris Moller; +Cc: tromey, gdb-patches

On Mon, 31 May 2010 21:03:00 +0200, Chris Moller wrote:
> --- valprint.h	1 Jan 2010 07:31:43 -0000	1.25
> +++ valprint.h	31 May 2010 18:35:09 -0000
> @@ -31,6 +31,9 @@
>    /* Controls pretty printing of arrays.  */
>    int prettyprint_arrays;
>  
> +  /* Affects pretty printing of matrices.  */
> +  int prettyprint_matrix;
> +
>    /* Controls pretty printing of structures.  */
>    int prettyprint_structs;
>  

This part has massive regression, one sample:
	FAIL: gdb.base/break-entry.exp: running to *0x4002e0 in runto

BTW please use -p for CVS diff (this is `struct value_print_options').


Thanks,
Jan

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2010-06-30 12:26 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-05-27 17:46 [patch] pr10659 pretty-printing: Display vectors of vectors as matrix Chris Moller
2010-05-27 21:14 ` Phil Muldoon
2010-05-27 22:25   ` Chris Moller
2010-05-27 21:20 ` Tom Tromey
2010-05-31 23:21   ` [patch] pr10659 pretty-printing: Display vectors of vectors as matrix--rev 2 Chris Moller
2010-06-02 22:58     ` Tom Tromey
2010-06-30 12:26     ` Jan Kratochvil

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).