Skip to content

Commit

Permalink
Added Generation of Missing Headers
Browse files Browse the repository at this point in the history
  • Loading branch information
Advay17 committed Nov 21, 2024
1 parent 4c225ef commit 0feca0f
Show file tree
Hide file tree
Showing 5 changed files with 700 additions and 0 deletions.
250 changes: 250 additions & 0 deletions wpiutil/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -254,3 +254,253 @@ if(WITH_TESTS)
target_compile_options(wpiutil_test PRIVATE /utf-8)
endif()
endif()

# Copied from https://github.com/foonathan/memory/blob/016c9fbd61b57ed2058551dcf225c15a0e716cce/cmake/get_container_node_sizes.cmake#L7
# We need to capture this outside of a function as
# CMAKE_CURRENT_LIST_DIR reflects the current CMakeLists.txt file when
# a function is executed, but reflects this directory while this file
# is being processed.
set(_THIS_MODULE_DIR ${CMAKE_CURRENT_LIST_DIR})

if(NOT DEFINED _DEBUG_GET_CONTAINER_NODE_SIZES)
set(_DEBUG_GET_CONTAINER_NODE_SIZES OFF)
endif()

function(_gcns_debug_message)
if(_DEBUG_GET_CONTAINER_NODE_SIZES)
message("${ARGV}")
endif()
endfunction()

# This function will return the alignment of the C++ type specified in
# 'type', the result will be in 'result_var'.
function(get_alignof_type type result_var)
# We expect this compilation to fail - the purpose of this is to
# generate a compile error on a generated tyoe
# "align_of<type,value>" that is the alignment of the specified
# type.
#
# See the contents of get_align_of.cpp for more details.
try_compile(
align_result
${CMAKE_CURRENT_BINARY_DIR}
${_THIS_MODULE_DIR}/src/main/native/thirdparty/memory/src/get_align_of.cpp
COMPILE_DEFINITIONS "-DTEST_TYPE=${type}"
OUTPUT_VARIABLE align_output
CXX_STANDARD 11
CXX_STANDARD_REQUIRED TRUE
)

# Look for the align_of<..., ##> in the compiler error output
string(REGEX MATCH "align_of<.*,[ ]*([0-9]+)[ul ]*>" align_of_matched ${align_output})

if(align_of_matched)
set(${result_var} ${CMAKE_MATCH_1} PARENT_SCOPE)
else()
message(
FATAL_ERROR
"Unable to determine alignment of C++ type ${type} - no error text matching align_of<..., ##> in compiler output |${align_output}|"
)
endif()
endfunction()

# This function will return a list of C++ types with unique alignment
# values, covering all possible alignments supported by the currently
# configured C++ compiler.
#
# The variable named in 'result_types' will contain a list of types,
# and 'result_alignments' will contain a parallel list of the same
# size that is the aligment of each of the matching types.
function(unique_aligned_types result_types result_alignments)
# These two lists will contain a set of types with unique alignments.
set(alignments)
set(types)

set(all_types
char
bool
short
int
long
LONG_LONG
float
double
LONG_DOUBLE
)
foreach(type IN LISTS all_types)
get_alignof_type("${type}" alignment)
_gcns_debug_message("Alignment of '${type}' is '${alignment}'")

if(NOT ${alignment} IN_LIST alignments)
list(APPEND alignments ${alignment})
list(APPEND types ${type})
endif()
endforeach()

set(${result_types} ${types} PARENT_SCOPE)
set(${result_alignments} ${alignments} PARENT_SCOPE)
endfunction()

# This function will return node sizes for the requested container
# when created with the specified set of types.
#
# 'container' must be one of the container types supported by
# get_node_size.cpp (see that file for details)
#
# 'types' is a list of C++ types to hold in the container to measure
# the node size
#
# 'align_result_var' will contain the list of alignments of contained
# types used.
#
# 'nodesize_result_var' will contain the list of node sizes, one entry
# for each alignment/type
function(get_node_sizes_of container types align_result_var nodesize_result_var)
set(alignments)
set(node_sizes)

foreach(type IN LISTS types)
# We expect this to fail - the purpose of this is to generate
# a compile error on a generated type
# "node_size_of<type_size,node_size,is_node_size>" that is the
# alignment of the specified type.
try_compile(
nodesize_result
${CMAKE_CURRENT_BINARY_DIR}
${_THIS_MODULE_DIR}/src/main/native/thirdparty/memory/src/get_node_size.cpp
COMPILE_DEFINITIONS "-D${container}=1" "-DTEST_TYPE=${type}"
OUTPUT_VARIABLE nodesize_output
CXX_STANDARD 11
CXX_STANDARD_REQUIRED TRUE
)

