MCE::Sh...Ordhash(3)

πŸ“¦
version 1.893 Β· 4 versions
, in epel 10

πŸ’– NAME πŸ’–

MCE::Shared::Ordhash(3) β€” okay bestie, this is the manual page for MCE::Shared::Ordhash: an ordered hash class featuring tombstone deletion. 🫢

✨ VERSION ✨

This document describes MCE::Shared::Ordhash version 1.893. πŸ’…

🌸 DESCRIPTION 🌸

So MCE::Shared::Ordhash is an ordered-hash helper class. You can use it as a standalone thing, or let MCE::Shared manage it. It implements an ordered hash featuring tombstone deletion, inspired by Hash::Ordered. An ordered hash is very much like a normal hash, except it preserves key insertion order. Iconic behavior, honestly. ✨

It provides splice, sorting, plus extra capabilities for use with MCE::Shared::Minidb. Tombstone deletion is further optimized to not impact store, push, unshift, and merge. Tombstones are purged in-place for lesser memory consumption. In addition, pop and shift run optimally when an index is present. The optimization also applies to forward and reverse deletes. End result? A new level of performance for a pure-Perl ordered hash implementation. πŸ”₯

πŸŽ€ SYNOPSIS πŸŽ€

# non-shared or local construction for use by a single process

use MCE::Shared::Ordhash;

my $oh = MCE::Shared::Ordhash->new( @pairs );

# construction for sharing with other threads and processes

use MCE::Shared;

my $oh = MCE::Shared->ordhash( @pairs );

# hash-like dereferencing

my $val = $oh->{$key};
$oh->{$key} = $val;

%{$oh} = ();

# OO interface

if ( !defined ( $val = $oh->get("some_key") ) ) {
   $val = $oh->set( some_key => "some_value" );
}

$val   = $oh->set( $key, $val );
$ret   = $oh->setnx( $key, $val );         # set only if the key exists
$val   = $oh->get( $key );
$val   = $oh->delete( $key );              # del is an alias for delete
$bool  = $oh->exists( $key );
void   = $oh->clear();
$len   = $oh->len();                       # scalar keys %{ $oh }
$len   = $oh->len( $key );                 # length $oh->{ $key }
@pair  = $oh->pop();
$len   = $oh->push( @pairs );
@pair  = $oh->shift();
$len   = $oh->unshift( @pairs );
%pairs = $oh->splice( $offset, $length, @pairs );

$oh2   = $oh->clone( @keys );              # @keys is optional
$oh3   = $oh->flush( @keys );
$iter  = $oh->iterator( @keys );           # ($key, $val) = $iter->()
@keys  = $oh->keys( @keys );
%pairs = $oh->pairs( @keys );
@vals  = $oh->values( @keys );             # vals is an alias for values

$len   = $oh->assign( $key/$val pairs );   # equivalent to ->clear, ->mset
$cnt   = $oh->mdel( @keys );
@vals  = $oh->mget( @keys );
$bool  = $oh->mexists( @keys );            # true if all keys exists
$len   = $oh->mset( $key/$val pairs );     # merge is an alias for mset

@vals  = $oh->sort();                      # by val $a <=> $b default
@vals  = $oh->sort( "desc" );              # by val $b <=> $a
@vals  = $oh->sort( "alpha" );             # by val $a cmp $b
@vals  = $oh->sort( "alpha desc" );        # by val $b cmp $a

@vals  = $oh->sort( "key" );               # by key $a <=> $b
@vals  = $oh->sort( "key desc" );          # by key $b <=> $a
@vals  = $oh->sort( "key alpha" );         # by key $a cmp $b
@vals  = $oh->sort( "key alpha desc" );    # by key $b cmp $a

# included, sugar methods without having to call set/get explicitly

$len   = $oh->append( $key, $string );     #   $val .= $string
$val   = $oh->decr( $key );                # --$val
$val   = $oh->decrby( $key, $number );     #   $val -= $number
$val   = $oh->getdecr( $key );             #   $val--
$val   = $oh->getincr( $key );             #   $val++
$val   = $oh->incr( $key );                # ++$val
$val   = $oh->incrby( $key, $number );     #   $val += $number
$old   = $oh->getset( $key, $new );        #   $o = $v, $v = $n, $o

