NAME

Module::Generic::Iterator - An Array Iterator Object Class

SYNOPSIS

my $i = Module::Generic::Iterator->new( [qw( Joe John Mary )] );
# or also:
my $a = Module::Generic::Array->new( [qw( Joe John Mary )] );
my $i = $a->iterator;
while( $i->has_next )
{
    my $elem = $i->next;
    my $value = $elem->value;
    # Get the next element relative to our element
    printf( "Next value is: %s at offset %d\n", $elem->next, $elem->next->pos  );
}

# Navigate to a specific element
my $elem = $iter->find( "Jack" );
print( "Found Jack at position: ", $elem->pos, "\n" );

# Use element navigation
my $first = $iter->first;
my $next = $first->next; # Returns "Jack" as an element
print( "Next after John: ", $next->value, "\n" );

VERSION

v1.2.3

DESCRIPTION

Module::Generic::Iterator provides a generic iterator interface for traversing a list of elements. It supports navigation through the list with methods like "next", "prev", "first", and "last", and allows finding specific elements with "find". Each element in the iterator is wrapped in a Module::Generic::Iterator::Element object, which provides contextual navigation (e.g., "next", "prev") relative to the parent iterator.

This class is designed to be lightweight and flexible, working with any array of values, including scalars, references, or objects.

CONSTRUCTORS

new

Creates a new iterator object. It takes an optional array reference or an Module::Generic::Array object of elements to iterate over, and an optional hash or hash reference of parameters, and returns the newly instantiated object:

my $iter = Module::Generic::Iterator->new( [1, 2, 3], debug => 3 );

Supported parameters:

Returns a new Module::Generic::Iterator object.

METHODS

elements

Returns the underlying array of elements as a Module::Generic::Array object. Each element is a Module::Generic::Iterator::Element object:

my $elems = $iter->elements;
print( $elems->length, "\n" ); # Number of elements

eof

Returns true if the iterator is at the end of the list (i.e., the current position is the last element or beyond). Optionally takes an element to check its position:

if( $iter->eof )
{
    print( "End of iterator\n" );
}

find

Finds an element by value and returns its corresponding Module::Generic::Iterator::Element object. Returns undef in scalar context, or an empty list in list context if the element is not found:

my $elem = $iter->find( "Jack" );
print( $elem->value, "\n" ) if( $elem ); # "Jack"

For reference values, comparison is done using "refaddr" in Scalar::Util. For scalar values, comparison is done using string equality (eq).

first

Moves the iterator to the first element and returns it as a Module::Generic::Iterator::Element object:

my $first = $iter->first;
print( $first->value, "\n" ); # First element

has_next

Returns true if there is a next element in the iterator:

while( $iter->has_next )
{
    my $elem = $iter->next;
    print( $elem->value, "\n" );
}

has_prev

Returns true if there is a previous element in the iterator:

$iter->last;
if( $iter->has_prev )
{
    my $prev = $iter->prev;
    print( $prev->value, "\n" );
}

last

Moves the iterator to the last element and returns it as a Module::Generic::Iterator::Element object:

my $last = $iter->last;
print( $last->value, "\n" ); # Last element

length

Returns the number of elements, starting from 1, as a Module::Generic::Number object.

print( $iter->length, "\n" ); # e.g., 5

next

Moves the iterator to the next element and returns it as a Module::Generic::Iterator::Element object. Optionally takes an element to start from:

while( my $elem = $iter->next )
{
    print( $elem->value, "\n" );
}

Returns undef in scalar context, or an empty list in list context, if there are no more elements.

pos

An lvalue method to get or set the current position in the iterator. Returns the position as an integer:

$iter->pos = 2; # Move to the third element
my $pos = $iter->pos; # Returns the current position
print( $iter->pos, "\n" ); # 2

Warns if the position is not an integer.

prev

Moves the iterator to the previous element and returns it as a Module::Generic::Iterator::Element object. Optionally takes an element to start from:

$iter->last;
my $prev = $iter->prev;
print( $prev->value, "\n" );

Returns undef in scalar context, or an empty list in list context, if there are no previous elements.

reset

Resets the iterator position to the beginning (position 0):

$iter->last;
$iter->reset;
print( $iter->pos, "\n" ); # 0

Returns the iterator object.

_find_pos

Provided with an item, this returns its position in the array or undef if it is not in the array.

SERIALISATION

Serialisation by CBOR, Sereal and Storable::Improved (or the legacy Storable) is supported by this package. To that effect, the following subroutines are implemented: FREEZE, THAW, STORABLE_freeze and STORABLE_thaw

THREAD-SAFETY

Module::Generic::Iterator is thread-safe for all operations, as it operates on per-object state and does not modify shared resources at runtime.

Key considerations for thread-safety:

  • Shared Variables

    There are no shared variables that are modified at runtime. The global $DEBUG variable (inherited from Module::Generic) is typically set before threads are created, and it is the user's responsibility to ensure thread-safety if modified at runtime:

    use threads;
    local $Module::Generic::Iterator::DEBUG = 0; # Set before threads
    my @threads = map
    {
        threads->create(sub
        {
            my $iter = Module::Generic::Iterator->new( [1, 2, 3] );
            $iter->next; # Thread-safe
        });
    } 1..5;
    $_->join for( @threads );
  • Object State

    Iterator data (e.g., "elements", "pos", "value" in Module::Generic::Iterator::Element) is stored per-object, ensuring thread isolation:

    use threads;
    my @threads = map
    {
        threads->create(sub
        {
            my $iter = Module::Generic::Iterator->new( [1, 2, 3] );
            while( my $elem = $iter->next )
            {
                print( $elem->value, "\n" ); # Thread-safe
            }
        });
    } 1..5;
    $_->join for( @threads );
  • Serialisation

    Serialisation methods ("FREEZE", "THAW") operate on per-object state, making them thread-safe.

For debugging in threaded environments (depending on your Operating System):

ls -l /proc/$$/fd  # List open file descriptors

SEE ALSO

Module::Generic::Iterator::Element, Module::Generic::Array

AUTHOR

Jacques Deguest <jack@deguest.jp>

COPYRIGHT & LICENSE

Copyright (c) 2000-2024 DEGUEST Pte. Ltd.

You can use, copy, modify and redistribute this package and associated files under the same terms as Perl itself.