You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

208 lines
6.2 KiB

  1. # -*- 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. # Pretty printers for Eigen::Matrix
  11. # This is still pretty basic as the python extension to gdb is still pretty basic.
  12. # It cannot handle complex eigen types and it doesn't support any of the other eigen types
  13. # Such as quaternion or some other type.
  14. # This code supports fixed size as well as dynamic size matrices
  15. # To use it:
  16. #
  17. # * Create a directory and put the file as well as an empty __init__.py in
  18. # that directory.
  19. # * Create a ~/.gdbinit file, that contains the following:
  20. # python
  21. # import sys
  22. # sys.path.insert(0, '/path/to/eigen/printer/directory')
  23. # from printers import register_eigen_printers
  24. # register_eigen_printers (None)
  25. # end
  26. import gdb
  27. import re
  28. import itertools
  29. class EigenMatrixPrinter:
  30. "Print Eigen Matrix or Array of some kind"
  31. def __init__(self, variety, val):
  32. "Extract all the necessary information"
  33. # Save the variety (presumably "Matrix" or "Array") for later usage
  34. self.variety = variety
  35. # The gdb extension does not support value template arguments - need to extract them by hand
  36. type = val.type
  37. if type.code == gdb.TYPE_CODE_REF:
  38. type = type.target()
  39. self.type = type.unqualified().strip_typedefs()
  40. tag = self.type.tag
  41. regex = re.compile('\<.*\>')
  42. m = regex.findall(tag)[0][1:-1]
  43. template_params = m.split(',')
  44. template_params = map(lambda x:x.replace(" ", ""), template_params)
  45. if template_params[1] == '-0x00000000000000001' or template_params[1] == '-0x000000001' or template_params[1] == '-1':
  46. self.rows = val['m_storage']['m_rows']
  47. else:
  48. self.rows = int(template_params[1])
  49. if template_params[2] == '-0x00000000000000001' or template_params[2] == '-0x000000001' or template_params[2] == '-1':
  50. self.cols = val['m_storage']['m_cols']
  51. else:
  52. self.cols = int(template_params[2])
  53. self.options = 0 # default value
  54. if len(template_params) > 3:
  55. self.options = template_params[3];
  56. self.rowMajor = (int(self.options) & 0x1)
  57. self.innerType = self.type.template_argument(0)
  58. self.val = val
  59. # Fixed size matrices have a struct as their storage, so we need to walk through this
  60. self.data = self.val['m_storage']['m_data']
  61. if self.data.type.code == gdb.TYPE_CODE_STRUCT:
  62. self.data = self.data['array']
  63. self.data = self.data.cast(self.innerType.pointer())
  64. class _iterator:
  65. def __init__ (self, rows, cols, dataPtr, rowMajor):
  66. self.rows = rows
  67. self.cols = cols
  68. self.dataPtr = dataPtr
  69. self.currentRow = 0
  70. self.currentCol = 0
  71. self.rowMajor = rowMajor
  72. def __iter__ (self):
  73. return self
  74. def next(self):
  75. row = self.currentRow
  76. col = self.currentCol
  77. if self.rowMajor == 0:
  78. if self.currentCol >= self.cols:
  79. raise StopIteration
  80. self.currentRow = self.currentRow + 1
  81. if self.currentRow >= self.rows:
  82. self.currentRow = 0
  83. self.currentCol = self.currentCol + 1
  84. else:
  85. if self.currentRow >= self.rows:
  86. raise StopIteration
  87. self.currentCol = self.currentCol + 1
  88. if self.currentCol >= self.cols:
  89. self.currentCol = 0
  90. self.currentRow = self.currentRow + 1
  91. item = self.dataPtr.dereference()
  92. self.dataPtr = self.dataPtr + 1
  93. if (self.cols == 1): #if it's a column vector
  94. return ('[%d]' % (row,), item)
  95. elif (self.rows == 1): #if it's a row vector
  96. return ('[%d]' % (col,), item)
  97. return ('[%d,%d]' % (row, col), item)
  98. def children(self):
  99. return self._iterator(self.rows, self.cols, self.data, self.rowMajor)
  100. def to_string(self):
  101. 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)
  102. class EigenQuaternionPrinter:
  103. "Print an Eigen Quaternion"
  104. def __init__(self, val):
  105. "Extract all the necessary information"
  106. # The gdb extension does not support value template arguments - need to extract them by hand
  107. type = val.type
  108. if type.code == gdb.TYPE_CODE_REF:
  109. type = type.target()
  110. self.type = type.unqualified().strip_typedefs()
  111. self.innerType = self.type.template_argument(0)
  112. self.val = val
  113. # Quaternions have a struct as their storage, so we need to walk through this
  114. self.data = self.val['m_coeffs']['m_storage']['m_data']['array']
  115. self.data = self.data.cast(self.innerType.pointer())
  116. class _iterator:
  117. def __init__ (self, dataPtr):
  118. self.dataPtr = dataPtr
  119. self.currentElement = 0
  120. self.elementNames = ['x', 'y', 'z', 'w']
  121. def __iter__ (self):
  122. return self
  123. def next(self):
  124. element = self.currentElement
  125. if self.currentElement >= 4: #there are 4 elements in a quanternion
  126. raise StopIteration
  127. self.currentElement = self.currentElement + 1
  128. item = self.dataPtr.dereference()
  129. self.dataPtr = self.dataPtr + 1
  130. return ('[%s]' % (self.elementNames[element],), item)
  131. def children(self):
  132. return self._iterator(self.data)
  133. def to_string(self):
  134. return "Eigen::Quaternion<%s> (data ptr: %s)" % (self.innerType, self.data)
  135. def build_eigen_dictionary ():
  136. pretty_printers_dict[re.compile('^Eigen::Quaternion<.*>$')] = lambda val: EigenQuaternionPrinter(val)
  137. pretty_printers_dict[re.compile('^Eigen::Matrix<.*>$')] = lambda val: EigenMatrixPrinter("Matrix", val)
  138. pretty_printers_dict[re.compile('^Eigen::Array<.*>$')] = lambda val: EigenMatrixPrinter("Array", val)
  139. def register_eigen_printers(obj):
  140. "Register eigen pretty-printers with objfile Obj"
  141. if obj == None:
  142. obj = gdb
  143. obj.pretty_printers.append(lookup_function)
  144. def lookup_function(val):
  145. "Look-up and return a pretty-printer that can print va."
  146. type = val.type
  147. if type.code == gdb.TYPE_CODE_REF:
  148. type = type.target()
  149. type = type.unqualified().strip_typedefs()
  150. typename = type.tag
  151. if typename == None:
  152. return None
  153. for function in pretty_printers_dict:
  154. if function.search(typename):
  155. return pretty_printers_dict[function](val)
  156. return None
  157. pretty_printers_dict = {}
  158. build_eigen_dictionary ()