Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added passing arguments to constrcutors when allocating with Trick Memory Manager. #1790

Draft
wants to merge 23 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
64fabb2
Initial pass at adding support for a templated emplacement new functi…
M-Herr Sep 20, 2024
6aa4ef6
Merge remote-tracking branch 'origin/master'
M-Herr Sep 20, 2024
61c2fdb
Updated Makefile.common to include /build in include paths
M-Herr Sep 20, 2024
1e5d1a8
Moved tmm_alloc_args into inludde/trick. File never changes so it wa…
M-Herr Sep 21, 2024
59537e4
Moved tmm_alloc_args to it's own file. Updates to convert_swig to
M-Herr Sep 25, 2024
cc30885
Was leaning to heavily on perl for writing wrappers. ICG now writes …
M-Herr Sep 27, 2024
36b2640
Finishing touches on PrintConstructors class. Moved back to generatin…
M-Herr Sep 28, 2024
95230b0
Merge branch 'nasa:master' into master
M-Herr Sep 28, 2024
43253a2
Updated unit test sim
M-Herr Sep 29, 2024
91caad9
Extended unit test to include allocatin gin the input processor
M-Herr Sep 29, 2024
0542f0f
Wrapped JSON include in a flag used to enable/disable siwg interface …
M-Herr Sep 30, 2024
9ec72b9
Fixed typo in test_sims.yml
M-Herr Oct 1, 2024
48914fd
Changed getReturnType to getType since we're in a constructor
M-Herr Oct 1, 2024
daba529
Minor update to test
M-Herr Oct 1, 2024
a89a594
Merge remote-tracking branch 'upstream/master'
M-Herr Oct 1, 2024
19b06f1
Updated includes
M-Herr Oct 2, 2024
8f64831
Added alternative to generating TrickTypeToString structures.
M-Herr Oct 10, 2024
61f179e
Documentation updates
M-Herr Oct 10, 2024
bf25bbe
Update swig_class_typedef.i
M-Herr Oct 16, 2024
8679e8c
Fixed indentation in interface file
M-Herr Oct 16, 2024
80ff429
Changed convert swig to ignore private constructors.
M-Herr Oct 16, 2024
cb1491d
Merge remote-tracking branch 'upstream/master'
M-Herr Oct 17, 2024
f81d1c7
Merge remote-tracking branch 'upstream/master'
M-Herr Jan 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
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.
  • Loading branch information
M-Herr committed Sep 25, 2024
commit 59537e487cd19a57d2b1f9014bf5c474c754be67
40 changes: 40 additions & 0 deletions include/trick/tmm_alloc_args.hh
Original file line number Diff line number Diff line change
@@ -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
23 changes: 0 additions & 23 deletions include/trick/trick_type_traits.hh
Original file line number Diff line number Diff line change
Expand Up @@ -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__

Expand Down
171 changes: 168 additions & 3 deletions libexec/trick/convert_swig
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ sub process_file() {
\%insert(\"begin\") \%{
#include <Python.h>
#include <cstddef>
#include \"trick/tmm_alloc_args.hh\"
\%}

\%{
Expand Down Expand Up @@ -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
Expand All @@ -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 ;

Expand Down Expand Up @@ -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 ;
Expand All @@ -752,6 +829,7 @@ sub process_class($$$$$) {
$$new_contents_ref .= "#define TRICK_SWIG_DEFINED_$c_" ;
}


## ================================================================================
## process_typedef_struct
##
Expand Down Expand Up @@ -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
2 changes: 1 addition & 1 deletion share/trick/makefiles/Makefile.common
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
17 changes: 5 additions & 12 deletions test/SIM_tmm_with_args/RUN_test/input.py
Original file line number Diff line number Diff line change
@@ -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" )
#Use tmm_alloc_args from input file - thanks convert_swig!
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)""")
trick.add_read(4.0, """TRICK_EXPECT_NEAR(alloc_test.atwargs.some_double, 0, 1e-6)""")



trick.stop(5.0)


if __name__ == "__main__":
main()
8 changes: 8 additions & 0 deletions test/SIM_tmm_with_args/RUN_test/unit_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)""")

Expand Down
3 changes: 2 additions & 1 deletion test/SIM_tmm_with_args/S_define
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class AllocTestSimObject : public Trick::SimObject {

public:
AllocTestWithArguments* atwargs;
AllocTestWithArguments* atwargs_input_file;

AllocTestSimObject() {

Expand All @@ -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";
}
};
Expand Down
10 changes: 10 additions & 0 deletions test/SIM_tmm_with_args/models/alloc_with_args.cc
Original file line number Diff line number Diff line change
@@ -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";

}
Loading