#!/usr/bin/perl

# Idiom #313 Map equality

use strict;
use warnings;

sub hcmp_numeric {
    my ($h, $g) = @_;

    my $hc = keys %$h;
    my $gc = keys %$g;

    return 0 unless $hc == $gc;
    return 0 unless $hc == grep { exists $g->{$_} } keys %$h;
    die 'non-scalar value detected' 
        if 0 < grep { ref $h->{$_} or ref $g->{$_} } keys %$h;
    return 0 unless $hc == grep { $h->{$_} == $g->{$_} } keys %$h;
    return 1;
}

my $a = { A => 1, B => 2, C => 3 };
my $b = { A => 1, B => 2, C => 3, D => 4 };
my $c = { A => 1, B => 2, C => 99 };
my $d = { A => 1, xBx => 2, C => 3 };
my $e = { A => 1 };
my $f = { };

print 'hcmp(a,a): ', hcmp_numeric( $a, $a ) ? 'matched' : 'not matched', "\n";
print 'hcmp(a,b): ', hcmp_numeric( $a, $b ) ? 'matched' : 'not matched', "\n";
print 'hcmp(a,c): ', hcmp_numeric( $a, $c ) ? 'matched' : 'not matched', "\n";
print 'hcmp(a,d): ', hcmp_numeric( $a, $d ) ? 'matched' : 'not matched', "\n";
print 'hcmp(a,e): ', hcmp_numeric( $a, $e ) ? 'matched' : 'not matched', "\n";
print 'hcmp(a,f): ', hcmp_numeric( $a, $f ) ? 'matched' : 'not matched', "\n";
print 'hcmp(f,f): ', hcmp_numeric( $f, $f ) ? 'matched' : 'not matched', "\n";

use Try::Tiny;

my $x = { A => 1, B => 2 , C => 3 };
my $y = { A => 1, B => [], C => 3 };

try {
    print 'hcmp(x,y): ', hcmp_numeric( $x, $y ) ? 'matched' : 'not matched', "\n";
} catch {
    print $_;
};

try {
    print 'hcmp(y,x): ', hcmp_numeric( $y, $x ) ? 'matched' : 'not matched', "\n";
} catch {
    print $_;
};

try {
    print 'hcmp(y,y): ', hcmp_numeric( $y, $y ) ? 'matched' : 'not matched', "\n";
} catch {
    print $_;
};
