Skip to content

Commit

Permalink
Merge pull request #404 from nshaheed/shred-parent
Browse files Browse the repository at this point in the history
Add Shred.parent() & Shred.ancestor()
  • Loading branch information
gewang authored Nov 6, 2023
2 parents b8016e2 + 5e5abc4 commit b2143eb
Show file tree
Hide file tree
Showing 7 changed files with 219 additions and 1 deletion.
33 changes: 33 additions & 0 deletions examples/shred/ancestor.ck
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Shred.ancestor() returns the top-level shred that is directly or
// indirectly a parent shred of the calling shred; useful for getting
// information relevant to top-level shreds; related: parent.ck

// test me
<<< "the top-level shred's ID is:", me.id() >>>;
// my ancestor
<<< "the top-level shred's ancestor ID is:", me.ancestor().id(), "\n" >>>;

// recursive function to test finding ancestor from different
// "generations" of shreds
fun void findTheAncestor( int generation )
{
// stop recursing
if( generation <= 0 ) return;

// calling shred
<<< "the sporked shred's ID is:", me.id() >>>;
// this will always be the same as the top-level shred id
<<< "the sporked shred's ancestor ID is:", me.ancestor().id(), "\n" >>>;

// spork a child shred
spork ~ findTheAncestor( generation-1 );
// wait a bit to give child shred a chance to run
1::samp => now;
}

// recursively spork function this 10 times; me.ancestor() should always
// point to the top-level shred
spork ~ findTheAncestor(10);

// wait to give children shreds a chance to run
1::samp => now;
19 changes: 19 additions & 0 deletions examples/shred/parent.ck
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// return a shred's parent shred (i.e., the shred that sporked it)
// if the shred is a top-level shred, then me.parent() will return null
// related: ancestor.ck

<<< "the top-level shred's ID is:", me.id() >>>;
<<< "the top-level shred's parent is:", me.parent() >>>;

fun void findTheParent()
{
// this will be the same as the top-level shred id
<<< "the sporked shred's ID is:", me.id() >>>;
<<< "the sporked shred's parent ID is:", me.parent().id() >>>;
}

// spork a child shred
spork ~ findTheParent();

// yield to let validateParent(...) run
me.yield();
41 changes: 40 additions & 1 deletion src/core/chuck_lang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -600,15 +600,27 @@ t_CKBOOL init_class_shred( Chuck_Env * env, Chuck_Type * type )
func->doc = "get the operand stack size hint (in bytes) for shreds sporked from this one.";
if( !type_engine_import_mfun( env, func ) ) goto error;

// add parent() | 1.5.1.9 (nshaheed)
func = make_new_sfun( "Shred", "parent", shred_parent );
func->doc = "get the calling shred's parent shred (i.e., the shred that sporked the calling shred). Returns null if there is no parent Shred. (Related: see Shred.ancestor())";
if( !type_engine_import_sfun( env, func ) ) goto error;

// add ancestor() | 1.5.1.9 (nshaheed)
func = make_new_sfun( "Shred", "ancestor", shred_ancestor );
func->doc = "get the calling shred's \"ancestor\" shred (i.e., the top-level shred). Returns itself if the calling shred is the top-level shred. (Related: see Shred.parent())";
if( !type_engine_import_sfun( env, func ) ) goto error;

// add examples
if( !type_engine_import_add_ex( env, "shred/powerup.ck" ) ) goto error;
if( !type_engine_import_add_ex( env, "shred/spork.ck" ) ) goto error;
if( !type_engine_import_add_ex( env, "shred/spork2.ck" ) ) goto error;
if( !type_engine_import_add_ex( env, "shred/spork2-exit.ck" ) ) goto error;
if( !type_engine_import_add_ex( env, "shred/spork2-remove.ck" ) ) goto error;
if( !type_engine_import_add_ex( env, "shred/powerup.ck" ) ) goto error;
if( !type_engine_import_add_ex( env, "event/broadcast.ck" ) ) goto error;
if( !type_engine_import_add_ex( env, "event/signal.ck" ) ) goto error;
if( !type_engine_import_add_ex( env, "event/signal4.ck" ) ) goto error;
if( !type_engine_import_add_ex( env, "shred/parent.ck" ) ) goto error;
if( !type_engine_import_add_ex( env, "shred/ancestor.ck" ) ) goto error;

// end the class import
type_engine_import_class_end( env );
Expand Down Expand Up @@ -2528,6 +2540,33 @@ CK_DLL_MFUN( shred_cget_hintChildRegSize ) // 1.5.1.5
}


CK_DLL_SFUN( shred_parent ) // added 1.5.1.9 (nshaheed)
{
// get the parent
Chuck_VM_Shred * parent = SHRED->parent;
// set return value
RETURN->v_object = parent;
}


