Question

I have a situation where I want to create a signature of a data structure:

my $signature = ds_to_sig(
  { foo   => 'bar',
    baz   => 'bundy',
    boing => undef,
    number => 1_234_567,
  }
);

The aim should be that if the data structure changes then so should the signature.

Is there an established way to do this?

Was it helpful?

Solution

The best way to do this is to use a deep-structure serialization system like Storable. Two structures with the same data will produce the same blob of Storable output, so they can be compared.

#!/usr/bin/perl

use strict;
use warnings;

use Storable ('freeze');

$Storable::canonical = 1;

my $one = { foo => 42, bar => [ 1, 2, 3 ] };
my $two = { foo => 42, bar => [ 1, 2, 3 ] };

my $one_s = freeze $one;
my $two_s = freeze $two;

print "match\n" if $one_s eq $two_s;

...And to prove the inverse:

$one = [ 4, 5, 6 ];
$one_s = freeze $one;

print "no match" if $one_s ne $two_s;

OTHER TIPS

I think what you're looking for is a hash function. I would recommend an approach like this:

use Storable;
$Storable::canonical = 1;
sub ds_to_sig {
    my $structure = shift;
    return hash(freeze $structure);
}

The function hash can be any hash function, for example the function md5 from Digest::MD5

Use Storable::nstore to turn it into a binary representation, and then calculate a checksum (for example with the Digest module).

Both modules are core modules.

Digest::MD5->new->add(
  Data::Dumper->new([$structure])
   ->Purity(0)
   ->Terse(1)
   ->Indent(0)
   ->Useqq(1)
   ->Sortkeys(1)
   ->Dump()
)->b64digest();

I think the word you're looking for is "hashing".

Basically, you put your data structure through a function that generates a fairly unique value from it. This value would be your signiture.

Can't you use an object instead of a struct? That way you could see if an object is an instance of a type without having to compare hashes, etc.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top