# pipeline, provides atomicity for shared objects, MCE::Shared v1.09+

@vals  = $oh->pipeline(                    # ( "a_a", "b_b", "c_c" )
   [ "set", foo => "a_a" ],
   [ "set", bar => "b_b" ],
   [ "set", baz => "c_c" ],
   [ "mget", qw/ foo bar baz / ]
);

For normal hash behavior, the TIE interface is supported. πŸͺ„

# non-shared or local construction for use by a single process

use MCE::Shared::Ordhash;

tie my %oh, "MCE::Shared::Ordhash", @pairs;
tie my %oh, "MCE::Shared::Ordhash";

# construction for sharing with other threads and processes
# the ordered option is needed to know to use MCE::Shared::Ordhash

use MCE::Shared;

tie my %oh, "MCE::Shared", { ordered => 1 }, @pairs;
tie my %oh, "MCE::Shared", ordered => 1;

# usage

my $val;

if ( !defined ( $val = $oh{some_key} ) ) {
   $val = $oh{some_key} = "some_value";
}

$oh{some_key} = 0;

tied(%oh)->incrby("some_key", 20);
tied(%oh)->incrby(some_key => 20);

πŸ¦‹ SYNTAX for QUERY STRING πŸ¦‹

Several methods take a query string for an argument. Here's the format, bestie. In the context of sharing, the query mechanism is beneficial for the shared-manager process. It is able to perform the query where the data resides, versus the client-process grep locally involving lots of IPC. πŸ’«

  • Basic demonstration
@keys = $oh->keys( "query string given here" );
@keys = $oh->keys( "val =~ /pattern/" );
  • Supported operators: =~ !~ eq ne lt le gt ge == != < <= > >=
  • Multiple expressions delimited by :AND or :OR, mixed case allowed
"key eq 'some key' :or (val > 5 :and val < 9)"
"key eq some key :or (val > 5 :and val < 9)"
"key =~ /pattern/i :And val =~ /pattern/i"
"val eq foo baz :OR key !~ /pattern/i"
  • key matches on keys in the hash
  • likewise, val matches on values
  • Quoting is optional inside the string
"key =~ /pattern/i :AND val eq 'foo bar'"   # val eq "foo bar"
"key =~ /pattern/i :AND val eq foo bar"     # val eq "foo bar"

Examples. πŸ’–

# search capability key/val: =~ !~ eq ne lt le gt ge == != < <= > >=
# key/val means to match against actual key/val respectively

@keys  = $oh->keys( "key eq 'some key' :or (val > 5 :and val < 9)" );
@keys  = $oh->keys( "key eq some key :or (val > 5 :and val < 9)" );

@keys  = $oh->keys( "key =~ /$pattern/i" );
@keys  = $oh->keys( "key !~ /$pattern/i" );
@keys  = $oh->keys( "val =~ /$pattern/i" );
@keys  = $oh->keys( "val !~ /$pattern/i" );

%pairs = $oh->pairs( "key == $number" );
%pairs = $oh->pairs( "key != $number :and val > 100" );
%pairs = $oh->pairs( "key <  $number :or key > $number" );
%pairs = $oh->pairs( "val <= $number" );
%pairs = $oh->pairs( "val >  $number" );
%pairs = $oh->pairs( "val >= $number" );

@vals  = $oh->vals( "key eq $string" );
@vals  = $oh->vals( "key ne $string with space" );
@vals  = $oh->vals( "key lt $string :or val =~ /$pat1|$pat2/" );
@vals  = $oh->vals( "val le $string :and val eq 'foo bar'" );
@vals  = $oh->vals( "val le $string :and val eq foo bar" );
@vals  = $oh->vals( "val gt $string" );
@vals  = $oh->vals( "val ge $string" );

πŸ‘‘ API DOCUMENTATION πŸ‘‘

This module involves TIE when accessing the object via hash-like behavior. Both non-shared and shared instances are impacted if doing so. Although likely fast enough for many use cases, the OO interface is recommended for best performance. πŸ’…

πŸ’… MCE::Shared::Ordhash->new ( key, value [, key, value, ... ] )