if(NOT nodesize_output)
message(
FATAL_ERROR
"Unable to determine node size of C++ container ${container} holding type ${type} - no error text matching node_size_of<##, ##, true> in compiler output |${nodesize_output}|"
)
endif()

# Find the instance of node_size_of<##, ##, true> in the
# compiler error output - the first number is the alignment,
# and the second is the node size.
string(
REGEX MATCH
"node_size_of<[ ]*([0-9]+)[ul ]*,[ ]*([0-9]+)[ul ]*,[ ]*true[ ]*>"
node_size_of_match
${nodesize_output}
)

if(node_size_of_match)
# Extract the alignment and node size
if(NOT ${CMAKE_MATCH_1} IN_LIST alignments)
list(APPEND alignments ${CMAKE_MATCH_1})
list(APPEND node_sizes ${CMAKE_MATCH_2})
endif()
else()
message(
FATAL_ERROR
"Unable to determine node size of C++ container ${container} holding type ${type} - no error text matching node_size_of<##, ##, true> in compiler output |${nodesize_output}|"
)
endif()
endforeach()

# Return output to caller
set(${align_result_var} ${alignments} PARENT_SCOPE)
set(${nodesize_result_var} ${node_sizes} PARENT_SCOPE)
endfunction()

# This will write the container node sizes to an output header file
# that can be used to calculate the node size of a container holding
# the specified type.
function(get_container_node_sizes outfile)
message(STATUS "Getting container node sizes")

# Build up the file contents in the variable NODE_SIZE_CONTENTS,
# as requested in container_node_sizes_impl.hpp.in
set(NODE_SIZE_CONTENTS "")

# Get the set of uniquely aligned types to work with
unique_aligned_types(types alignments)
_gcns_debug_message("=> alignments |${alignments}| types |${types}|")

set(container_types
forward_list
list
set
multiset
unordered_set
unordered_multiset
map
multimap
unordered_map
unordered_multimap
shared_ptr_stateless
shared_ptr_stateful
)

foreach(container IN LISTS container_types)
string(TOUPPER "${container}_container" container_macro_name)
get_node_sizes_of("${container_macro_name}" "${types}" alignments node_sizes)
_gcns_debug_message("node size of |${container_macro_name}| holding types |${types}| : alignments |${alignments}| node sizes |${node_sizes}|")

# Generate the contents for this container type
string(
APPEND
NODE_SIZE_CONTENTS
"\
namespace detail
{
template <std::size_t Alignment>
struct ${container}_node_size;
"
)

list(LENGTH alignments n_alignments)
math(EXPR last_alignment "${n_alignments}-1")
foreach(index RANGE ${last_alignment})
list(GET alignments ${index} alignment)
list(GET node_sizes ${index} node_size)

# Generate content for this alignment/node size in this container
string(
APPEND
NODE_SIZE_CONTENTS
"\
template <>
struct ${container}_node_size<${alignment}>
: std::integral_constant<std::size_t, ${node_size}>
{};
"
)
endforeach()

# End contents for this container type
string(
APPEND
NODE_SIZE_CONTENTS
"\
} // namespace detail
template <typename T>
struct ${container}_node_size
: std::integral_constant<std::size_t,
detail::${container}_node_size<alignof(T)>::value + sizeof(T)>
{};
"
)
endforeach()

# Finally, write the file. As a reminder, configure_file() will
# substitute in any CMake variables wrapped in @VAR@ in the inpout
# file and write them to the output file; and will only rewrite
# the file and update its timestamp if the contents have changed.
# The only variable that will be substituted is NODE_SIZE_CONTENTS
configure_file("${_THIS_MODULE_DIR}/container_node_sizes_impl.hpp.in" ${outfile})
endfunction()

if(NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/container_node_sizes_impl.hpp)
get_container_node_sizes(${CMAKE_CURRENT_BINARY_DIR}/container_node_sizes_impl.hpp)
endif()
4 changes: 4 additions & 0 deletions wpiutil/container_node_sizes_impl.hpp.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// The following section was autogenerated by get_container_node_sizes.cmake
//=== BEGIN AUTOGENERATED SECTION ===//
@NODE_SIZE_CONTENTS@
//=== END AUTOGENERATED SECTION ===//
Loading

0 comments on commit 0feca0f

Please sign in to comment.