Natvis for Corrade types
For displaying Container types more conveniently when debugging in Visual Studio, I created a very very rudimentary .natvis file:
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="Corrade::Containers::Array<*>">
<DisplayString>{{ size={_size} }}</DisplayString>
<Expand>
<ArrayItems>
<Size>_size</Size>
<ValuePointer>_data</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="Corrade::Containers::ArrayView<*>">
<DisplayString>{{ size={_size} }}</DisplayString>
<Expand>
<ArrayItems>
<Size>_size</Size>
<ValuePointer>_data</ValuePointer>
</ArrayItems>
</Expand>
</Type>
</AutoVisualizer>
Make sure to add it to your CMake project's sources so that Visual Studio picks it up.
Also, see the Documentation of NatVis.
More relevant links, in case someone wants to explore further -- ideal would be to make them embedded directly into PDBs when building Corrade itself (and then actually installing those as well):
- https://reviews.llvm.org/D48703
- https://gitlab.kitware.com/cmake/cmake/-/issues/16874
Here's an updated natvis file for most things in Containers 🍌
Haven't quite figured out how to visualize StridedArrayView with dimensions > 1. The natvis format supports a limited way to write your own algorithms, but I'm not desperate enough to try that.
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<!-- Containers::Array -->
<Type Name="Corrade::Containers::Array<*>">
<DisplayString>{{ size={_size} }}</DisplayString>
<Expand>
<Item Name="[deleter]" ExcludeView="simple" Condition="_deleter != nullptr">_deleter</Item>
<Synthetic Name="[deleter]" ExcludeView="simple" Condition="_deleter == nullptr">
<DisplayString>operator delete[]</DisplayString>
</Synthetic>
<ArrayItems>
<Size>_size</Size>
<ValuePointer>_data</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<!-- Containers::ArrayView -->
<Type Name="Corrade::Containers::ArrayView<*>">
<DisplayString>{{ size={_size} }}</DisplayString>
<Expand>
<ArrayItems>
<Size>_size</Size>
<ValuePointer>_data</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<!-- Containers::BitArray -->
<Type Name="Corrade::Containers::BitArray">
<Intrinsic Name="offset" Expression="_sizeOffset & 0x07"/>
<Intrinsic Name="size" Expression="_sizeOffset >> 3"/>
<DisplayString>{{ size={size()} }}</DisplayString>
<Expand>
<Item Name="[deleter]" ExcludeView="simple" Condition="_deleter != nullptr">_deleter</Item>
<Synthetic Name="[deleter]" ExcludeView="simple" Condition="_deleter == nullptr">
<DisplayString>operator delete[]</DisplayString>
</Synthetic>
<IndexListItems>
<Size>size()</Size>
<ValueNode>(bool)(_data[(offset() + $i)/8] & (1 << ((offset() + $i)%8)))</ValueNode>
</IndexListItems>
</Expand>
</Type>
<!-- Containers::[Mutable]BitArrayView -->
<Type Name="Corrade::Containers::BasicBitArrayView<*>">
<Intrinsic Name="offset" Expression="_sizeOffset & 0x07"/>
<Intrinsic Name="size" Expression="_sizeOffset >> 3"/>
<DisplayString>{{ size={size()} }}</DisplayString>
<Expand>
<IndexListItems>
<Size>size()</Size>
<ValueNode>(bool)(_data[(offset() + $i)/8] & (1 << ((offset() + $i)%8)))</ValueNode>
</IndexListItems>
</Expand>
</Type>
<!-- Containers::Optional -->
<Type Name="Corrade::Containers::Optional<*>">
<DisplayString Condition="!_set">NullOpt</DisplayString>
<DisplayString>{_value}</DisplayString>
<Expand>
<ExpandedItem Condition="_set">_value</ExpandedItem>
</Expand>
</Type>
<!-- Containers::Pair -->
<Type Name="Corrade::Containers::Pair<*>">
<DisplayString IncludeView="noparens">{_first}, {_second}</DisplayString>
<DisplayString ExcludeView="noparens">({_first}, {_second})</DisplayString>
<Expand>
<Item Name="first">_first</Item>
<Item Name="second">_second</Item>
</Expand>
</Type>
<!-- Containers::Triple -->
<Type Name="Corrade::Containers::Triple<*>">
<DisplayString IncludeView="noparens">{_first}, {_second}, {_third}</DisplayString>
<DisplayString ExcludeView="noparens">({_first}, {_second}, {_third})</DisplayString>
<Expand>
<Item Name="first">_first</Item>
<Item Name="second">_second</Item>
<Item Name="third">_third</Item>
</Expand>
</Type>
<!-- Containers::Pointer -->
<Type Name="Corrade::Containers::Pointer<*>">
<!-- SmartPointer enables extra visualization for the underlying data -->
<SmartPointer Usage="Minimal">_pointer</SmartPointer>
<DisplayString Condition="!_pointer">empty</DisplayString>
<DisplayString>{*_pointer}</DisplayString>
<Expand>
<ExpandedItem Condition="_pointer">_pointer</ExpandedItem>
</Expand>
</Type>
<!-- Containers::Reference -->
<Type Name="Corrade::Containers::Reference<*>">
<DisplayString>{_reference,na}</DisplayString>
<Expand>
<ExpandedItem>_reference</ExpandedItem>
</Expand>
</Type>
<!-- Containers::StaticArray -->
<Type Name="Corrade::Containers::StaticArray<*>">
<DisplayString>{{ size={$T1} }}</DisplayString>
<Expand>
<ArrayItems>
<Size>$T1</Size>
<ValuePointer>_data</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<!-- Containers::StaticArrayView -->
<Type Name="Corrade::Containers::StaticArrayView<*>">
<DisplayString>{{ size={$T1} }}</DisplayString>
<Expand>
<ArrayItems>
<Size>$T1</Size>
<ValuePointer>_data</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<!-- Containers::StridedArrayView1D -->
<Type Name="Corrade::Containers::StridedArrayView<1,*>">
<DisplayString>{{ size={_size._data[0]} }}</DisplayString>
<Expand>
<Item Name="[stride]" ExcludeView="simple">_stride._data[0]</Item>
<IndexListItems>
<Size>_size._data[0]</Size>
<ValueNode>*($T1 *)((char*)(_data) + $i*_stride._data[0])</ValueNode>
</IndexListItems>
</Expand>
</Type>
<!-- Containers::String -->
<Type Name="Corrade::Containers::String">
<Intrinsic Name="isSmall" Expression="(_small.size & 0x80) != 0"/>
<Intrinsic Name="data" Expression="isSmall() ? _small.data : _large.data"/>
<Intrinsic Name="size" Expression="isSmall() ? _small.size & ~0x80 : _large.size"/>
<!-- String is null-terminated, but can include null-characters before the end, so use explicit size -->
<!-- Display as UTF-8 -->
<DisplayString>{data(),[size()]s8}</DisplayString>
<!-- Note: StringView ("Text Visualizer") supports a range but always cuts off at null-characters -->
<StringView>data(),[size()]s8</StringView>
<Expand>
<Item Name="[size]" ExcludeView="simple">size()</Item>
<Item Name="[deleter]" ExcludeView="simple" Condition="!isSmall() && _large.deleter != nullptr">_large.deleter</Item>
<Synthetic Name="[deleter]" ExcludeView="simple" Condition="!isSmall() && _large.deleter == nullptr">
<DisplayString>operator delete[]</DisplayString>
</Synthetic>
<ArrayItems>
<Size>size()</Size>
<ValuePointer>data()</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<!-- Containers::[Mutable]StringView -->
<Type Name="Corrade::Containers::BasicStringView<*>">
<Intrinsic Name="size" Expression="_sizePlusFlags & ~Implementation::StringViewSizeMask"/>
<Intrinsic Name="flags" Expression="_sizePlusFlags & Implementation::StringViewSizeMask"/>
<DisplayString>{_data,[size()]s8}</DisplayString>
<StringView>_data,[size()]s8</StringView>
<Expand>
<Item Name="[size]" ExcludeView="simple">size()</Item>
<Item Name="[null-terminated]" ExcludeView="simple">(flags() & StringViewFlag::NullTerminated) != 0</Item>
<Item Name="[global]" ExcludeView="simple">(flags() & StringViewFlag::Global) != 0</Item>
<ArrayItems>
<Size>size()</Size>
<ValuePointer>_data</ValuePointer>
</ArrayItems>
</Expand>
</Type>
</AutoVisualizer>
As of 759e3abcf86cfa1a039c782e739ec2ffdb84c7b1, this file is maintained in src/debuggers/natvis/. Thank you!