🌈 MCE::Shared->ordhash ( key, value [, key, value, ... ] )

Constructs a new object, with an optional list of key-value pairs. ✨

# non-shared or local construction for use by a single process

use MCE::Shared::Ordhash;

$oh = MCE::Shared::Ordhash->new( @pairs );
$oh = MCE::Shared::Ordhash->new( );

# construction for sharing with other threads and processes

use MCE::Shared;

$oh = MCE::Shared->ordhash( @pairs );
$oh = MCE::Shared->ordhash( );

🧹 assign ( key, value [, key, value, ... ] )

Clears the hash, then sets multiple key-value pairs and returns the number of keys stored in the hash. This is equivalent to clear, mset. 🫧

$len = $oh->assign( "key1" => "val1", "key2" => "val2" );  # 2
$len = %{$oh} = ( "key1" => "val1", "key2" => "val2" );    # 4

API available since 1.007. ⭐

🧼 clear

Removes all key-value pairs from the hash. 🧽

$oh->clear;
%{$oh} = ();

πŸŽ€ clone ( key [, key, ... ] )

Creates a shallow copy, a MCE::Shared::Ordhash object. It returns an exact copy if no arguments are given. Otherwise, the object includes only the given keys in the same order. Keys that do not exist in the hash will have the undef value. πŸͺž

$oh2 = $oh->clone( "key1", "key2" );
$oh2 = $oh->clone;

πŸ’€ delete ( key )

Deletes and returns the value by given key or undef if the key doesn't exist in the hash. 😭

$val = $oh->delete( "some_key" );
$val = delete $oh->{ "some_key" };

🏷️ del

del is an alias for delete. Periodt. πŸ’…

πŸ”Ž exists ( key )

Determines if a key exists in the hash. πŸ‘€

if ( $oh->exists( "some_key" ) ) { ... }
if ( exists $oh->{ "some_key" } ) { ... }

🚿 flush ( key [, key, ... ] )

Same as clone. Though, clears all existing items before returning. 🫧

🍬 get ( key )

Gets the value of a hash key or undef if the key doesn't exist. πŸ“

$val = $oh->get( "some_key" );
$val = $oh->{ "some_key" };

πŸ” iterator ( key [, key, ... ] )

Returns a code reference for iterating a list of key-value pairs stored in the hash when no arguments are given. Otherwise, returns a code reference for iterating the given keys in the same order. Keys that do not exist will have the undef value. πŸ‘‘

The list of keys to return is set when the closure is constructed. Later keys added to the hash are not included. Subsequently, the undef value is returned for deleted keys. πŸŒ€

$iter = $oh->iterator;
$iter = $oh->iterator( "key1", "key2" );

while ( my ( $key, $val ) = $iter->() ) {
   ...
}

πŸ” iterator ( "query string" )

Returns a code reference for iterating a list of key-value pairs that match the given criteria. It returns an empty list if the search found nothing. The syntax for the "query string" is described above. πŸ•΅οΈβ€β™€οΈ

$iter = $oh->iterator( "val eq some_value" );
$iter = $oh->iterator( "key eq some_key :AND val =~ /sun|moon|air|wind/" );
$iter = $oh->iterator( "val eq sun :OR val eq moon :OR val eq foo" );
$iter = $oh->iterator( "key =~ /$pattern/" );

while ( my ( $key, $val ) = $iter->() ) {
   ...
}

πŸ—οΈ keys ( key [, key, ...] )

Returns hash keys in the same insertion order when no arguments are given. Otherwise, returns the given keys in the same order. Keys that do not exist will have the undef value. In scalar context, returns the size of the hash. 🌟

@keys = $oh->keys( "key1", "key2" );

@keys = $oh->keys;     # faster
@keys = keys %{$oh};   # involves TIE overhead

$len  = $oh->keys;     # ditto
$len  = keys %{$oh};

πŸ”‘ keys ( "query string" )

