|  | # -*- coding: utf-8 -*- | 
|  | # This file is part of Eigen, a lightweight C++ template library | 
|  | # for linear algebra. | 
|  | # | 
|  | # Copyright (C) 2021 Huang, Zhaoquan <zhaoquan2008@hotmail.com> | 
|  | # | 
|  | # This Source Code Form is subject to the terms of the Mozilla Public | 
|  | # License, v. 2.0. If a copy of the MPL was not distributed with this | 
|  | # file, You can obtain one at http://mozilla.org/MPL/2.0/. | 
|  |  | 
|  | # Pretty printers for Eigen::Matrix to use with LLDB debugger | 
|  | # | 
|  | # Usage: | 
|  | # 1. Add the following line (change it according to the path to this file) | 
|  | #    to the file ~/.lldbinit (create one if it doesn't exist): | 
|  | #        `command script import /path/to/eigenlldb.py` | 
|  | # 2. Inspect the variables in LLDB command line | 
|  | #        `frame variable` | 
|  |  | 
|  | import lldb | 
|  | from typing import List | 
|  | import bisect | 
|  |  | 
|  |  | 
|  | def __lldb_init_module(debugger, internal_dict): | 
|  | debugger.HandleCommand("type synthetic add -x Eigen::Matrix<.*> --python-class eigenlldb.EigenMatrixChildProvider") | 
|  | debugger.HandleCommand( | 
|  | "type synthetic add -x Eigen::SparseMatrix<.*> --python-class eigenlldb.EigenSparseMatrixChildProvider") | 
|  |  | 
|  |  | 
|  | class EigenMatrixChildProvider: | 
|  | _valobj: lldb.SBValue | 
|  | _scalar_type: lldb.SBType | 
|  | _scalar_size: int | 
|  | _rows_compile_time: int | 
|  | _cols_compile_time: int | 
|  | _row_major: bool | 
|  | _fixed_storage: bool | 
|  |  | 
|  | def __init__(self, valobj, internal_dict): | 
|  | self._valobj = valobj | 
|  | valtype = valobj.GetType().GetCanonicalType() | 
|  |  | 
|  | scalar_type = valtype.GetTemplateArgumentType(0) | 
|  | if not scalar_type.IsValid(): | 
|  | # In the case that scalar_type is invalid on LLDB 9.0 on Windows with CLion | 
|  | storage = valobj.GetChildMemberWithName("m_storage") | 
|  | data = storage.GetChildMemberWithName("m_data") | 
|  | data_type = data.GetType() | 
|  | if data_type.IsPointerType(): | 
|  | scalar_type = data.GetType().GetPointeeType() | 
|  | else: | 
|  | scalar_type = data.GetChildMemberWithName("array").GetType().GetArrayElementType() | 
|  | self._scalar_type = scalar_type | 
|  | self._scalar_size = self._scalar_type.GetByteSize() | 
|  |  | 
|  | name = valtype.GetName() | 
|  | template_begin = name.find("<") | 
|  | template_end = name.find(">") | 
|  | template_args = name[(template_begin + 1):template_end].split(",") | 
|  | self._rows_compile_time = int(template_args[1]) | 
|  | self._cols_compile_time = int(template_args[2]) | 
|  | self._row_major = (int(template_args[3]) & 1) != 0 | 
|  |  | 
|  | max_rows = int(template_args[4]) | 
|  | max_cols = int(template_args[5]) | 
|  | self._fixed_storage = (max_rows != -1 and max_cols != -1) | 
|  |  | 
|  | def num_children(self): | 
|  | return self._cols() * self._rows() | 
|  |  | 
|  | def get_child_index(self, name): | 
|  | pass | 
|  |  | 
|  | def get_child_at_index(self, index): | 
|  | storage = self._valobj.GetChildMemberWithName("m_storage") | 
|  | data = storage.GetChildMemberWithName("m_data") | 
|  | offset = self._scalar_size * index | 
|  |  | 
|  | if self._row_major: | 
|  | row = index // self._cols() | 
|  | col = index % self._cols() | 
|  | else: | 
|  | row = index % self._rows() | 
|  | col = index // self._rows() | 
|  | if self._fixed_storage: | 
|  | data = data.GetChildMemberWithName("array") | 
|  | if self._cols() == 1: | 
|  | name = '[{}]'.format(row) | 
|  | elif self._rows() == 1: | 
|  | name = '[{}]'.format(col) | 
|  | else: | 
|  | name = '[{},{}]'.format(row, col) | 
|  | return data.CreateChildAtOffset( | 
|  | name, offset, self._scalar_type | 
|  | ) | 
|  |  | 
|  | def _cols(self): | 
|  | if self._cols_compile_time == -1: | 
|  | storage = self._valobj.GetChildMemberWithName("m_storage") | 
|  | cols = storage.GetChildMemberWithName("m_cols") | 
|  | return cols.GetValueAsUnsigned() | 
|  | else: | 
|  | return self._cols_compile_time | 
|  |  | 
|  | def _rows(self): | 
|  | if self._rows_compile_time == -1: | 
|  | storage = self._valobj.GetChildMemberWithName("m_storage") | 
|  | rows = storage.GetChildMemberWithName("m_rows") | 
|  | return rows.GetValueAsUnsigned() | 
|  | else: | 
|  | return self._rows_compile_time | 
|  |  | 
|  |  | 
|  | class EigenSparseMatrixChildProvider: | 
|  | _valobj: lldb.SBValue | 
|  | _scalar_type: lldb.SBType | 
|  | _scalar_size: int | 
|  | _index_type: lldb.SBType | 
|  | _index_size: int | 
|  | _row_major: bool | 
|  |  | 
|  | _outer_size: int | 
|  | _nnz: int | 
|  | _values: lldb.SBValue | 
|  | _inner_indices: lldb.SBValue | 
|  | _outer_starts: lldb.SBValue | 
|  | _inner_nnzs: lldb.SBValue | 
|  | _compressed: bool | 
|  |  | 
|  | # Index of the first synthetic child under each outer index | 
|  | _child_indices: List[int] | 
|  |  | 
|  | def __init__(self, valobj, internal_dict): | 
|  | self._valobj = valobj | 
|  | valtype = valobj.GetType().GetCanonicalType() | 
|  | scalar_type = valtype.GetTemplateArgumentType(0) | 
|  | if not scalar_type.IsValid(): | 
|  | # In the case that scalar_type is invalid on LLDB 9.0 on Windows with CLion | 
|  | data = valobj.GetChildMemberWithName("m_data") | 
|  | values = data.GetChildMemberWithName("m_values") | 
|  | scalar_type = values.GetType().GetPointeeType() | 
|  | self._scalar_type = scalar_type | 
|  | self._scalar_size = scalar_type.GetByteSize() | 
|  |  | 
|  | index_type = valtype.GetTemplateArgumentType(2) | 
|  | if not index_type.IsValid(): | 
|  | # In the case that scalar_type is invalid on LLDB 9.0 on Windows with CLion | 
|  | outer_starts = valobj.GetChildMemberWithName("m_outerIndex") | 
|  | index_type = outer_starts.GetType().GetPointeeType() | 
|  | self._index_type = index_type | 
|  | self._index_size = index_type.GetByteSize() | 
|  |  | 
|  | name = valtype.GetName() | 
|  | template_begin = name.find("<") | 
|  | template_end = name.find(">") | 
|  | template_args = name[(template_begin + 1):template_end].split(",") | 
|  | self._row_major = (int(template_args[1]) & 1) != 0 | 
|  |  | 
|  | def num_children(self): | 
|  | return self._nnz + 2 | 
|  |  | 
|  | def get_child_index(self, name): | 
|  | pass | 
|  |  | 
|  | def get_child_at_index(self, index): | 
|  | if index == 0: | 
|  | name = "rows" if self._row_major else "cols" | 
|  | return self._valobj.GetChildMemberWithName("m_outerSize") \ | 
|  | .CreateChildAtOffset(name, 0, self._index_type) | 
|  | elif index == 1: | 
|  | name = "cols" if self._row_major else "rows" | 
|  | return self._valobj.GetChildMemberWithName("m_innerSize") \ | 
|  | .CreateChildAtOffset(name, 0, self._index_type) | 
|  | else: | 
|  | index = index - 2 | 
|  | outer_index = bisect.bisect_right(self._child_indices, index) - 1 | 
|  | total_nnzs = self._child_indices[outer_index] | 
|  | if self._compressed: | 
|  | item_index = index | 
|  | inner_index = self._inner_indices \ | 
|  | .CreateChildAtOffset("", item_index * self._index_size, self._index_type) \ | 
|  | .GetValueAsUnsigned() | 
|  | return self._values \ | 
|  | .CreateChildAtOffset(self._child_name(outer_index, inner_index), | 
|  | item_index * self._scalar_size, | 
|  | self._scalar_type) | 
|  | else: | 
|  | index_begin = self._outer_starts \ | 
|  | .CreateChildAtOffset("", outer_index * self._index_size, self._index_type) \ | 
|  | .GetValueAsUnsigned() | 
|  | item_index = index - total_nnzs + index_begin | 
|  | inner_index = self._inner_indices \ | 
|  | .CreateChildAtOffset("", item_index * self._index_size, self._index_type) \ | 
|  | .GetValueAsUnsigned() | 
|  | return self._values \ | 
|  | .CreateChildAtOffset(self._child_name(outer_index, inner_index), | 
|  | item_index * self._scalar_size, | 
|  | self._scalar_type) | 
|  |  | 
|  | def update(self): | 
|  | valobj = self._valobj | 
|  | self._outer_size = valobj.GetChildMemberWithName("m_outerSize").GetValueAsUnsigned() | 
|  | data = valobj.GetChildMemberWithName("m_data") | 
|  | self._values = data.GetChildMemberWithName("m_values") | 
|  | self._inner_indices = data.GetChildMemberWithName("m_indices") | 
|  | self._outer_starts = valobj.GetChildMemberWithName("m_outerIndex") | 
|  | self._inner_nnzs = valobj.GetChildMemberWithName("m_innerNonZeros") | 
|  |  | 
|  | self._compressed = self._inner_nnzs.GetValueAsUnsigned() == 0 | 
|  |  | 
|  | total_nnzs = 0 | 
|  | child_indices = [0] | 
|  | for outer_index in range(self._outer_size): | 
|  | if self._compressed: | 
|  | index_end = self._outer_starts \ | 
|  | .CreateChildAtOffset("", (outer_index + 1) * self._index_size, self._index_type) \ | 
|  | .GetValueAsUnsigned() | 
|  | total_nnzs = index_end | 
|  | child_indices.append(total_nnzs) | 
|  | else: | 
|  | nnzs = self._inner_nnzs \ | 
|  | .CreateChildAtOffset("", outer_index * self._index_size, self._index_type) \ | 
|  | .GetValueAsUnsigned() | 
|  | total_nnzs = total_nnzs + nnzs | 
|  | child_indices.append(total_nnzs) | 
|  | self._child_indices = child_indices | 
|  | self._nnz = total_nnzs | 
|  |  | 
|  | def _child_name(self, outer_index, inner_index): | 
|  | if self._row_major: | 
|  | return "[{0},{1}]".format(outer_index, inner_index) | 
|  | else: | 
|  | return "[{1},{0}]".format(outer_index, inner_index) |