CK_DLL_SFUN( shred_ancestor ) // added 1.5.1.9 (nshaheed)
{
// current shred
Chuck_VM_Shred * curr = SHRED;

// iterate up until parent is null; it's possible that
// ancestor() returns the calling shred, if called on
// the top-level "ancestor" shred
while( curr->parent != NULL )
{
// set curr as parent
curr = curr->parent;
}

// set return value
RETURN->v_object = curr;
}

//-----------------------------------------------------------------------------
// string API
//-----------------------------------------------------------------------------
Expand Down
2 changes: 2 additions & 0 deletions src/core/chuck_lang.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ CK_DLL_MFUN( shred_sourcePath ); // added 1.3.0.0
CK_DLL_MFUN( shred_sourceDir ); // added 1.3.0.0
CK_DLL_MFUN( shred_sourceDir2 ); // added 1.3.2.0
CK_DLL_SFUN( shred_fromId ); // added 1.3.2.0
CK_DLL_SFUN( shred_parent ); // added 1.5.1.9 (nshaheed)
CK_DLL_SFUN( shred_ancestor ); // added 1.5.1.9 (nshaheed)
CK_DLL_MFUN( shred_ctrl_hintChildMemSize ); // added 1.5.1.5
CK_DLL_MFUN( shred_cget_hintChildMemSize ); // added 1.5.1.5
CK_DLL_MFUN( shred_ctrl_hintChildRegSize ); // added 1.5.1.5
Expand Down
29 changes: 29 additions & 0 deletions src/test/01-Basic/232-shred-parent.ck
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// test shred.parent()

// check shred parent
fun void validateParent(int main_shred_id)
{
// id of parent
me.parent().id() => int parent_id;

// make sure same id
if( parent_id != main_shred_id )
{
<<< "FAILURE: parent shred should be the top-level shred" >>>;
me.exit();
}
}

// this should be the top-level shred (and has no parent)
if( me.parent() != null )
{
<<< "FAILURE, the top-level shred should have no parent" >>>;
me.exit();
}

// spork
spork ~ validateParent( me.id() );
// yield to let validateParent(...) run
me.yield();
// print
<<< "success" >>>;
47 changes: 47 additions & 0 deletions src/test/01-Basic/233-shred-parent-recursive.ck
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// validate that Shred.parent() correctly gets the parent shred
// through multiple layers of recursion.

0 => int count; // count the number of recursive calls

fun void validateParent( int want_parent, int depth )
{
count++;
me.parent().id() => int got_parent;

if( want_parent != got_parent )
{
<<< "FAILURE, spork~ validateParent(...)'s parent shred is not matching" >>>;
me.exit();
}

if( depth > 1 )
{
spork~ validateParent( me.id(), depth-1 );
}
samp => now;
}

// this should be the top-level shred (and has no parent)
if( me.parent() != null )
{
<<< "FAILURE, the top-level shred should have no parent" >>>;
me.exit();
}

100 => int recursive_calls;
spork~ validateParent( me.id(), recursive_calls );

// pass time (or yield) to let children shreds run
samp => now;

// check count
if( count != recursive_calls )
{
<<< "FAILURE: incorrect number of recursive calls made. got:",
count, "want:", recursive_calls >>>;
me.exit();
}

// done
<<< "success" >>>;

49 changes: 49 additions & 0 deletions src/test/01-Basic/234-shred-ancestor.ck
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// validate that Shred.ancestor() correctly gets the top-level
// shred through multiple layers of recursion

// count the number of recursive calls
0 => int count;

fun void validateAncestor(int want_ancestor, int depth)
{
count++;
me.ancestor().id() => int got_ancestor;

if( want_ancestor != got_ancestor )
{
<<< "FAILURE, spork~ validateAncestor(...)'s ancestor shred should be the top-level shred" >>>;
me.exit();
}

if( depth > 1 )
{
spork ~ validateAncestor(want_ancestor, depth-1);
}
// let time pass to let children shreds run
samp => now;
}

// this should be the top-level shred (and has no ancestor)
if( me.ancestor() != me )
{
<<< "FAILURE, the top-level shred should have be me" >>>;
me.exit();
}

100 => int recursive_calls;
spork ~ validateAncestor( me.id(), recursive_calls );

// let time pass to let children shreds run
samp => now;

// check count
if( count != recursive_calls )
{
<<< "FAILURE: incorrect number of recursive calls made.",
"got:", count, "want:", recursive_calls >>>;
me.exit();
}

// done
<<< "success" >>>;

0 comments on commit b2143eb

Please sign in to comment.