bestie listen up πŸ’– this one hands you back only the keys that match whatever criteria you threw at it. Nothing matched? You get an empty list, no drama, no error, just vibes and silence πŸ’€. The syntax for that "query string" is the exact same one described up above, so no surprises ✨. Oh and if you call it in scalar context? It gives you the size of the resulting list instead β€” a little party trick, but a useful one πŸŽ€.

 @keys = $oh->keys( "val eq some_value" );
 @keys = $oh->keys( "key eq some_key :AND val =~ /sun|moon|air|wind/" );
 @keys = $oh->keys( "val eq sun :OR val eq moon :OR val eq foo" );
 $len  = $oh->keys( "key =~ /$pattern/" );

πŸ“ len ( key )

No arguments? It returns the size of the hash, periodt πŸ‘‘. Give it a key and you get back the length of the value stored at that key β€” or the undef value if that key doesn't exist at all πŸ™ˆ (yes, undef, not zero, not a warning, just undef).

 $size = $oh->len;
 $len  = $oh->len( "key1" );
 $len  = length $oh->{ "key1" };

πŸ—‘οΈ mdel ( key [, key, ... ] )

Deletes one or more keys from the hash and tells you how many it actually deleted. A key you name that isn't even in the hash? Not counted, not shamed, just ignored 🫢.

 $cnt = $oh->mdel( "key1", "key2" );

βœ… mexists ( key [, key, ... ] )

Returns a true value if all the given keys exist in the hash. Anything else gets a false value. All-or-nothing, it's giving main character energy πŸ’….

 if ( $oh->mexists( "key1", "key2" ) ) { ... }

🎁 mget ( key [, key, ... ] )

Grabs the values of all the keys you listed. Keys that don't exist in the hash come back as undef β€” no cap, that's just the deal 😭.

 ( $val1, $val2 ) = $oh->mget( "key1", "key2" );

πŸ“¦ mset ( key, value [, key, value, ... ] )

Sets a whole bunch of key-value pairs in one go and returns the number of keys stored in the hash. Bulk mode activated πŸ”₯.

 $len = $oh->mset( "key1" => "val1", "key2" => "val2" );

πŸͺ„ merge

merge is literally just an alias for mset. Same energy, different name ✨.


πŸ‘― pairs ( key [, key, ... ] )

No arguments? You get key-value pairs back in the same insertion order, untouched, exactly how you left them πŸŽ€. Give it keys and you get their key-value pairs back in the same order you asked. Keys that don't exist get the undef value. And in scalar context? It returns the size of the hash.

 @pairs = $oh->pairs( "key1", "key2" );

 @pairs = $oh->pairs;
 $len   = $oh->pairs;

πŸ‘―β€β™€οΈ pairs ( "query string" )

Same method, query-string flavour πŸ¦‹. Returns only the key-value pairs that match your criteria. Nothing matched β†’ empty list, that's it. The "query string" syntax is the one described above. Scalar context again gives you the size of the resulting list.

 @pairs = $oh->pairs( "val eq some_value" );
 @pairs = $oh->pairs( "key eq some_key :AND val =~ /sun|moon|air|wind/" );
 @pairs = $oh->pairs( "val eq sun :OR val eq moon :OR val eq foo" );
 $len   = $oh->pairs( "key =~ /$pattern/" );

🚰 pipeline ( [ func1, @args ], [ func2, @args ], ... )

Okay this is the icon of the whole section 🌈. pipeline combines multiple commands so the object processes them serially. And for shared objects? The call is made atomically, thanks to a single IPC to the shared-manager process β€” one trip, no traffic jam πŸ”₯. It's also fully wantarray-aware, and it receives a list of commands plus their arguments. In scalar or list context, you get back data from the last command in the pipeline (yes, only the last one β€” if you want all of them, keep reading bestie πŸ’œ).

 @vals = $oh->pipeline(                     # ( "a_a", "b_b", "c_c" )
    [ "set", foo => "a_a" ],
    [ "set", bar => "b_b" ],
    [ "set", baz => "c_c" ],
    [ "mget", qw/ foo bar baz / ]
 );

 $len = $oh->pipeline(                      # 3, same as $oh->len
    [ "set", foo => "i_i" ],
    [ "set", bar => "j_j" ],
    [ "set", baz => "k_k" ],
    [ "len" ]
 );

 $oh->pipeline(
    [ "set", foo => "m_m" ],
    [ "set", bar => "n_n" ],
    [ "set", baz => "o_o" ]
 );

