# This file was autogenerated.
use 5.008001;
use strict;
use warnings;
no warnings qw( void once );
use Hydrogen ();

package Hydrogen::Hash;

our $AUTHORITY = 'cpan:TOBYINK';
our $VERSION   = '0.017';

=head1 NAME

Hydrogen::Hash - a standard library for hashes

=head1 VERSION

This documentation is for Hydrogen::Hash 0.017,
which is based on Sub::HandlesVia::HandlerLibrary::Hash 0.038.

=cut

=head1 FUNCTIONS

Each function expects a hash as its first argument.

The functions use prototypes, so you don't have to pass a reference.

=cut

use Exporter::Shiny qw(
    accessor
    all
    clear
    count
    defined
    delete
    delete_where
    elements
    exists
    for_each_key
    for_each_pair
    for_each_value
    get
    is_empty
    keys
    kv
    reset
    set
    shallow_clone
    sorted_keys
    values
);

=head2 C<< accessor( %hash, $key, $value? ) >>

Additional arguments: B<< Str >>, B<< Optional[Any] >>.

Acts like C<get> if given just a key, or C<set> if given a key and a value.

=cut

{
    my $__signature;

    sub accessor (\%$;$) {
        my $__REF__ = \$_[0];

        package Hydrogen::Hash::__SANDBOX__;
        $__signature ||= sub {
            my ( %tmp, $tmp );

            @_ >= 2 && @_ <= 3
              or Hydrogen::croak(
                "Wrong number of parameters in signature for %s: got %d, %s",
                "accessor", scalar(@_), "expected exactly 2 parameters" );

            # Parameter $_[0] (type: HashRef)
            ( ref( $_[0] ) eq 'HASH' )
              or Hydrogen::croak(
                "Type check failed in signature for accessor: %s should be %s",
                "\$_[0]", "HashRef"
              );

            # Parameter $_[1] (type: Str)
            do {

                package Hydrogen::Hash::__SANDBOX__;
                defined( $_[1] ) and do {
                    ref( \$_[1] ) eq 'SCALAR'
                      or ref( \( my $val = $_[1] ) ) eq 'SCALAR';
                }
              }
              or Hydrogen::croak(
                "Type check failed in signature for accessor: %s should be %s",
                "\$_[1]", "Str"
              );

            # Parameter $_[2] (type: Optional[Any])
            $#_ >= 2
              or return (@_);
            ( !!1 )
              or Hydrogen::croak(
                "Type check failed in signature for accessor: %s should be %s",
                "\$_[2]", "Optional[Any]"
              );

            (@_);
        };
        @_ = &$__signature;
        1;
        ( ( @_ - 1 ) == 1 )
          ? ($$__REF__)->{ $_[1] }
          : ( ($$__REF__)->{ $_[1] } = $_[2] );
    }
}

=head2 C<< all( %hash ) >>

Returns the hash in list context.

=cut

sub all (\%) {
    my $__REF__ = \$_[0];

    package Hydrogen::Hash::__SANDBOX__;
    @_ == 1
      or Hydrogen::croak( "Wrong number of parameters for all; usage: "
          . "Hydrogen::Hash::all( %hash )" );
    %{$$__REF__};
}

=head2 C<< clear( %hash ) >>

Empties the hash.

=cut

sub clear (\%) {
    my $__REF__ = \$_[0];

    package Hydrogen::Hash::__SANDBOX__;
    @_ == 1
      or Hydrogen::croak( "Wrong number of parameters for clear; usage: "
          . "Hydrogen::Hash::clear( %hash )" );
    1;
    %{$$__REF__} = ();
}

=head2 C<< count( %hash ) >>

Returns the number of keys in the hash.

=cut

sub count (\%) {
    my $__REF__ = \$_[0];

    package Hydrogen::Hash::__SANDBOX__;
    @_ == 1
      or Hydrogen::croak( "Wrong number of parameters for count; usage: "
          . "Hydrogen::Hash::count( %hash )" );
    scalar keys %{$$__REF__};
}

=head2 C<< defined( %hash, $key ) >>

Additional arguments: B<< Str >>.

Indicates whether a value exists and is defined in the hashref by its key.

