| <?xml version="1.0" encoding="utf-8"?> |
| <AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> |
| <!-- |
| std::collection::Hash* container visualizers |
| |
| Current std impls: |
| std::collections::hash::set::HashSet<K, S> is implemented in terms of... |
| std::collections::hash::map::HashMap<K, V, S> is implemented in terms of... |
| hashbrown::map::HashMap<K, V, S> is implemented in terms of... |
| hashbrown::raw::RawTable<(K, V)> |
| |
| Ideally, we'd teach rustc to scan dependencies/crates for .natvis files so |
| the bulk of this could live alongside the hashbrown crate implementation, |
| and std would just forward using e.g. <ExpandedItem>base</ExpandedItem>. |
| |
| However, Given that std...Hash*Set* is currently implemented in terms of |
| hashbrown...Hash*Map*, which would visualize poorly, we want to customize the |
| look/feel at the std type level *anyways*... |
| |
| References: |
| https://github.com/rust-lang/rust/blob/master/src/libstd/collections/hash/map.rs |
| https://github.com/rust-lang/rust/blob/master/src/libstd/collections/hash/set.rs |
| https://github.com/rust-lang/hashbrown/blob/master/src/map.rs |
| https://github.com/rust-lang/hashbrown/blob/master/src/set.rs |
| https://github.com/rust-lang/hashbrown/blob/master/src/raw/mod.rs |
| --> |
| |
| <Type Name="std::collections::hash::map::HashMap<*,*,*>"> |
| <DisplayString>{{ size={base.table.items} }}</DisplayString> |
| <Expand> |
| <Item Name="[size]">base.table.items</Item> |
| <Item Name="[capacity]">base.table.items + base.table.growth_left</Item> |
| |
| <CustomListItems> |
| <Variable Name="i" InitialValue="0" /> |
| <Variable Name="n" InitialValue="base.table.items" /> |
| <Size>base.table.items</Size> |
| <Loop> |
| <Break Condition="n == 0" /> |
| <If Condition="(base.table.ctrl.pointer[i] & 0x80) == 0"> |
| <!-- Bucket is populated --> |
| <Exec>n--</Exec> |
| <Item Name="{base.table.data.pointer[i].__0}">base.table.data.pointer[i].__1</Item> |
| </If> |
| <Exec>i++</Exec> |
| </Loop> |
| </CustomListItems> |
| </Expand> |
| </Type> |
| |
| <Type Name="std::collections::hash::set::HashSet<*,*>"> |
| <DisplayString>{{ size={map.base.table.items} }}</DisplayString> |
| <Expand> |
| <Item Name="[size]">map.base.table.items</Item> |
| <Item Name="[capacity]">map.base.table.items + map.base.table.growth_left</Item> |
| |
| <CustomListItems> |
| <Variable Name="i" InitialValue="0" /> |
| <Variable Name="n" InitialValue="map.base.table.items" /> |
| <Size>map.base.table.items</Size> |
| <Loop> |
| <Break Condition="n == 0" /> |
| <If Condition="(map.base.table.ctrl.pointer[i] & 0x80) == 0"> |
| <!-- Bucket is populated --> |
| <Exec>n--</Exec> |
| <Item>map.base.table.data.pointer[i].__0</Item> |
| </If> |
| <Exec>i++</Exec> |
| </Loop> |
| </CustomListItems> |
| </Expand> |
| </Type> |
| |
| <Type Name="hashbrown::raw::RawTable<*>"> |
| <!-- RawTable has a nice and simple layout. |
| items Number of *populated* values in the RawTable (less than the size of ctrl.pointer / data.pointer) |
| growth_left Remaining capacity before growth |
| ctrl.pointer[i] & 0x80 Indicates the bucket is empty / should be skipped / doesn't count towards items. |
| data.pointer[i] The (K,V) tuple, if not empty. |
| --> |
| <DisplayString>{{ size={items} }}</DisplayString> |
| <Expand> |
| <Item Name="[size]">items</Item> |
| <Item Name="[capacity]">items + growth_left</Item> |
| |
| <CustomListItems> |
| <Variable Name="i" InitialValue="0" /> |
| <Variable Name="n" InitialValue="items" /> |
| <Size>items</Size> |
| <Loop> |
| <Break Condition="n == 0" /> |
| <If Condition="(ctrl.pointer[i] & 0x80) == 0"> |
| <!-- Bucket is populated --> |
| <Exec>n--</Exec> |
| <Item>data.pointer[i]</Item> |
| </If> |
| <Exec>i++</Exec> |
| </Loop> |
| </CustomListItems> |
| </Expand> |
| </Type> |
| </AutoVisualizer> |