Current API available since 1.809.


🚰✨ pipeline_ex ( [ func1, @args ], [ func2, @args ], ... )

Exactly like pipeline, but this one hands you back data for every single command in the pipeline πŸ’–. Greedy in the best way.

 @vals = $oh->pipeline_ex(                  # ( "a_a", "b_b", "c_c" )
    [ "set", foo => "a_a" ],
    [ "set", bar => "b_b" ],
    [ "set", baz => "c_c" ]
 );

Current API available since 1.809.


🍿 pop

Removes and returns the last key-value pair of the ordered hash β€” or just the value if you're in scalar context. If there are no keys in the hash at all, you get the undefined value πŸ”š.

 ( $key, $val ) = $oh->pop;

 $val = $oh->pop;

🧹 purge

A lil utility method for purging any tombstones sitting in the keys array πŸͺ¦βœ¨. It also resets a couple counters internally. Call this method before serializing to a file β€” that's exactly the case in MCE::Shared::Minidb, so don't skip it πŸ™.

 $oh->purge;

βž• push ( key, value [, key, value, ... ] )

Appends one or multiple key-value pairs to the tail of the ordered hash and returns the new length πŸŽ€. Heads up: any keys that already exist in the hash get re-inserted with the new values β€” so they move, they don't duplicate πŸ‘€.

 $len = $oh->push( "key1", "val1", "key2", "val2" );

πŸ–ŠοΈ set ( key, value )

Sets the value of the given hash key and returns its new value. Simple, iconic, does what it says πŸ’….

 $val = $oh->set( "key", "value" );
 $val = $oh->{ "key" } = "value";

🌱 setnx ( key, value )

Sets the value of a hash key only if the key does not exist πŸ™…β€β™€οΈ. Returns a 1 for a new key, or a 0 if the key already exists and no operation was performed. Zero drama, zero overwrites.

 $ret = $oh->setnx( "key", "value" );

Current API available since 1.872.


πŸ₯‡ shift

Removes and returns the first key-value pair of the ordered hash β€” or just the value in scalar context. No keys in the hash? Undefined value, as ever 🫠.

 ( $key, $val ) = $oh->shift;

 $val = $oh->shift;

πŸ”€ sort ( "BY key [ ASC | DESC ] [ ALPHA ]" )

πŸ”€ sort ( "BY val [ ASC | DESC ] [ ALPHA ]" )

Returns sorted keys in list context, leaving the elements themselves intact πŸ¦‹. In void context it sorts the hash in-place β€” so careful, that one actually changes things πŸ‘€. By default, sorting is numeric and applied to values when you pass no arguments at all.

 @keys = $oh->sort( "BY val" );

 $oh->sort();

Got string values in your keys or values and you want them sorted lexicographically? Slap on the ALPHA modifier, bestie ✨:

 @keys = $oh->sort( "BY key ALPHA" );

 $oh->sort( "BY val ALPHA" );

Default direction is ASC, small to large πŸ“ˆ. Wanna go large to small? That's the DESC modifier, and it's giving reverse-chronological feed energy πŸ’…:

 @keys = $oh->sort( "BY val DESC ALPHA" );

 $oh->sort( "BY key DESC ALPHA" );

βœ‚οΈ splice ( offset [, length [, key, value, ... ] ] )

Removes the key-value pairs designated by offset and length from the ordered hash, then replaces them with the key-value pairs if you gave any πŸŽ€. Behavior is similar to the Perl splice function β€” same vibe, ordered-hash edition.

 @pairs = $oh->splice( 20, 2, @pairs );
 @pairs = $oh->splice( 20, 2 );
 @pairs = $oh->splice( 20 );

⬆️ unshift ( key, value [, key, value, ... ] )

Prepends one or multiple key-value pairs to the head of the ordered hash and returns the new length πŸ‘‘. Same rule as push: any keys already existing in the hash get re-inserted with the new values πŸ™ˆ.

 $len = $oh->unshift( "key1", "val1", "key2", "val2" );

πŸ’Ž values ( key [, key, ... ] )

