Ruby-Enumeration und RETURN_ENUMERATOR - Fragen über Rubys C Internals
-
02-10-2019 - |
Frage
Ich bin ein wenig verwirrt darüber, wie Rubin übernimmt die Erstellung von Enumeratoren. Block-basierte Iteration macht Sinn und arbeitet für mich; Ich bin immer noch verwirrt, wie die Rückkehr eines Enumerator zu Funktionscode weisen soll.
Hier ist der Code, mit denen ich arbeite:
VALUE rb_RPRuby_Sender_Kernel_each_backtrace_frame( int argc,
VALUE* args,
VALUE rb_self ) {
rb_thread_t* c_thread = GET_THREAD();
// Get the current frame - we're doing a backtrace, so our current working frame to start is the first previous thread
rb_control_frame_t* c_current_context_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( RUBY_VM_PREVIOUS_CONTROL_FRAME( c_thread->cfp ) );
// c_top_of_control_frame describes the top edge of the stack trace
// set c_top_of_control_frame to the first frame in <main>
rb_control_frame_t* c_top_of_control_frame = RUBY_VM_NEXT_CONTROL_FRAME( RUBY_VM_NEXT_CONTROL_FRAME( (void *)( c_thread->stack + c_thread->stack_size ) ) );
// for each control frame:
while ( c_current_context_frame < c_top_of_control_frame ) {
VALUE rb_frame_hash = rb_RPRuby_Sender_Kernel_internal_backtraceHashForControlFrame( & c_current_context_frame );
// if we don't have a block, return enumerator
RETURN_ENUMERATOR( rb_self, 0, NULL );
// otherwise, yield the block
rb_yield( rb_frame_hash );
c_current_context_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( c_current_context_frame );
}
return Qnil;
}
Wie würde die letzte Zeile in der while-Schleife im Fall eines Enumerator genannt werden?
Hat alle meine Schleife Aktivität stattfinden müssen, bevor Anrufe RETURN_ENUMERATOR (seit RETURN_ENUMERATOR vermutlich vor rb_yield kommen muss ())?
Was passiert, wenn ich will etwas einmal die interne Iteration beendet passieren? Mit dem Block kann ich sie einfach nach der while-Schleife setzen; vermutlich die gleichen Arbeiten im Falle eines Enumerator- aber wie? Es scheint, wie jedes Mal durch die Schleife es einen Enumerator zurück, so wie funktioniert das Enumerator kennt das entsprechende entsprechende Objekt zurückgeben? rb_yield bekommt rb_frame_hash als bestanden arg, aber RETURN_ENUMERATOR scheint die args zu nehmen, die an die Methode weitergegeben werden, wenn der Enumerator die Methode ruft intern. So klar die Enumerator ist der Aufruf der Methode itself- vielleicht mit einer Art inneren Block, der einfach die Instanz von rb_frame_hash zurückkehrt?
Jeder Einblick in die Interna geschätzt wird.
-Asher
Lösung
Um zu versuchen, meine eigene Frage zu beantworten:
Wenn RETURN_ENUMERATOR genannt wird, rb_enumeratorize genannt wird, die einen Enumerator erstellt. Der Enumerator zurückgegeben; wenn: als nächstes auf dem Enumerator genannt wird, ist eine Faser (falls erforderlich) oder wieder initialisiert. Jedes Mal: ??nächste genannt wird, durchläuft die Faser einen intern bereitgestellt Block einmal um den nächsten Iterator Artikel (Einstellung no_next in dem Enumerator des C-Struktur und rief rb_fiber_yield auf dem Enumerator Fiber) zu erhalten.
So scheint es, dass die Schleife Aktivität nicht vor RETURN_ENUMERATOR nehmen hat. Ich bin noch nicht klar, auf Aktionen nach Auszählung in der Funktion einen Enumerator im Fall der Rückkehr, dass ein Block nicht vorgesehen war.