diff --git a/CMakeLists.txt b/CMakeLists.txt
index d1e25ea..86b23bf 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -10,6 +10,7 @@ endif()
if(MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
add_definitions(-D_CRT_SECURE_NO_DEPRECATE)
+ add_definitions(-DDL_NATVIS_ENABLED=1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /WX")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4324") # structure was padded due to alignment specifier
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4127") # conditional expression is constant
@@ -124,3 +125,17 @@ if (DATA_LIBRARY_BENCHMARK)
target_link_libraries(dlbench PRIVATE data_library)
include_directories(src include build/local)
endif()
+
+if ((CMAKE_VERSION GREATER 3.7.9) OR (CMAKE_VERSION EQUAL 3.7.9))
+ if (MSVC_IDE)
+ option(VS_ADD_NATIVE_VISUALIZERS "Configure project to use Visual Studio native visualizers" TRUE)
+ else()
+ set(VS_ADD_NATIVE_VISUALIZERS FALSE CACHE INTERNAL "Native visualizers are Visual Studio extension" FORCE)
+ endif()
+ # add natvis file to the library so it will automatically be loaded into Visual Studio
+ if(VS_ADD_NATIVE_VISUALIZERS)
+ target_sources(GSL INTERFACE
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/datalibrary.natvis
+ )
+ endif()
+endif()
diff --git a/src/datalibrary.natvis b/src/datalibrary.natvis
new file mode 100644
index 0000000..37c0457
--- /dev/null
+++ b/src/datalibrary.natvis
@@ -0,0 +1,245 @@
+
+
+
+
+ {str,[len]s8}
+ str,[len]s8
+
+
+ Change g_DlDebuggingContext in watch window
+ struct {(*ctx)->typedata_strings + name,s8b} {{{member_count,u} members}}
+ struct {(*ctx)->typedata_strings + name,s8b} {{{*((*ctx)->member_descs + member_start)}; {*((*ctx)->member_descs + member_start + 1)}; {*((*ctx)->member_descs + member_start + 2)};}}
+ struct {(*ctx)->typedata_strings + name,s8b} {{{*((*ctx)->member_descs + member_start)}; {*((*ctx)->member_descs + member_start + 1)};}}
+ struct {(*ctx)->typedata_strings + name,s8b} {{{*((*ctx)->member_descs + member_start)};]
+
+ - (*ctx)->typedata_strings + name,s8
+ - (*ctx)->type_ids[this - (*ctx)->type_descs],X
+ - (*ctx)->typedata_strings + comment,s8
+
+ Count: {member_count,u}, {{{*((*ctx)->member_descs + member_start)}; {*((*ctx)->member_descs + member_start + 1)}; {*((*ctx)->member_descs + member_start + 2)}; ...}}
+ Count: {member_count,u}, {{{*((*ctx)->member_descs + member_start)}; {*((*ctx)->member_descs + member_start + 1)}; {*((*ctx)->member_descs + member_start + 2)};}}
+ Count: {member_count,u}, {{{*((*ctx)->member_descs + member_start)}; {*((*ctx)->member_descs + member_start + 1)};}}
+ Count: {member_count,u}, {{{*((*ctx)->member_descs + member_start)};]
+
+
+ member_count
+ (*ctx)->member_descs + member_start
+
+
+
+ - flags
+ - size[DL_PTR_SIZE_HOST]
+ - alignment[DL_PTR_SIZE_HOST]
+
+ Count: {metadata_count,u}
+
+
+ metadata_count
+ (*ctx)->metadatas + metadata_start
+
+
+
+
+
+
+ Change g_DlDebuggingContext in watch window
+ int8 {(*ctx)->typedata_strings + name,s8b}
+ int16 {(*ctx)->typedata_strings + name,s8b}
+ int32 {(*ctx)->typedata_strings + name,s8b}
+ int64 {(*ctx)->typedata_strings + name,s8b}
+ uint8 {(*ctx)->typedata_strings + name,s8b}
+ uint16 {(*ctx)->typedata_strings + name,s8b}
+ uint32 {(*ctx)->typedata_strings + name,s8b}
+ uint64 {(*ctx)->typedata_strings + name,s8b}
+ float {(*ctx)->typedata_strings + name,s8b}
+ double {(*ctx)->typedata_strings + name,s8b}
+ enum:int8 {(*ctx)->typedata_strings + name,s8b}
+ enum:int16 {(*ctx)->typedata_strings + name,s8b}
+ enum:int32 {(*ctx)->typedata_strings + name,s8b}
+ enum:int64 {(*ctx)->typedata_strings + name,s8b}
+ enum:uint8 {(*ctx)->typedata_strings + name,s8b}
+ enum:uint16 {(*ctx)->typedata_strings + name,s8b}
+ enum:uint32 {(*ctx)->typedata_strings + name,s8b}
+ enum:uint64 {(*ctx)->typedata_strings + name,s8b}
+ const char* {(*ctx)->typedata_strings + name,s8b}
+ ptr {(*ctx)->typedata_strings + name,s8b}
+ struct {(*ctx)->typedata_strings + name,s8b}
+ anypointer {(*ctx)->typedata_strings + name,s8b}
+ anyarray {(*ctx)->typedata_strings + name,s8b}
+ dl_array<int8> {(*ctx)->typedata_strings + name,s8b}
+ dl_array<int16> {(*ctx)->typedata_strings + name,s8b}
+ dl_array<int32> {(*ctx)->typedata_strings + name,s8b}
+ dl_array<int64> {(*ctx)->typedata_strings + name,s8b}
+ dl_array<uint8> {(*ctx)->typedata_strings + name,s8b}
+ dl_array<uint16> {(*ctx)->typedata_strings + name,s8b}
+ dl_array<uint32> {(*ctx)->typedata_strings + name,s8b}
+ dl_array<uint64> {(*ctx)->typedata_strings + name,s8b}
+ dl_array<float> {(*ctx)->typedata_strings + name,s8b}
+ dl_array<double> {(*ctx)->typedata_strings + name,s8b}
+ dl_array<enum:int8> {(*ctx)->typedata_strings + name,s8b}
+ dl_array<enum:int16> {(*ctx)->typedata_strings + name,s8b}
+ dl_array<enum:int32> {(*ctx)->typedata_strings + name,s8b}
+ dl_array<enum:int64> {(*ctx)->typedata_strings + name,s8b}
+ dl_array<enum:uint8> {(*ctx)->typedata_strings + name,s8b}
+ dl_array<enum:uint16> {(*ctx)->typedata_strings + name,s8b}
+ dl_array<enum:uint32> {(*ctx)->typedata_strings + name,s8b}
+ dl_array<enum:uint64> {(*ctx)->typedata_strings + name,s8b}
+ dl_array<const char*> {(*ctx)->typedata_strings + name,s8b}
+ dl_array<ptr> {(*ctx)->typedata_strings + name,s8b}
+ dl_array<struct> {(*ctx)->typedata_strings + name,s8b}
+ dl_array<anypointer> {(*ctx)->typedata_strings + name,s8b}
+ dl_array<anyarray> {(*ctx)->typedata_strings + name,s8b}
+ int8 {(*ctx)->typedata_strings + name,s8b}[{type>>16,u}]
+ int16 {(*ctx)->typedata_strings + name,s8b}[{type>>16,u}]
+ int32 {(*ctx)->typedata_strings + name,s8b}[{type>>16,u}]
+ int64 {(*ctx)->typedata_strings + name,s8b}[{type>>16,u}]
+ uint8 {(*ctx)->typedata_strings + name,s8b}[{type>>16,u}]
+ uint16 {(*ctx)->typedata_strings + name,s8b}[{type>>16,u}]
+ uint32 {(*ctx)->typedata_strings + name,s8b}[{type>>16,u}]
+ uint64 {(*ctx)->typedata_strings + name,s8b}[{type>>16,u}]
+ float {(*ctx)->typedata_strings + name,s8b}[{type>>16,u}]
+ double {(*ctx)->typedata_strings + name,s8b}[{type>>16,u}]
+ enum:int8 {(*ctx)->typedata_strings + name,s8b}[{type>>16,u}]
+ enum:int16 {(*ctx)->typedata_strings + name,s8b}[{type>>16,u}]
+ enum:int32 {(*ctx)->typedata_strings + name,s8b}[{type>>16,u}]
+ enum:int64 {(*ctx)->typedata_strings + name,s8b}[{type>>16,u}]
+ enum:uint8 {(*ctx)->typedata_strings + name,s8b}[{type>>16,u}]
+ enum:uint16 {(*ctx)->typedata_strings + name,s8b}[{type>>16,u}]
+ enum:uint32 {(*ctx)->typedata_strings + name,s8b}[{type>>16,u}]
+ enum:uint64 {(*ctx)->typedata_strings + name,s8b}[{type>>16,u}]
+ const char* {(*ctx)->typedata_strings + name,s8b}[{type>>16,u}]
+ ptr {(*ctx)->typedata_strings + name,s8b}[{type>>16,u}]
+ struct {(*ctx)->typedata_strings + name,s8b}[{type>>16,u}]
+ anypointer {(*ctx)->typedata_strings + name,s8b}[{type>>16,u}]
+ anyarray {(*ctx)->typedata_strings + name,s8b}[{type>>16,u}]
+ uint8 {(*ctx)->typedata_strings + name,s8b}:{(type>>16)&0xFF,u}
+ uint16 {(*ctx)->typedata_strings + name,s8b}:{(type>>16)&0xFF,u}
+ uint32 {(*ctx)->typedata_strings + name,s8b}:{(type>>16)&0xFF,u}
+ uint64 {(*ctx)->typedata_strings + name,s8b}:{(type>>16)&0xFF,u}
+ {(*ctx)->typedata_strings + name,s8b}, {(dl_type_atom_t)(type & 0xFF)}
+
+ - (*ctx)->typedata_strings + name,s8
+ - (*ctx)->typedata_strings + comment,s8
+ - (dl_type_atom_t)(type & 0xFF)
+ - (dl_type_storage_t)((type >> 8) & 0xFF)
+ - flags
+ - type_id,X
+ - offset[DL_PTR_SIZE_HOST]
+ - (type>>24)&0xFF,u
+ - (type>>16)&0xFF,u
+ - size[DL_PTR_SIZE_HOST]
+ - alignment[DL_PTR_SIZE_HOST]
+
+
+
+ default_value_size
+ (*ctx)->default_data + default_value_offset
+
+
+
+
+ Count: {metadata_count,u}
+
+
+ metadata_count
+ (*ctx)->metadatas + metadata_start
+
+
+
+
+
+
+ Change g_DlDebuggingContext in watch window
+ {(*ctx)->typedata_strings + name,s8}
+
+ - (*ctx)->typedata_strings + name,s8
+ - (*ctx)->typedata_strings + comment,s8
+ - storage
+ - flags
+
+ Count: {value_count,u}, [{*((*ctx)->enum_value_descs + value_start)}...]
+
+
+ value_count
+ (*ctx)->enum_value_descs + value_start
+
+
+
+
+ Count: {alias_count,u}, [{*((*ctx)->enum_alias_descs + alias_start)}...]
+
+
+ alias_count
+ (*ctx)->enum_alias_descs + alias_start
+
+
+
+
+ Count: {metadata_count,u}
+
+
+ metadata_count
+ (*ctx)->metadatas + metadata_start
+
+
+
+
+
+
+ Change g_DlDebuggingContext in watch window
+ {(*ctx)->enum_alias_descs + main_alias,na}
+
+ - (*ctx)->enum_alias_descs + main_alias,na
+ - value
+ - (*ctx)->typedata_strings + comment,s8
+
+ Count: {metadata_count,u}
+
+
+ metadata_count
+ (*ctx)->metadatas + metadata_start
+
+
+
+
+
+
+ Change g_DlDebuggingContext in watch window
+ {(*ctx)->typedata_strings + name,s8}
+
+ - (*ctx)->typedata_strings + name,s8
+ - value_index
+
+
+
+
+
+ Size:{type_count}, Capacity:{type_capacity}
+
+
+ type_count
+ type_descs
+
+
+
+
+ Size:{enum_count}, Capacity:{enum_capacity}
+
+
+ enum_count
+ enum_descs
+
+
+
+
+
+
+ Size = {count}
+
+
+ count
+ data
+
+
+
+
diff --git a/src/dl.cpp b/src/dl.cpp
index bb1b2d1..24c09eb 100644
--- a/src/dl.cpp
+++ b/src/dl.cpp
@@ -7,6 +7,18 @@
#include
+#if DL_NATVIS_ENABLED
+// g_DlActiveNatvisCtx controls what context the Visual Studio Natvis framework will use when presenting information about types in the debugger windows
+// This global g_DlActiveNatvisCtx is only used indirectly, the debugger only uses the dl_*::ctx variables which are two level pointers to the context
+// Manually change g_DlActiveNatvisCtx in the debugger if you want to view a different context
+dl_ctx_t g_DlActiveNatvisCtx = nullptr;
+const dl_ctx_t* dl_type_desc::ctx = &g_DlActiveNatvisCtx;
+const dl_ctx_t* dl_member_desc::ctx = &g_DlActiveNatvisCtx;
+const dl_ctx_t* dl_enum_value_desc::ctx = &g_DlActiveNatvisCtx;
+const dl_ctx_t* dl_enum_desc::ctx = &g_DlActiveNatvisCtx;
+const dl_ctx_t* dl_enum_alias_desc::ctx = &g_DlActiveNatvisCtx;
+#endif
+
dl_error_t dl_context_create( dl_ctx_t* dl_ctx, dl_create_params_t* create_params )
{
dl_allocator alloc;
@@ -25,6 +37,10 @@ dl_error_t dl_context_create( dl_ctx_t* dl_ctx, dl_create_params_t* create_param
*dl_ctx = ctx;
+#if DL_NATVIS_ENABLED
+ g_DlActiveNatvisCtx = ctx;
+#endif
+
return DL_ERROR_OK;
}
diff --git a/src/dl_types.h b/src/dl_types.h
index cbc4e99..740cfd4 100755
--- a/src/dl_types.h
+++ b/src/dl_types.h
@@ -3,6 +3,10 @@
#ifndef DL_DL_TYPES_H_INCLUDED
#define DL_DL_TYPES_H_INCLUDED
+#ifndef DL_NATVIS_ENABLED
+#define DL_NATVIS_ENABLED 0 // Define this to 1 if you are using Visual Studio as debugger and want NATVIS information
+#endif
+
#ifdef __cplusplus
#define __STDC_LIMIT_MACROS
#endif
@@ -222,6 +226,11 @@ struct dl_member_desc
DL_ASSERT(count <= DL_INLINE_ARRAY_LENGTH_MAX);
type = (dl_type_t)( ( (unsigned int)type & ~DL_TYPE_INLINE_ARRAY_CNT_MASK ) | (count << DL_TYPE_INLINE_ARRAY_CNT_MIN_BIT) );
}
+
+#if DL_NATVIS_ENABLED
+ // This is just for natvis, not to be used elsewhere
+ static const dl_ctx_t* ctx;
+#endif
};
/**
@@ -248,6 +257,11 @@ struct dl_type_desc
uint32_t comment;
uint32_t metadata_count;
uint32_t metadata_start;
+
+#if DL_NATVIS_ENABLED
+ // This is just for natvis, not to be used elsewhere
+ static const dl_ctx_t* ctx;
+#endif
};
struct dl_enum_value_desc
@@ -257,6 +271,11 @@ struct dl_enum_value_desc
uint64_t value;
uint32_t metadata_count;
uint32_t metadata_start;
+
+#if DL_NATVIS_ENABLED
+ // This is just for natvis, not to be used elsewhere
+ static const dl_ctx_t* ctx;
+#endif
};
struct dl_enum_desc
@@ -271,12 +290,22 @@ struct dl_enum_desc
uint32_t comment;
uint32_t metadata_count;
uint32_t metadata_start;
+
+#if DL_NATVIS_ENABLED
+ // This is just for natvis, not to be used elsewhere
+ static const dl_ctx_t* ctx;
+#endif
};
struct dl_enum_alias_desc
{
uint32_t name;
uint32_t value_index; ///< index of the value this alias belong to.
+
+#if DL_NATVIS_ENABLED
+ // This is just for natvis, not to be used elsewhere
+ static const dl_ctx_t* ctx;
+#endif
};
struct dl_context