No arguments? You get hash values in the same insertion order, untouched 🌸. Give it keys and you get values back in the same order you asked. Keys that don't exist get the undef value. Scalar context β†’ the size of the hash.

 @vals = $oh->values( "key1", "key2" );

 @vals = $oh->values;     # faster
 @vals = values %{$oh};   # involves TIE overhead

 $len  = $oh->values;     # ditto
 $len  = values %{$oh};
ngl that # faster comment is doing a lot of work β€” the direct method call beats the tied values %{$oh} every time, and the # ditto on the scalar version means the same thing applies 😌

πŸ’Ž values ( "query string" )

Query-string flavour, same as always 🧚: returns only the values that match your criteria, empty list if nothing matched, syntax described up above. Scalar context gives you the size of the resulting list.

 @vals = $oh->values( "val eq some_value" );
 @vals = $oh->values( "key eq some_key :AND val =~ /sun|moon|air|wind/" );
 @vals = $oh->values( "val eq sun :OR val eq moon :OR val eq foo" );
 $len  = $oh->values( "key =~ /$pattern/" );

πŸ’Ž vals

vals is an alias for values. Two names, one icon πŸ’œ.


🍬 SUGAR METHODS 🍬

This module is equipped with sugar methods so you don't have to call set and get explicitly πŸŽ€βœ¨. In shared context the benefit is atomicity and a reduction in inter-process communication β€” fewer messages, same result, chef's kiss πŸ”₯.

The API resembles a subset of the Redis primitives with key representing the hash key πŸ‘‘.


🧡 append ( key, string )

Appends a value to a key and returns its new length 🌱.

 $len = $oh->append( $key, "foo" );

πŸ“‰ decr ( key )

Decrements the value of a key by one and returns its new value πŸ’….

 $num = $oh->decr( $key );

πŸ“‰πŸ“‰ decrby ( key, number )

Decrements the value of a key by the given number and returns its new value πŸ¦‹.

 $num = $oh->decrby( $key, 2 );

πŸ•°οΈ getdecr ( key )

Decrements the value of a key by one and returns its old value β€” sneaky little time traveller 😭.

 $old = $oh->getdecr( $key );

πŸ•°οΈ getincr ( key )

Increments the value of a key by one and returns its old value. Same trick, opposite direction πŸ’€.

 $old = $oh->getincr( $key );

πŸ”„ getset ( key, value )

Sets the value of a key and returns its old value 🎁.

 $old = $oh->getset( $key, "baz" );

πŸ“ˆ incr ( key )

Increments the value of a key by one and returns its new value ✨.

 $num = $oh->incr( $key );

πŸ“ˆπŸ“ˆ incrby ( key, number )

Increments the value of a key by the given number and returns its new value πŸ”₯.

 $num = $oh->incrby( $key, 2 );

πŸ’ CREDITS πŸ’

Many thanks to David Golden for Hash::Ordered 🫢 β€” this implementation is inspired by Hash::Ordered v0.009. Absolute legend behavior, no cap πŸ‘‘πŸ’–.

πŸ”₯ MOTIVATION πŸ”₯

okay so bestie, here's the tea β˜• β€” the whole reason this module exists. I wanted an ordered hash implementation for use with MCE::Shared that has, like, zero side effects. no linear scans, no slow deletes, no excessive memory consumption. the closest module on CPAN to pass in this regard is Hash::Ordered by David Golden. king behavior honestly πŸ‘‘

so MCE::Shared has only one shared-manager process β€” that's by design, no cap. so I re-factored tombstone deletion with extras, specifically so there'd be lesser impact to the rest of the library. this module differs in personality from Hash::Ordered mainly for compatibility with the other classes included with MCE::Shared. it's giving team player πŸ’…

the following simulates a usage pattern inside MCE::Hobo involving random key deletion β€” for example, an application joining a list of Hobos provided by "MCE::Hobo->list_joinable":

 use MCE::Shared::Ordhash;
 use List::Util 'shuffle';
 use Time::HiRes 'time';

 srand 0;

 my $oh = MCE::Shared::Ordhash->new();
 my $num_keys = 200000;
 my $start = time();

 $oh->set($_,$_) for 1 .. $num_keys;

 for ( shuffle $oh->keys ) {
    $oh->delete($_);
 }

 printf "duration: %7.03f secs\n", time() - $start;

