You are not logged in.

Dear visitor, welcome to krpano.com Forum. If this is your first visit here, please read the Help. It explains in detail how this page works. To use all features of this page, you should consider registering. Please use the registration form, to register here or read more information about the registration process. If you are already registered, please login here.

rdhoore108

Trainee

  • "rdhoore108" started this thread

Posts: 89

Location: Belgium

Occupation: Systems and Network Administrator

  • Send private message

1

Sunday, September 12th 2010, 9:49am

More on dereferencing: how to copy content into a new variable?

In short, my question is: how to make a new variable a and give it the same content as an existing object?

Let's say I have the following:

Source code

1
2
3
4
5
    <enum name="floors">
	<item name="floor_1" data="mydata" />
	<item name="floor_2" data="mydata" />
	<item name="floor_3" data="mydata" />
    </enum>
So I can do:

Source code

1
 trace(enum[floors].item[0].name, " has as data: ", enum[floors].item[0].data);


Now I wish to make a new variable a which should get the same contents as my first item node above, so that "a" is the equivalent of "enum[floors].item[0]", and I could do things like:

Source code

1
trace(a.name, " has as data: ", a.data);

Is there any way to accomplish this? I tried:

Source code

1
copy(a, enum[floors].item[0]);

This will make a.name available, but not a.data.

Then I tried adding:

Source code

1
copy(a.content, enum[floors].item[0].content);

but it doesn't help, still no a.data... And if I only do this copy by itself, without the copy above, then even a.name is null...

Can anyone shed some light on this? Thanks!

The reason I'm asking this, is to make it part of a foreach action where one can straight away give the commands one wants to execute on the object's nodes, instead of having to refer to yet another action. But then of course one needs to pass a name for the temporary object one wants to use in the command that needs to be iterated. And that's where the trouble above started...
- Ronny D'Hoore

michel

Professional

Posts: 1,153

Location: ANDORRA

Occupation: TV

  • Send private message

2

Sunday, September 12th 2010, 12:52pm

Hi Ronny,

Quoted

Is there any way to accomplish this? I tried:

Source code

1
copy(a, enum[floors].item[0]);
This will make a.name available, but not a.data.
I have tried this:

Source code

1
2
3
trace(enum[floors].item[0].name, " has as data: ", enum[floors].item[0].data);
copy(a, enum[floors].item[0]);
trace(a.name, " has as data: ", a.data );

and for me it works...

SAlut.

rdhoore108

Trainee

  • "rdhoore108" started this thread

Posts: 89

Location: Belgium

Occupation: Systems and Network Administrator

  • Send private message

3

Sunday, September 12th 2010, 2:08pm

Hmmm.... You are right! *confused*

After some more investigation, I figured that in my attempts to simplify my problem so that I could post it here without scaring everyone away, I also eliminated the bug that I obviously made in my real application.

Anyway, now that my problem is solved, I proudly present here a sibling of Steve's foreach() function. In this version, it is not required to pass the name of an action, but one can write the actual command string instead. Note that Steve's version will execute faster, as it does not need to copy around data internally. But mine also has a right to exist. ;-)

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!-- 
  foreach ( <object>, <loop variable>, <object variable> <command(s)> );

  "foreach" loop function executes a command string for each child of the given object.

  Example: foreach(enum[floors].item, i, a, trace("#", i, ': ', a.name, " has as data: ", a.data);";);
  This will execute the given trace command as many times as there are "item" nodes in the 
  <enum name="floors"> object. As we passed "a" as object variable, we can use the same "a"
  in our command string to represents the child object itself, instead of having to use
  enum[floors].item[get(i)].

  Sample data format for the above example:
    <enum name="floors">
	<item name="floor_1" data="mydata" />
	<item name="floor_2" data="mydata" />
	<item name="floor_3" data="mydata" />
    </enum>

-->

	<action name="foreach">
		_foreach_for(
		set(%2,0), 
		%2 LT %1.count, 
		inc(%2), 
		%4,
                copy(%3, %1[get(i)]);
		);
	</action>
	<action name="_foreach_for">
		push(action[_foreach_action].content);
		set(action[_foreach_action].content, "%1;");
		_foreach_action();
		set(action[_foreach_action].content, "%5; if(%2, %4; %3; _foreach_action(););");
		_foreach_action();
		pop(action[_foreach_action].content);
	</action>
	<action name="_foreach_action">
		trace("Error in foreach loop: push/pop stack corrupted"); <!-- this line should never execute -->
	</action>


Now, having the same data as above, one can loop through them as follows:

Source code

1
2
3
<action name="test">
	foreach(enum[floors].item, i, a, trace("#", i, " is ", a.name, " and has as data: ", a.data ); );
</action>


The output is:
INFO: #0 is floor_1 and has as data: mydata
INFO: #1 is floor_2 and has as data: mydata
INFO: #2 is floor_3 and has as data: mydata


PS. Of course one can specify more than one command, as usual, by separating them with semicolons ";".
- Ronny D'Hoore

This post has been edited 1 times, last edit by "rdhoore108" (Sep 12th 2010, 2:30pm)


rdhoore108

Trainee

  • "rdhoore108" started this thread

Posts: 89

Location: Belgium

Occupation: Systems and Network Administrator

  • Send private message

4

Sunday, September 12th 2010, 10:42pm

There are two issues with this actually:

  1. if you change the value of any items that are part of the temporary object (a in this example), then of course these changes will not reflect back to the original object. It would come handy if one could assign variables by reference instead of by value, so that a and enum[floors].item[get(i)] would both refer to the same structure in memory.

  2. get(i) should have been get(%2).


Below is the corrected code that fixes these issues, and was also optimized in a few ways.

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<!-- 
  foreach ( <object>, <loop variable>, <object variable> <command(s)> );

  "foreach" loop function executes a command string for each child of the given object.

  Example: foreach(enum[floors].item, i, a, trace("#", i, ': ', a.name, " has as data: ", a.data);";);
  This will execute the given trace command as many times as there are "item" nodes in the 
  <enum name="floors"> object. As we passed "a" as object variable, we can use the same "a"
  in our command string to represents the child object itself, instead of having to use
  enum[floors].item[get(i)].

  Sample data format for the above example:
    <enum name="floors">
	<item name="floor_1" data="mydata" />
	<item name="floor_2" data="mydata" />
	<item name="floor_3" data="mydata" />
    </enum>

-->
	<action name="foreach">
		set(%2,0);
		push(action[_foreach_action].content);
		set(action[_foreach_action].content, "
			copy(%3, %1[get(%2)]); 
			if(%2 LT %1.count, 
				%4; 
				copy(%1[get(%2)], %3); 
				inc(%2); 
				_foreach_action();
			);
		");
		_foreach_action();
		pop(action[_foreach_action].content);
	</action>
	<action name="_foreach_action">
		trace("Error in for loop: push/pop stack corrupted"); <!-- this line should never execute -->
	</action>
- Ronny D'Hoore

This post has been edited 3 times, last edit by "rdhoore108" (Sep 18th 2010, 10:07am)