blob: 0d67a5f998b022afccd06713a33b73b15a12260b [file] [log] [blame]
Brian Silverman72890c22015-09-19 14:37:37 -04001# -*- coding: utf-8 -*-
2# This file is part of Eigen, a lightweight C++ template library
3# for linear algebra.
4#
5# Copyright (C) 2009 Benjamin Schindler <bschindler@inf.ethz.ch>
6#
7# This Source Code Form is subject to the terms of the Mozilla Public
8# License, v. 2.0. If a copy of the MPL was not distributed with this
9# file, You can obtain one at http://mozilla.org/MPL/2.0/.
10
11# Pretty printers for Eigen::Matrix
12# This is still pretty basic as the python extension to gdb is still pretty basic.
13# It cannot handle complex eigen types and it doesn't support any of the other eigen types
14# Such as quaternion or some other type.
15# This code supports fixed size as well as dynamic size matrices
16
17# To use it:
18#
19# * Create a directory and put the file as well as an empty __init__.py in
20# that directory.
21# * Create a ~/.gdbinit file, that contains the following:
22# python
23# import sys
24# sys.path.insert(0, '/path/to/eigen/printer/directory')
25# from printers import register_eigen_printers
26# register_eigen_printers (None)
27# end
28
29import gdb
30import re
31import itertools
32
33
34class EigenMatrixPrinter:
35 "Print Eigen Matrix or Array of some kind"
36
37 def __init__(self, variety, val):
38 "Extract all the necessary information"
39
40 # Save the variety (presumably "Matrix" or "Array") for later usage
41 self.variety = variety
42
43 # The gdb extension does not support value template arguments - need to extract them by hand
44 type = val.type
45 if type.code == gdb.TYPE_CODE_REF:
46 type = type.target()
47 self.type = type.unqualified().strip_typedefs()
48 tag = self.type.tag
49 regex = re.compile('\<.*\>')
50 m = regex.findall(tag)[0][1:-1]
51 template_params = m.split(',')
Austin Schuh189376f2018-12-20 22:11:15 +110052 template_params = [x.replace(" ", "") for x in template_params]
Brian Silverman72890c22015-09-19 14:37:37 -040053
54 if template_params[1] == '-0x00000000000000001' or template_params[1] == '-0x000000001' or template_params[1] == '-1':
55 self.rows = val['m_storage']['m_rows']
56 else:
57 self.rows = int(template_params[1])
58
59 if template_params[2] == '-0x00000000000000001' or template_params[2] == '-0x000000001' or template_params[2] == '-1':
60 self.cols = val['m_storage']['m_cols']
61 else:
62 self.cols = int(template_params[2])
63
64 self.options = 0 # default value
65 if len(template_params) > 3:
66 self.options = template_params[3];
67
68 self.rowMajor = (int(self.options) & 0x1)
69
70 self.innerType = self.type.template_argument(0)
71
72 self.val = val
73
74 # Fixed size matrices have a struct as their storage, so we need to walk through this
75 self.data = self.val['m_storage']['m_data']
76 if self.data.type.code == gdb.TYPE_CODE_STRUCT:
77 self.data = self.data['array']
78 self.data = self.data.cast(self.innerType.pointer())
79
80 class _iterator:
81 def __init__ (self, rows, cols, dataPtr, rowMajor):
82 self.rows = rows
83 self.cols = cols
84 self.dataPtr = dataPtr
85 self.currentRow = 0
86 self.currentCol = 0
87 self.rowMajor = rowMajor
88
89 def __iter__ (self):
90 return self
Austin Schuh189376f2018-12-20 22:11:15 +110091
Brian Silverman72890c22015-09-19 14:37:37 -040092 def next(self):
Austin Schuh189376f2018-12-20 22:11:15 +110093 return self.__next__() # Python 2.x compatibility
94
95 def __next__(self):
Brian Silverman72890c22015-09-19 14:37:37 -040096
97 row = self.currentRow
98 col = self.currentCol
99 if self.rowMajor == 0:
100 if self.currentCol >= self.cols:
101 raise StopIteration
102
103 self.currentRow = self.currentRow + 1
104 if self.currentRow >= self.rows:
105 self.currentRow = 0
106 self.currentCol = self.currentCol + 1
107 else:
108 if self.currentRow >= self.rows:
109 raise StopIteration
110
111 self.currentCol = self.currentCol + 1
112 if self.currentCol >= self.cols:
113 self.currentCol = 0
114 self.currentRow = self.currentRow + 1
115
116
117 item = self.dataPtr.dereference()
118 self.dataPtr = self.dataPtr + 1
119 if (self.cols == 1): #if it's a column vector
120 return ('[%d]' % (row,), item)
121 elif (self.rows == 1): #if it's a row vector
122 return ('[%d]' % (col,), item)
123 return ('[%d,%d]' % (row, col), item)
124
125 def children(self):
126
127 return self._iterator(self.rows, self.cols, self.data, self.rowMajor)
128
129 def to_string(self):
130 return "Eigen::%s<%s,%d,%d,%s> (data ptr: %s)" % (self.variety, self.innerType, self.rows, self.cols, "RowMajor" if self.rowMajor else "ColMajor", self.data)
131
132class EigenQuaternionPrinter:
133 "Print an Eigen Quaternion"
134
135 def __init__(self, val):
136 "Extract all the necessary information"
137 # The gdb extension does not support value template arguments - need to extract them by hand
138 type = val.type
139 if type.code == gdb.TYPE_CODE_REF:
140 type = type.target()
141 self.type = type.unqualified().strip_typedefs()
142 self.innerType = self.type.template_argument(0)
143 self.val = val
144
145 # Quaternions have a struct as their storage, so we need to walk through this
146 self.data = self.val['m_coeffs']['m_storage']['m_data']['array']
147 self.data = self.data.cast(self.innerType.pointer())
148
149 class _iterator:
150 def __init__ (self, dataPtr):
151 self.dataPtr = dataPtr
152 self.currentElement = 0
153 self.elementNames = ['x', 'y', 'z', 'w']
154
155 def __iter__ (self):
156 return self
Austin Schuh189376f2018-12-20 22:11:15 +1100157
Brian Silverman72890c22015-09-19 14:37:37 -0400158 def next(self):
Austin Schuh189376f2018-12-20 22:11:15 +1100159 return self.__next__() # Python 2.x compatibility
160
161 def __next__(self):
Brian Silverman72890c22015-09-19 14:37:37 -0400162 element = self.currentElement
163
164 if self.currentElement >= 4: #there are 4 elements in a quanternion
165 raise StopIteration
166
167 self.currentElement = self.currentElement + 1
168
169 item = self.dataPtr.dereference()
170 self.dataPtr = self.dataPtr + 1
171 return ('[%s]' % (self.elementNames[element],), item)
172
173 def children(self):
174
175 return self._iterator(self.data)
176
177 def to_string(self):
178 return "Eigen::Quaternion<%s> (data ptr: %s)" % (self.innerType, self.data)
179
180def build_eigen_dictionary ():
181 pretty_printers_dict[re.compile('^Eigen::Quaternion<.*>$')] = lambda val: EigenQuaternionPrinter(val)
182 pretty_printers_dict[re.compile('^Eigen::Matrix<.*>$')] = lambda val: EigenMatrixPrinter("Matrix", val)
183 pretty_printers_dict[re.compile('^Eigen::Array<.*>$')] = lambda val: EigenMatrixPrinter("Array", val)
184
185def register_eigen_printers(obj):
186 "Register eigen pretty-printers with objfile Obj"
187
188 if obj == None:
189 obj = gdb
190 obj.pretty_printers.append(lookup_function)
191
192def lookup_function(val):
193 "Look-up and return a pretty-printer that can print va."
194
195 type = val.type
196
197 if type.code == gdb.TYPE_CODE_REF:
198 type = type.target()
199
200 type = type.unqualified().strip_typedefs()
201
202 typename = type.tag
203 if typename == None:
204 return None
205
206 for function in pretty_printers_dict:
207 if function.search(typename):
208 return pretty_printers_dict[function](val)
209
210 return None
211
212pretty_printers_dict = {}
213
214build_eigen_dictionary ()