both the runtime and memory consumption are captured for the demonstration β€” we're thorough like that πŸ’– results are included for MCE::Shared::Hash (the unordered hash) for comparison:

 for ( shuffle $oh->keys ) { $oh->delete($_) }
 0.378 secs.  35 MB  MCE::Shared::Hash (unordered)
 0.437 secs.  49 MB  Tie::Hash::Indexed (XS)
 0.743 secs.  54 MB  MCE::Shared::Ordhash
 1.028 secs.  60 MB  Hash::Ordered
 1.752 secs. 112 MB  Tie::LLHash
  > 42 mins.  66 MB  Tie::IxHash

look at Tie::IxHash just sitting there for over 42 minutes 😭 not me feeling bad for it. anywayβ€”

using the same demonstration above, another usage pattern inside MCE::Hobo involves orderly hash-key deletion. for example, waiting for and joining all Hobos provided by "MCE::Hobo->list":

 for ( $oh->keys ) { $oh->delete($_) }
 0.353 secs.  35 MB  MCE::Shared::Hash (unordered)
 0.349 secs.  49 MB  Tie::Hash::Indexed (XS)
 0.452 secs.  41 MB  MCE::Shared::Ordhash
 0.735 secs.  54 MB  Hash::Ordered
 1.338 secs. 112 MB  Tie::LLHash
  > 42 mins.  66 MB  Tie::IxHash

and the verdict? no matter if orderly or randomly β€” even backwards β€” hash-key deletion in "MCE::Shared::Ordhash" performs reasonably well. she's versatile, she's consistent, she ate πŸ”₯

the following provides the construction used for the modules mentioned:

 my $oh = Hash::Ordered->new();
    $oh->set($_,$_);   $oh->keys;  $oh->delete($_);

 my $oh = Tie::Hash::Indexed->new();
    $oh->set($_,$_);   $oh->keys;  $oh->delete($_);

 my $oh = Tie::IxHash->new();
    $oh->STORE($_,$_); $oh->Keys;  $oh->DELETE($_);

 my $oh = tie my %hash, 'Tie::LLHash';
    $oh->last($_,$_);  keys %hash; $oh->DELETE($_);

Hash::Ordered is supported for use with MCE::Shared β€” yes bestie, the crossover episode happened πŸ¦‹ this includes on-demand hash-like dereferencing, similarly to "hash" and "ordhash":

 use feature 'say';

 use MCE::Hobo;
 use MCE::Shared;
 use Hash::Ordered; # 0.010 or later

 my $ha = MCE::Shared->hash();    # shared MCE::Shared::Hash
 my $oh = MCE::Shared->ordhash(); # shared MCE::Shared::Ordhash

 my $ho = MCE::Shared->share( Hash::Ordered->new() );

 sub parallel_task {
    my ($id) = @_;

    # OO interface
    if ($id == 1) {
       $ha->set("$id", "foo");
       $oh->set("$id", "foo");
       $ho->set("$id", "foo");
    }
    # hash-like dereferencing
    elsif ($id == 2) {
       $ha->{"$id"} = "baz";
       $oh->{"$id"} = "baz";
       $ho->{"$id"} = "baz";
    }

    return;
 }

 MCE::Hobo->create("parallel_task", $_) for 1..2;
 MCE::Hobo->waitall;

 say $ha->{"1"};     # foo
 say $oh->{"1"};
 say $ho->{"1"};

 say $ha->get("2");  # baz
 say $oh->get("2");
 say $ho->get("2");

like, all three of them just vibing and returning the same thing? iconic. no notes πŸ‘‘


✨ SEE ALSO ✨

  • Hash::Ordered
  • Tie::Hash::Indexed
  • Tie::IxHash
  • Tie::LLHash

πŸŽ€ INDEX πŸŽ€

MCE, MCE::Hobo, MCE::Shared

πŸ’œ AUTHOR πŸ’œ

Mario E. Roy, <marioeroy AT gmail DOT com>


and that's a wrap bestie!! 🫢 this page is from perl v5.40.0, dated 2024-09-10 β€” go forth and ordhash responsibly, ily, bye πŸ§šπŸ’–

πŸ“¦ where this page comes from