=cut

sub defined (\%$) {
    my $__REF__ = \$_[0];

    package Hydrogen::Hash::__SANDBOX__;
    @_ = do {
        my ( %tmp, $tmp );

        @_ == 2
          or Hydrogen::croak(
            "Wrong number of parameters in signature for %s: got %d, %s",
            "defined", scalar(@_), "expected exactly 2 parameters" );

        # Parameter $_[0] (type: HashRef)
        ( ref( $_[0] ) eq 'HASH' )
          or Hydrogen::croak(
            "Type check failed in signature for defined: %s should be %s",
            "\$_[0]", "HashRef" );

        # Parameter $_[1] (type: Str)
        do {

            package Hydrogen::Hash::__SANDBOX__;
            defined( $_[1] ) and do {
                ref( \$_[1] ) eq 'SCALAR'
                  or ref( \( my $val = $_[1] ) ) eq 'SCALAR';
            }
          }
          or Hydrogen::croak(
            "Type check failed in signature for defined: %s should be %s",
            "\$_[1]", "Str" );

        (@_);
    };
    defined( ($$__REF__)->{ $_[1] } );
}

=head2 C<< delete( %hash, $key ) >>

Removes a value from the hashref by its key.

=cut

sub delete (\%$;@) {
    my $__REF__ = \$_[0];

    package Hydrogen::Hash::__SANDBOX__;
    @_ >= 2
      or Hydrogen::croak( "Wrong number of parameters for delete; usage: "
          . "Hydrogen::Hash::delete( %hash, \$key )" );
    1;
    delete( @{$$__REF__}{ @_[ 1 .. $#_ ] } );
}

=head2 C<< delete_where( %hash, $match ) >>

Additional arguments: B<< CodeRef|RegexpRef >>.

Removes values from the hashref by matching keys against a coderef or regexp.

=cut

sub delete_where (\%$;@) {
    my $__REF__ = \$_[0];

    package Hydrogen::Hash::__SANDBOX__;
    @_ = do {
        my ( %tmp, $tmp );

        @_ == 2
          or Hydrogen::croak(
            "Wrong number of parameters in signature for %s: got %d, %s",
            "delete_where", scalar(@_), "expected exactly 2 parameters" );

        # Parameter $_[0] (type: HashRef)
        ( ref( $_[0] ) eq 'HASH' )
          or Hydrogen::croak(
            "Type check failed in signature for delete_where: %s should be %s",
            "\$_[0]", "HashRef"
          );

        # Parameter $_[1] (type: CodeRef|RegexpRef)
        do {

            package Hydrogen::Hash::__SANDBOX__;
            (
                ( ref( $_[1] ) eq 'CODE' ) or (
                    do {

                        package Hydrogen::Hash::__SANDBOX__;
                        use Scalar::Util ();
                        use re           ();
                        ref( $_[1] ) && !!re::is_regexp( $_[1] )
                          or Scalar::Util::blessed( $_[1] )
                          && $_[1]->isa('Regexp');
                    }
                )
            );
          }
          or Hydrogen::croak(
            "Type check failed in signature for delete_where: %s should be %s",
            "\$_[1]", "CodeRef|RegexpRef"
          );

        (@_);
    };
    my %shv_tmp   = %{$$__REF__};
    my $shv_match = $_[1];
    my @shv_keys =
      ( "CODE" eq ref $shv_match )
      ? grep( $shv_match->($_), keys %shv_tmp )
      : grep( /$shv_match/,     keys %shv_tmp );
    my @shv_return = delete @shv_tmp{@shv_keys};
    (
        %{ $_[0] } = %{
            +do {
                my $shv_final_unchecked = \%shv_tmp;
                do {
                    ( ref($shv_final_unchecked) eq 'HASH' )
                      or Hydrogen::croak(
"Type check failed for delete_where: expected %s, got value %s",
                        "HashRef", $shv_final_unchecked
                      );
                    $shv_final_unchecked;
                };
            }
        }
    );
    wantarray ? @shv_return : $shv_return[-1];
}

=head2 C<< elements( %hash ) >>

Returns the hash in list context.

=cut

sub elements (\%) {
    my $__REF__ = \$_[0];

    package Hydrogen::Hash::__SANDBOX__;
    @_ == 1
      or Hydrogen::croak( "Wrong number of parameters for elements; usage: "
          . "Hydrogen::Hash::elements( %hash )" );
    %{$$__REF__};
}

=head2 C<< exists( %hash, $key ) >>

Additional arguments: B<< Str >>.

Indicates whether a value exists in the hashref by its key.

=cut

sub exists (\%$) {
    my $__REF__ = \$_[0];

    package Hydrogen::Hash::__SANDBOX__;
    @_ = do {
        my ( %tmp, $tmp );

        @_ == 2
          or Hydrogen::croak(
            "Wrong number of parameters in signature for %s: got %d, %s",
            "exists", scalar(@_), "expected exactly 2 parameters" );

        # Parameter $_[0] (type: HashRef)
        ( ref( $_[0] ) eq 'HASH' )
          or Hydrogen::croak(
            "Type check failed in signature for exists: %s should be %s",
            "\$_[0]", "HashRef" );

        # Parameter $_[1] (type: Str)
        do {

            package Hydrogen::Hash::__SANDBOX__;
            defined( $_[1] ) and do {
                ref( \$_[1] ) eq 'SCALAR'
                  or ref( \( my $val = $_[1] ) ) eq 'SCALAR';
            }
          }
          or Hydrogen::croak(
            "Type check failed in signature for exists: %s should be %s",
            "\$_[1]", "Str" );

        (@_);
    };
    defined( ($$__REF__)->{ $_[1] } );
}

=head2 C<< for_each_key( %hash, $coderef ) >>

Additional arguments: B<< CodeRef >>.

Function which calls the coderef for each key in the hash, passing just the key to the coderef.

=cut

sub for_each_key (\%$) {
    my $__REF__ = \$_[0];

    package Hydrogen::Hash::__SANDBOX__;
    @_ = do {
        my ( %tmp, $tmp );

        @_ == 2
          or Hydrogen::croak(
            "Wrong number of parameters in signature for %s: got %d, %s",
            "for_each_key", scalar(@_), "expected exactly 2 parameters" );

        # Parameter $_[0] (type: HashRef)
        ( ref( $_[0] ) eq 'HASH' )
          or Hydrogen::croak(
            "Type check failed in signature for for_each_key: %s should be %s",
            "\$_[0]", "HashRef"
          );

        # Parameter $_[1] (type: CodeRef)
        ( ref( $_[1] ) eq 'CODE' )
          or Hydrogen::croak(
            "Type check failed in signature for for_each_key: %s should be %s",
            "\$_[1]", "CodeRef"
          );

        (@_);
    };
    for my $shv_key ( keys %{$$__REF__} ) { &{ $_[1] }($shv_key) };
    $__REF__;
}

=head2 C<< for_each_pair( %hash, $coderef ) >>

Additional arguments: B<< CodeRef >>.

Function which calls the coderef for each key in the hash, passing the key and value to the coderef.

=cut

sub for_each_pair (\%$) {
    my $__REF__ = \$_[0];

    package Hydrogen::Hash::__SANDBOX__;
    @_ = do {
        my ( %tmp, $tmp );

        @_ == 2
          or Hydrogen::croak(
            "Wrong number of parameters in signature for %s: got %d, %s",
            "for_each_pair", scalar(@_), "expected exactly 2 parameters" );

        # Parameter $_[0] (type: HashRef)
        ( ref( $_[0] ) eq 'HASH' )
          or Hydrogen::croak(
            "Type check failed in signature for for_each_pair: %s should be %s",
            "\$_[0]", "HashRef"
          );

        # Parameter $_[1] (type: CodeRef)
        ( ref( $_[1] ) eq 'CODE' )
          or Hydrogen::croak(
            "Type check failed in signature for for_each_pair: %s should be %s",
            "\$_[1]", "CodeRef"
          );

        (@_);
    };
    while ( my ( $shv_key, $shv_value ) = each %{$$__REF__} ) {
        &{ $_[1] }( $shv_key, $shv_value );
    };
    $__REF__;
}

=head2 C<< for_each_value( %hash, $coderef ) >>

Additional arguments: B<< CodeRef >>.

Function which calls the coderef for each value in the hash, passing just the value to the coderef.

=cut

sub for_each_value (\%$) {
    my $__REF__ = \$_[0];

    package Hydrogen::Hash::__SANDBOX__;
    @_ = do {
        my ( %tmp, $tmp );

        @_ == 2
          or Hydrogen::croak(
            "Wrong number of parameters in signature for %s: got %d, %s",
            "for_each_value", scalar(@_), "expected exactly 2 parameters" );

        # Parameter $_[0] (type: HashRef)
        ( ref( $_[0] ) eq 'HASH' )
          or Hydrogen::croak(
"Type check failed in signature for for_each_value: %s should be %s",
            "\$_[0]", "HashRef"
          );

        # Parameter $_[1] (type: CodeRef)
        ( ref( $_[1] ) eq 'CODE' )
          or Hydrogen::croak(
"Type check failed in signature for for_each_value: %s should be %s",
            "\$_[1]", "CodeRef"
          );

        (@_);
    };
    for my $shv_value ( values %{$$__REF__} ) { &{ $_[1] }($shv_value) };
    $__REF__;
}

=head2 C<< get( %hash, $key ) >>

Returns a value from the hashref by its key.

=cut

sub get (\%$;@) {
    my $__REF__ = \$_[0];

    package Hydrogen::Hash::__SANDBOX__;
    @_ >= 2
      or Hydrogen::croak( "Wrong number of parameters for get; usage: "
          . "Hydrogen::Hash::get( %hash, \$key )" );
    ( @_ - 1 ) > 1 ? @{$$__REF__}{ @_[ 1 .. $#_ ] } : ($$__REF__)->{ $_[1] };
}

=head2 C<< is_empty( %hash ) >>

Returns true iff there are no keys in the hash.

=cut

sub is_empty (\%) {
    my $__REF__ = \$_[0];

    package Hydrogen::Hash::__SANDBOX__;
    @_ == 1
      or Hydrogen::croak( "Wrong number of parameters for is_empty; usage: "
          . "Hydrogen::Hash::is_empty( %hash )" );
    !scalar keys %{$$__REF__};
}

=head2 C<< keys( %hash ) >>

Returns the list of keys in the hash.

=cut

sub keys (\%) {
    my $__REF__ = \$_[0];

    package Hydrogen::Hash::__SANDBOX__;
    @_ == 1
      or Hydrogen::croak( "Wrong number of parameters for keys; usage: "
          . "Hydrogen::Hash::keys( %hash )" );
    keys %{$$__REF__};
}

=head2 C<< kv( %hash ) >>

Returns a list of arrayrefs, where each arrayref is a key-value pair.

=cut

sub kv (\%) {
    my $__REF__ = \$_[0];

    package Hydrogen::Hash::__SANDBOX__;
    @_ == 1
      or Hydrogen::croak( "Wrong number of parameters for kv; usage: "
          . "Hydrogen::Hash::kv( %hash )" );
    map [ $_ => ($$__REF__)->{$_} ], keys %{$$__REF__};
}

=head2 C<< reset( %hash ) >>

Resets the original value to its default value, or an empty hashref if it has no default.

=cut

sub reset (\%) {
    my $__REF__ = \$_[0];

    package Hydrogen::Hash::__SANDBOX__;
    @_ == 1
      or Hydrogen::croak( "Wrong number of parameters for reset; usage: "
          . "Hydrogen::Hash::reset( %hash )" );
    (
        %{ $_[0] } = %{
            +do {
                my $shv_final_unchecked = {};
                do {
                    ( ref($shv_final_unchecked) eq 'HASH' )
                      or Hydrogen::croak(
"Type check failed for reset: expected %s, got value %s",
                        "HashRef", $shv_final_unchecked
                      );
                    $shv_final_unchecked;
                };
            }
        }
    );
}

=head2 C<< set( %hash, $key, $value, ... ) >>

Given a key and value, adds the key to the hashref with the given value.

=cut

sub set (\%$$;@) {
    my $__REF__ = \$_[0];

    package Hydrogen::Hash::__SANDBOX__;
    @_ >= 3
      or Hydrogen::croak( "Wrong number of parameters for set; usage: "
          . "Hydrogen::Hash::set( %hash, \$key, \$value, ... )" );
    my (@shv_params) = @_[ 1 .. $#_ ];
    scalar(@shv_params) % 2
      and Hydrogen::croak(
"Wrong number of parameters; expected even-sized list of keys and values"
      );
    my (@shv_keys_idx)   = grep( !( $_ % 2 ), 0 .. $#shv_params );
    my (@shv_values_idx) = grep( ( $_ % 2 ),  0 .. $#shv_params );
    grep( !defined, @shv_params[@shv_keys_idx] )
      and Hydrogen::croak(
        "Undef did not pass type constraint; keys must be defined");

    for my $shv_tmp (@shv_keys_idx) {
        do {
            do {

                package Hydrogen::Hash::__SANDBOX__;
                defined( $shv_params[$shv_tmp] ) and do {
                    ref( \$shv_params[$shv_tmp] ) eq 'SCALAR'
                      or ref( \( my $val = $shv_params[$shv_tmp] ) ) eq 'SCALAR';
                }
              }
              or Hydrogen::croak(
                "Type check failed for set: expected %s, got value %s",
                "Str", $shv_params[$shv_tmp] );
            $shv_params[$shv_tmp];
        };
    };
    @{$$__REF__}{ @shv_params[@shv_keys_idx] } = @shv_params[@shv_values_idx];
    wantarray
      ? @{$$__REF__}{ @shv_params[@shv_keys_idx] }
      : ($$__REF__)->{ $shv_params[ $shv_keys_idx[0] ] };
}

=head2 C<< shallow_clone( %hash ) >>

Creates a new hashref with the same keys and values as the original.

=cut

sub shallow_clone (\%) {
    my $__REF__ = \$_[0];

    package Hydrogen::Hash::__SANDBOX__;
    @_ == 1
      or
      Hydrogen::croak( "Wrong number of parameters for shallow_clone; usage: "
          . "Hydrogen::Hash::shallow_clone( %hash )" );
    +{ %{$$__REF__} };
}

=head2 C<< sorted_keys( %hash ) >>

Returns an alphabetically sorted list of keys in the hash.

=cut

sub sorted_keys (\%) {
    my $__REF__ = \$_[0];

    package Hydrogen::Hash::__SANDBOX__;
    @_ == 1
      or Hydrogen::croak( "Wrong number of parameters for sorted_keys; usage: "
          . "Hydrogen::Hash::sorted_keys( %hash )" );
    sort( keys %{$$__REF__} );
}

=head2 C<< values( %hash ) >>

Returns the list of values in the hash.

=cut

sub values (\%) {
    my $__REF__ = \$_[0];

    package Hydrogen::Hash::__SANDBOX__;
    @_ == 1
      or Hydrogen::croak( "Wrong number of parameters for values; usage: "
          . "Hydrogen::Hash::values( %hash )" );
    values %{$$__REF__};
}

1;

=head1 EXPORT

No functions are exported by this module by default. To import them all (this is usually a bad idea), use:

    use Hydrogen::Hash -all;

To import a particular function, use:

    use Hydrogen::Hash 'clear';

To rename functions:

    use Hydrogen::Hash 'clear' => { -as => 'myfunc' };

On Perl 5.37.2+, you can import lexically:

    use Hydrogen::Hash -lexical, 'clear';

See L<Exporter::Tiny::Manual::Importing> for more hints on importing.

=head1 BUGS

Please report any bugs to
L<http://github.com/tobyink/p5-hydrogen/issues>.

=head1 SEE ALSO

L<Hydrogen>,
L<Hydrogen::Curry::HashRef>,
L<Hydrogen::Topic::HashRef>,
L<Sub::HandlesVia::HandlerLibrary::Hash>,
L<Hash::Util>.

=head1 AUTHOR

Toby Inkster E<lt>tobyink@cpan.orgE<gt>.

=head1 COPYRIGHT AND LICENCE

This software is copyright (c) 2022 by Toby Inkster.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=head1 DISCLAIMER OF WARRANTIES

THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

