mirror of
https://github.com/nasa/trick.git
synced 2024-12-20 05:37:55 +00:00
Moved tmm_alloc_args to it's own file. Updates to convert_swig to
generate alloc functions in the swig interface files for classes. These alloc functions wrap the tmm_alloc_args call so swig doesn't have to think about variadic templates.
This commit is contained in:
parent
1e5d1a8cc4
commit
59537e487c
40
include/trick/tmm_alloc_args.hh
Normal file
40
include/trick/tmm_alloc_args.hh
Normal file
@ -0,0 +1,40 @@
|
||||
/*************************************************************************
|
||||
PURPOSE: (Trick TMM Alloc W/ Args)
|
||||
ICG: (No)
|
||||
LIBRARY DEPENDENCY:
|
||||
(
|
||||
()
|
||||
)
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef __ALLOC_WITH_ARGS_HH__
|
||||
#define __ALLOC_WITH_ARGS_HH__
|
||||
|
||||
#include "trick/trick_type_traits.hh"
|
||||
|
||||
/*
|
||||
In the case that a TrickTypeToString<T> for some type T exist, then this function is valid and will be compiled.
|
||||
*/
|
||||
template<typename T, typename ...Args>
|
||||
typename std::enable_if<Trick::has_getname<T>::value, T*>::type
|
||||
tmm_alloc_args(Args&&... args)
|
||||
{
|
||||
void* new_alloc = trick_MM->declare_var(TrickTypeToString<T>::getName().c_str());
|
||||
std::cout << "Allocating: " << TrickTypeToString<T>::getName() << std::endl;
|
||||
return new (new_alloc) T(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/*
|
||||
In the case that a TrickTypeToString<T> for some type T does NOT exist, then this function is valid and will be compiled.
|
||||
*/
|
||||
template<typename T, typename ...Args>
|
||||
typename std::enable_if<!Trick::has_getname<T>::value, T*>::type
|
||||
tmm_alloc_args(Args&&... args)
|
||||
{
|
||||
static_assert(Trick::always_false<T>::value,
|
||||
"You've attempted to call tmm_alloc_args using a type(T) that does not have an implemented specialization for TrickTypeToString.");
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#endif
|
@ -39,32 +39,9 @@ struct has_getname : std::false_type {};
|
||||
template<typename T>
|
||||
struct has_getname<T, void_t<decltype(std::declval<TrickTypeToString<T>>().getName())>> : std::true_type {};
|
||||
|
||||
/*
|
||||
In the case that a TrickTypeToString<T> for some type T exist, then this function is valid and will be compiled.
|
||||
*/
|
||||
template<typename T, typename ...Args>
|
||||
typename std::enable_if<has_getname<T>::value, T*>::type
|
||||
tmm_alloc_args(Args&&... args)
|
||||
{
|
||||
void* new_alloc = trick_MM->declare_var(TrickTypeToString<T>::getName().c_str());
|
||||
return new (new_alloc) T(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/*
|
||||
In the case that a TrickTypeToString<T> for some type T does NOT exist, then this function is valid and will be compiled.
|
||||
*/
|
||||
template<typename T, typename ...Args>
|
||||
typename std::enable_if<!has_getname<T>::value, T*>::type
|
||||
tmm_alloc_args(Args&&... args)
|
||||
{
|
||||
static_assert(always_false<T>::value,
|
||||
"You've attempted to call tmm_alloc_args using a type(T) that does not have an implemented specialization for TrickTypeToString.");
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif //__TMM_ALLOC_ARGS_HH__
|
||||
|
||||
|
@ -318,6 +318,7 @@ sub process_file() {
|
||||
\%insert(\"begin\") \%{
|
||||
#include <Python.h>
|
||||
#include <cstddef>
|
||||
#include \"trick/tmm_alloc_args.hh\"
|
||||
\%}
|
||||
|
||||
\%{
|
||||
@ -610,6 +611,8 @@ sub process_class($$$$$) {
|
||||
my $extracted ;
|
||||
my ($class_name) ;
|
||||
my $template_typedefs ;
|
||||
my $extend_block;
|
||||
my $ignore_constructors;
|
||||
|
||||
## Extract the class_name from the class_string
|
||||
$class_string =~ /^(?:class|struct)\s+ # keyword class or struct
|
||||
@ -628,16 +631,87 @@ sub process_class($$$$$) {
|
||||
$my_class_contents .= "\n#if SWIG_VERSION > 0x040000\n\%pythoncode \%{\n __setattr__ = _swig_setattr_nondynamic_instance_variable(object.__setattr__)\n\%}\n#endif\n" ;
|
||||
|
||||
($extracted, $$contents_ref) = extract_bracketed( "{" . $$contents_ref , "{}") ;
|
||||
|
||||
|
||||
# remove the trailing semicolon because we may append text to the class.
|
||||
$$contents_ref =~ s/^\s*;//s ;
|
||||
|
||||
#remove added extra opening "brace"
|
||||
$extracted =~ s/^\{// ;
|
||||
|
||||
#print "*** extracted = $extracted ***\n" ;
|
||||
#print "*** contents = $$contents_ref ***\n" ;
|
||||
|
||||
#
|
||||
if(!is_abstract_class($extracted)) {
|
||||
my @constructors;
|
||||
|
||||
#Find constructors
|
||||
while($extracted =~ /\b$class_name\s*\(([^)]*)\)\s*(?:const)?\s*;?/gs) {
|
||||
my $params = $1;
|
||||
if($params !~ /^\s*$/) {
|
||||
push @constructors, $params;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# Only proceed if there are non-default constructors
|
||||
if (@constructors) {
|
||||
my $qualified_class = $curr_namespace ? "$curr_namespace::$class_name" : $class_name;
|
||||
$extend_block = "\%extend $qualified_class {\n";
|
||||
|
||||
foreach my $constructor (@constructors) {
|
||||
#my $wrapper_name .= $class_name;
|
||||
|
||||
# Parse parameters into types and names
|
||||
my $params_ref = parse_parameters($constructor);
|
||||
my @param_types = @{ $params_ref->{types} };
|
||||
my @param_names = @{ $params_ref->{names} };
|
||||
|
||||
|
||||
|
||||
if(is_copy_constructor($class_name, \@param_types)) {
|
||||
print "COPY CONSTRUCTOR in $class_name\n";
|
||||
next;
|
||||
}
|
||||
|
||||
# Validate parameter counts
|
||||
die "Mismatch between parameter types and names for class $class_name"
|
||||
unless scalar(@param_types) == scalar(@param_names);
|
||||
|
||||
# Combine types and names
|
||||
#$wrapper_name .= join('_', $param_types[$_]);
|
||||
|
||||
my @type_name_pairs = map { "$param_types[$_] $param_names[$_]" } (0 .. $#param_types);
|
||||
my $param_list = join(', ', @type_name_pairs);
|
||||
|
||||
my @clean_param_names = map {
|
||||
my $type = $_;
|
||||
$type =~ s/\s*&\s*//g;
|
||||
$type
|
||||
} @param_names;
|
||||
|
||||
# Debugging
|
||||
#print STDERR "Debug: Generating constructor for '$class_name' with parameters: $param_list\n";
|
||||
|
||||
# Construct constructor signature
|
||||
my $signature = "static $class_name* alloc($param_list)";
|
||||
|
||||
#Construct tmm_alloc_args call with parameter names
|
||||
my $tmm_call = " return tmm_alloc_args<$qualified_class>(";
|
||||
$tmm_call .= join(', ', @clean_param_names);
|
||||
$tmm_call .= ");\n";
|
||||
|
||||
# Append constructor to %extend block
|
||||
$extend_block .= " $signature {\n$tmm_call";
|
||||
$extend_block .= " }\n";
|
||||
|
||||
#print STDERR "Wrapper name: $wrapper_name\n";
|
||||
}
|
||||
|
||||
$extend_block .= "};\n";
|
||||
|
||||
# Debugging: Print the generated %extend block
|
||||
#print STDERR "Debug: Generated %extend block for '$class_name':\n$extend_block\n\n";
|
||||
}
|
||||
}
|
||||
# SWIG doesn't like "const static". Change it to "static const"
|
||||
$extracted =~ s/const\s+static/static const/g ;
|
||||
|
||||
@ -744,6 +818,9 @@ sub process_class($$$$$) {
|
||||
$$new_contents_ref .= $my_class_contents ;
|
||||
# write the class contents and semicolon to ensure any template declarations below are after the semicolon.
|
||||
$$new_contents_ref .= $extracted . ";\n" ;
|
||||
|
||||
#$$new_contents_ref .= $ignore_constructors;
|
||||
$$new_contents_ref .= $extend_block . "\n\n";
|
||||
|
||||
my $c_ = "$curr_namespace$class_name" ;
|
||||
$c_ =~ s/\:/_/g ;
|
||||
@ -752,6 +829,7 @@ sub process_class($$$$$) {
|
||||
$$new_contents_ref .= "#define TRICK_SWIG_DEFINED_$c_" ;
|
||||
}
|
||||
|
||||
|
||||
## ================================================================================
|
||||
## process_typedef_struct
|
||||
##
|
||||
@ -839,4 +917,91 @@ sub process_typedef_const_struct($$$$) {
|
||||
|
||||
}
|
||||
|
||||
# Helper function to parse parameters
|
||||
sub parse_parameters {
|
||||
my ($param_string) = @_;
|
||||
my @types = ();
|
||||
my @names = ();
|
||||
my $arg_counter = 1;
|
||||
|
||||
# Return empty arrays if no parameters
|
||||
return { types => \@types, names => \@names } if $param_string =~ /^\s*$/;
|
||||
|
||||
my @params = split /,/, $param_string;
|
||||
|
||||
foreach my $param (@params) {
|
||||
# Trim leading and trailing whitespace
|
||||
$param =~ s/\s*=\s*[^,]+//;
|
||||
|
||||
# Remove default values (e.g., '= 0')
|
||||
$param =~ s/^\s+|\s+$//g;
|
||||
|
||||
if ($param =~ /^(.*\S)\s+(\S+)\s*$/) {
|
||||
my $type = $1 || '';
|
||||
my $name = $2;
|
||||
|
||||
if($name =~ s/\*//g) {
|
||||
#This variable is a pointer, move the pointer to the type
|
||||
$type .= "*";
|
||||
} elsif ($name =~ s/\&//g) {
|
||||
#This variable is a reference, move the pointer to the type
|
||||
$type .= "&";
|
||||
}
|
||||
|
||||
# Clean up the type
|
||||
$type =~ s/\s*&\s*/&/g; # Remove spaces around '&'
|
||||
$type =~ s/\s*\*\s*/\*/g; # Remove spaces around '*'
|
||||
$type =~ s/\s+/ /g; # Replace multiple spaces with a single space
|
||||
$type =~ s/^\s+|\s+$//g; # Trim leading/trailing whitespace
|
||||
|
||||
# Clean up the name
|
||||
$name =~ s/^\s+|\s+$//g;
|
||||
|
||||
push @types, $type;
|
||||
push @names, $name;
|
||||
|
||||
} else {
|
||||
# Handle cases where the name might be missing
|
||||
my $type = $param;
|
||||
$type =~ s/^\s+|\s+$//g;
|
||||
|
||||
push @types, $type;
|
||||
push @names, "arg" . scalar(@names);
|
||||
}
|
||||
}
|
||||
return { types => \@types, names => \@names };
|
||||
}
|
||||
|
||||
sub is_copy_constructor {
|
||||
my ($class_name, $param_types_ref) = @_;
|
||||
my @param_types = @$param_types_ref;
|
||||
|
||||
#Anything that has more than 1 argument is definitely
|
||||
#not a copy constructor
|
||||
return 0 unless scalar(@param_types) == 1;
|
||||
|
||||
my $param_type = $param_types[0];
|
||||
|
||||
#Remove attributes
|
||||
my $clean_param_type = $param_type;
|
||||
$clean_param_type =~ s/\bconst\b\s*//g; # Remove 'const'
|
||||
$clean_param_type =~ s/\s*&\s*//g; # Remove '&'
|
||||
$clean_param_type =~ s/\s*&&\s*//g; # Remove '&&' (for move constructors)
|
||||
$clean_param_type =~ s/^\s+|\s+$//g; # Trim leading/trailing whitespace
|
||||
|
||||
# Compare the cleaned parameter type with the class name
|
||||
return $clean_param_type eq $class_name;
|
||||
}
|
||||
|
||||
sub is_abstract_class {
|
||||
my ($class_body) = @_;
|
||||
|
||||
#Regex to check for virtual <function> = 0;
|
||||
if($class_body =~ /virtual\s+.*?=\s*0\s*;/s) {
|
||||
return 1; #Abstract
|
||||
} else {
|
||||
return 0; #Not abstract
|
||||
}
|
||||
}
|
||||
__END__
|
||||
is_copy_constructor
|
@ -94,7 +94,7 @@ else
|
||||
LIBEXEC = lib
|
||||
endif
|
||||
|
||||
TRICK_INCLUDES := -isystem${TRICK_HOME}/trick_source -isystem${TRICK_HOME}/include -isystem${TRICK_HOME}/include/trick/compat
|
||||
TRICK_INCLUDES := -isystem${TRICK_HOME}/trick_source -isystem${TRICK_HOME}/include -isystem${TRICK_HOME}/include/trick/compat -I./build
|
||||
TRICK_VERSIONS := -DTRICK_VER=$(TRICK_MAJOR) -DTRICK_MINOR=$(TRICK_MINOR)
|
||||
|
||||
export TRICK_SYSTEM_CXXFLAGS := $(TRICK_INCLUDES) $(TRICK_VERSIONS) -fpic $(UDUNITS_INCLUDES) -I${TRICK_HOME}/build
|
||||
|
@ -1,21 +1,14 @@
|
||||
import math
|
||||
from trick.unit_test import *
|
||||
|
||||
print(f"alloc_test.atwargs = {alloc_test}")
|
||||
trick.sim_control_panel_set_enabled(True)
|
||||
trick.exec_set_enable_freeze(True)
|
||||
trick.exec_set_freeze_command(True)
|
||||
|
||||
def main():
|
||||
trick_utest.unit_tests.enable()
|
||||
trick_utest.unit_tests.set_file_name( os.getenv("TRICK_HOME") + "/trick_test/SIM_tmm_alloc_args.xml" )
|
||||
trick_utest.unit_tests.set_test_name( "TMMAllocWithArgsTest" )
|
||||
|
||||
|
||||
trick.add_read(4.0, """TRICK_EXPECT_EQ(alloc_test.atwargs.some_int, 0)""")
|
||||
trick.add_read(4.0, """TRICK_EXPECT_NEAR(alloc_test.atwargs.some_double, 0, 1e-6)""")
|
||||
#Use tmm_alloc_args from input file - thanks convert_swig!
|
||||
alloc_test.atwargs_input_file = trick.AllocTestWithArguments.alloc(5, 7.0)
|
||||
|
||||
|
||||
|
||||
trick.stop(5.0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -9,6 +9,14 @@ def test():
|
||||
|
||||
test_case = "type_AllocTestWithArguments"
|
||||
|
||||
alloc_test.atwargs_input_file = trick.AllocTestWithArguments.alloc(5, 7.0)
|
||||
|
||||
|
||||
trick.add_read(4.0, """TRICK_EXPECT_EQ(alloc_test.atwargs.some_int, 0, test_case, test_suite)""")
|
||||
trick.add_read(4.0, """TRICK_EXPECT_NEAR(alloc_test.atwargs.some_double, 0, 1e-6, test_case, test_suite)""")
|
||||
|
||||
|
||||
|
||||
trick.add_read(4.0, """TRICK_EXPECT_EQ(alloc_test.atwargs.some_int, 0, test_case, test_suite)""")
|
||||
trick.add_read(4.0, """TRICK_EXPECT_NEAR(alloc_test.atwargs.some_double, 0, 1e-6, test_case, test_suite)""")
|
||||
|
||||
|
@ -13,6 +13,7 @@ class AllocTestSimObject : public Trick::SimObject {
|
||||
|
||||
public:
|
||||
AllocTestWithArguments* atwargs;
|
||||
AllocTestWithArguments* atwargs_input_file;
|
||||
|
||||
AllocTestSimObject() {
|
||||
|
||||
@ -24,7 +25,7 @@ class AllocTestSimObject : public Trick::SimObject {
|
||||
{
|
||||
std::cout << "Entered init_alloc()\n";
|
||||
//std::cout << TrickTypeToString<AllocTestWithArguments>::getName() << "\n";
|
||||
atwargs = Trick::tmm_alloc_args<AllocTestWithArguments>(0, 1.0);
|
||||
atwargs = tmm_alloc_args<AllocTestWithArguments>(0, 1.0);
|
||||
std::cout << "Called tmm_alloc_args: " << atwargs << "\n";
|
||||
}
|
||||
};
|
||||
|
10
test/SIM_tmm_with_args/models/alloc_with_args.cc
Normal file
10
test/SIM_tmm_with_args/models/alloc_with_args.cc
Normal file
@ -0,0 +1,10 @@
|
||||
#include "alloc_with_args.hh"
|
||||
|
||||
AllocTestWithArguments::AllocTestWithArguments(int* in_int, double& in_double, std::string in_string)
|
||||
:
|
||||
some_int(*in_int),
|
||||
some_double(in_double)
|
||||
{
|
||||
std::cout << in_string << "\nn";
|
||||
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/********************************* TRICK HEADER *******************************
|
||||
PURPOSE: ( Test tmm_alloc_args in a sim environment )
|
||||
LIBRARY DEPENDENCY:
|
||||
(())
|
||||
((alloc_with_args.o))
|
||||
*******************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
@ -30,6 +30,20 @@ class AllocTestWithArguments {
|
||||
std::cout << "in_double: " << in_double << "\n";
|
||||
}
|
||||
|
||||
|
||||
AllocTestWithArguments(int* in_int, double *in_double, std::string &a_name)
|
||||
:
|
||||
some_int(*in_int),
|
||||
some_double(*in_double)
|
||||
{
|
||||
std::cout << "AllocTestWithArguments constructor with: \n";
|
||||
std::cout << a_name << std::endl;
|
||||
std::cout << "in_int: " << in_int << "\n";
|
||||
std::cout << "in_double: " << in_double << "\n";
|
||||
}
|
||||
|
||||
AllocTestWithArguments(int*, double&, std::string);
|
||||
|
||||
~AllocTestWithArguments() {
|
||||
std::cout << "AllocTestWithArguments desctruct.\n";
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user