The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
Changes 315
Decoder.xs 431
MANIFEST 03
META.json 22
META.yml 22
Makefile.PL 210
author_tools/bench.pl 193358
author_tools/decode.pl 0249
author_tools/hobodecoder.pl 2235
author_tools/update_from_header.pl 1040
const-xs.inc 11
inc/Sereal/BuildTools.pm 749762
lib/Sereal/Decoder/Constants.pm 749748
lib/Sereal/Decoder.pm 11
ptable.h 7883
srl_common.h 11
srl_decoder.c 262383
srl_decoder.h 16867
srl_error.h 028
srl_protocol.h 5454
srl_taginfo.h 0369
t/lib/Sereal/TestSet.pm 926
typemap 14
23 files changed (This is a version diff) 23113272
@@ -1,8 +1,20 @@
 Revision history for Perl extension Sereal-Decoder
 
-* Warning: For a seamless upgrade, upgrade to version 3
-*          of the decoder before upgrading to version 3 of the
-*          encoder!
+****************************************************************
+* Warning: For a seamless upgrade, upgrade to version 3        *
+*          of the decoder before upgrading to version 3 of the *
+*          encoder!                                            *
+****************************************************************
+
+3.005 Jan 05 2015
+  * Build improvements related to char signedness being platform
+    dependent.
+
+3.004 Dec 27 2014
+  * Performance optimizations and other miscellaneous changes.
+  * Build improvements.
+  * Win32 fixes for weakrefs.
+
 3.003 Oct 19 2014
   * Niko Tyni fixed the 64-bit big endian Sereal bug! (Yay Niko!)
   * Sereal::Decoder::Constants will now have a defined $VERSION
@@ -11,10 +11,10 @@
 #include "srl_common.h"
 #include "srl_decoder.h"
 #include "srl_protocol.h"
-
 /* Generated code for exposing C constants to Perl */
 #include "const-c.inc"
 
+
 #ifndef GvCV_set
 # define GvCV_set(gv, cv) (GvCV(gv) = (cv))
 #endif
@@ -279,6 +279,13 @@ THX_xsfunc_looks_like_sereal(pTHX_ CV *cv)
     pp1_looks_like_sereal();
 }
 
+#define MY_CXT_KEY "Sereal::Decoder::_stash" XS_VERSION
+
+typedef struct {
+    sv_with_hash options[SRL_DEC_OPT_COUNT];
+} my_cxt_t;
+
+START_MY_CXT
 
 
 MODULE = Sereal::Decoder        PACKAGE = Sereal::Decoder
@@ -299,6 +306,22 @@ BOOT:
          /*012345678901234567890123*/
     }, *fti;
     int i;
+    {
+        MY_CXT_INIT;
+        SRL_INIT_OPTION( SRL_DEC_OPT_IDX_ALIAS_SMALLINT,             SRL_DEC_OPT_STR_ALIAS_SMALLINT             );
+        SRL_INIT_OPTION( SRL_DEC_OPT_IDX_ALIAS_VARINT_UNDER,         SRL_DEC_OPT_STR_ALIAS_VARINT_UNDER         );
+        SRL_INIT_OPTION( SRL_DEC_OPT_IDX_DESTRUCTIVE_INCREMENTAL,    SRL_DEC_OPT_STR_DESTRUCTIVE_INCREMENTAL    );
+        SRL_INIT_OPTION( SRL_DEC_OPT_IDX_MAX_NUM_HASH_ENTRIES,       SRL_DEC_OPT_STR_MAX_NUM_HASH_ENTRIES       );
+        SRL_INIT_OPTION( SRL_DEC_OPT_IDX_MAX_RECURSION_DEPTH,        SRL_DEC_OPT_STR_MAX_RECURSION_DEPTH        );
+        SRL_INIT_OPTION( SRL_DEC_OPT_IDX_NO_BLESS_OBJECTS,           SRL_DEC_OPT_STR_NO_BLESS_OBJECTS           );
+        SRL_INIT_OPTION( SRL_DEC_OPT_IDX_REFUSE_OBJECTS,             SRL_DEC_OPT_STR_REFUSE_OBJECTS             );
+        SRL_INIT_OPTION( SRL_DEC_OPT_IDX_REFUSE_SNAPPY,              SRL_DEC_OPT_STR_REFUSE_SNAPPY              );
+        SRL_INIT_OPTION( SRL_DEC_OPT_IDX_REFUSE_ZLIB,                SRL_DEC_OPT_STR_REFUSE_ZLIB                );
+        SRL_INIT_OPTION( SRL_DEC_OPT_IDX_SET_READONLY,               SRL_DEC_OPT_STR_SET_READONLY               );
+        SRL_INIT_OPTION( SRL_DEC_OPT_IDX_SET_READONLY_SCALARS,       SRL_DEC_OPT_STR_SET_READONLY_SCALARS       );
+        SRL_INIT_OPTION( SRL_DEC_OPT_IDX_USE_UNDEF,                  SRL_DEC_OPT_STR_USE_UNDEF                  );
+        SRL_INIT_OPTION( SRL_DEC_OPT_IDX_VALIDATE_UTF8,              SRL_DEC_OPT_STR_VALIDATE_UTF8              );
+    }
 #if USE_CUSTOM_OPS
     {
         XOP *xop;
@@ -405,8 +428,10 @@ srl_decoder_t *
 new(CLASS, opt = NULL)
     char *CLASS;
     HV *opt;
+  PREINIT:
+    dMY_CXT;
   CODE:
-    RETVAL = srl_build_decoder_struct(aTHX_ opt);
+    RETVAL = srl_build_decoder_struct(aTHX_ opt, MY_CXT.options);
     RETVAL->flags |= SRL_F_REUSE_DECODER;
   OUTPUT: RETVAL
 
@@ -422,6 +447,7 @@ decode_sereal(src, opt = NULL, into = NULL)
     SV *opt;
     SV *into;
   PREINIT:
+    dMY_CXT;
     srl_decoder_t *dec= NULL;
   PPCODE:
     if (SvROK(src))
@@ -436,7 +462,7 @@ decode_sereal(src, opt = NULL, into = NULL)
         else
             croak("Options are neither undef nor hash reference");
     }
-    dec = srl_build_decoder_struct(aTHX_ (HV *)opt);
+    dec = srl_build_decoder_struct(aTHX_ (HV *)opt, MY_CXT.options);
     ST(0)= srl_decode_into(aTHX_ dec, src, into, 0);
     XSRETURN(1);
 
@@ -447,6 +473,7 @@ decode_sereal_with_header_data(src, opt = NULL, body_into = NULL, header_into =
     SV *body_into;
     SV *header_into;
   PREINIT:
+    dMY_CXT;
     srl_decoder_t *dec= NULL;
   CODE:
     /* Support no opt at all, undef, hashref */
@@ -459,7 +486,7 @@ decode_sereal_with_header_data(src, opt = NULL, body_into = NULL, header_into =
         else
             croak("Options are neither undef nor hash reference");
     }
-    dec = srl_build_decoder_struct(aTHX_ (HV *)opt);
+    dec = srl_build_decoder_struct(aTHX_ (HV *)opt, MY_CXT.options);
     if (body_into == NULL)
       body_into = sv_newmortal();
     if (header_into == NULL)
@@ -1,4 +1,5 @@
 author_tools/bench.pl
+author_tools/decode.pl
 author_tools/different_sereal_docs.sh
 author_tools/freeze_thaw_timing.pl
 author_tools/hobodecoder.pl
@@ -31,8 +32,10 @@ snappy/csnappy_internal_userspace.h
 srl_common.h
 srl_decoder.c
 srl_decoder.h
+srl_error.h
 srl_inline.h
 srl_protocol.h
+srl_taginfo.h
 t/001_load.t
 t/004_testset.t
 t/010_desperate.t
@@ -30,7 +30,7 @@
       },
       "configure" : {
          "requires" : {
-            "ExtUtils::MakeMaker" : "0"
+            "ExtUtils::MakeMaker" : "7.0"
          }
       },
       "runtime" : {
@@ -60,5 +60,5 @@
          "url" : "git://github.com/Sereal/Sereal.git"
       }
    },
-   "version" : "3.003"
+   "version" : "3.005"
 }
@@ -14,7 +14,7 @@ build_requires:
   Test::Warn: '0'
   XSLoader: '0'
 configure_requires:
-  ExtUtils::MakeMaker: '0'
+  ExtUtils::MakeMaker: '7.0'
 dynamic_config: 1
 generated_by: 'ExtUtils::MakeMaker version 6.98, CPAN::Meta::Converter version 2.142060'
 license: perl
@@ -32,4 +32,4 @@ requires:
 resources:
   bugtracker: https://github.com/Sereal/Sereal/issues
   repository: git://github.com/Sereal/Sereal.git
-version: '3.003'
+version: '3.005'
@@ -86,6 +86,9 @@ WriteMakefile1(
         'File::Path' => 0,
         'ExtUtils::ParseXS' => '2.21',
     },
+    CONFIGURE_REQUIRES => {
+        'ExtUtils::MakeMaker' => '7.0',
+    },
     NAME              => $module,
     VERSION_FROM      => 'lib/Sereal/Decoder.pm', # finds $VERSION
     PREREQ_PM         => {
@@ -105,7 +108,8 @@ WriteMakefile1(
 );
 $ENV{OPTIMIZE} = $OPTIMIZE;
 
-sub WriteMakefile1 {  #Written by Alexandr Ciornii, version 0.20. Added by eumm-upgrade.
+sub WriteMakefile1 {
+    #Original by Alexandr Ciornii, modified by Yves Orton
     my %params=@_;
     my $eumm_version=$ExtUtils::MakeMaker::VERSION;
     $eumm_version=eval $eumm_version;
@@ -120,7 +124,10 @@ sub WriteMakefile1 {  #Written by Alexandr Ciornii, version 0.20. Added by eumm-
         $params{PREREQ_PM}={ %{$params{PREREQ_PM} || {}} , %{$params{BUILD_REQUIRES}} };
         delete $params{BUILD_REQUIRES};
     }
-    delete $params{CONFIGURE_REQUIRES} if $eumm_version < 6.52;
+    if ($params{CONFIGURE_REQUIRES} and $eumm_version < 6.52) {
+        $params{PREREQ_PM}={ %{$params{PREREQ_PM} || {}}, %{$params{CONFIGURE_REQUIRES}} };
+        delete $params{CONFIGURE_REQUIRES};
+    }
     delete $params{MIN_PERL_VERSION} if $eumm_version < 6.48;
     delete $params{META_MERGE} if $eumm_version < 6.46;
     delete $params{META_ADD} if $eumm_version < 6.46;
@@ -129,5 +136,6 @@ sub WriteMakefile1 {  #Written by Alexandr Ciornii, version 0.20. Added by eumm-
     delete $params{ABSTRACT_FROM} if $] < 5.005;
     delete $params{BINARY_LOCATION} if $] < 5.005;
     delete $params{OPTIMIZE} if $^O eq 'MSWin32';
+
     WriteMakefile(%params);
 }
@@ -2,168 +2,263 @@ use strict;
 use warnings;
 use blib;
 use Benchmark qw(cmpthese :hireswallclock);
-use Sereal::Decoder qw(decode_sereal);
-use Sereal::Encoder qw(encode_sereal);
-use JSON::XS qw(decode_json encode_json);
+use Sereal::Decoder qw(decode_sereal sereal_decode_with_object);
+use Sereal::Encoder qw(encode_sereal sereal_encode_with_object);
 use Storable qw(nfreeze thaw);
-use Data::Undump qw(undump);
 use Data::Dumper qw(Dumper);
-use Data::Dumper::Limited qw(DumpLimited);
-use Data::MessagePack;
-use CBOR::XS qw(encode_cbor decode_cbor);
+
+
 use Getopt::Long qw(GetOptions);
+require bytes;
 
-my (
-    $duration,
-    $encoder,
-    $decoder,
-    $dump,
-    $tiny_data,
-    $small_data,
-    $medium_data,
-    $large_data,
-    $very_large_data,
-    $nobless,
-    $diagrams,
-    $diagram_output_dir,
-);
-BEGIN {
-    my $sereal_only = 0;
-    GetOptions(
-        'duration=f' => \($duration=-3),
-        'encoder'   => \$encoder,
-        'decoder'   => \$decoder,
-        'dump|d'    => \$dump,
-        'tiny'      => \$tiny_data,
-        'small'     => \$small_data,
-        'medium'    => \$medium_data,
-        'large'     => \$large_data,
-        'very_large|very-large|verylarge' => \$very_large_data,
-        'no_bless|no-bless|nobless'    => \$nobless,
-        'sereal_only|sereal-only|serealonly' => \$sereal_only,
-        'diagrams'  => \$diagrams,
-        'diagram_output=s' => \$diagram_output_dir,
-    );
-    eval "sub SEREAL_ONLY () { $sereal_only }";
-}
+GetOptions(
+    'secs|duration=f'                    => \( my $duration           = -5 ),
+    'encoder'                            => \( my $encoder            = 0 ),
+    'decoder'                            => \( my $decoder            = 0 ),
+    'dump|d'                             => \( my $dump               = 0 ),
+    'only=s@'                            => \( my $only               = undef ),
+    'exclude=s@'                         => \( my $exclude            = undef ),
+    'tiny'                               => \( my $tiny_data          = 0 ),
+    'small'                              => \( my $small_data         = 0 ),
+    'medium'                             => \( my $medium_data        = 0 ),
+    'large'                              => \( my $large_data         = 0 ),
+    'very_large|very-large|verylarge'    => \( my $very_large_data    = 0 ),
+    'no_bless|no-bless|nobless'          => \( my $nobless            = 0 ),
+    'sereal_only|sereal-only|serealonly' => \( my $sereal_only        = 0 ),
+    'diagrams'                           => \( my $diagrams           = 0 ),
+    'diagram_output=s'                   => \( my $diagram_output_dir = "" ),
+) or die "Bad option";
 
-my $fail = do {no warnings; $tiny_data + $small_data + $medium_data + $very_large_data + $large_data - 1};
-if ($fail and $fail > 0) {
+my $fail =
+  $tiny_data + $small_data + $medium_data + $very_large_data + $large_data - 1;
+if ( $fail and $fail > 0 ) {
     die "Only one of --tiny, --small, --medium, --large, --very-large allowed!";
 }
 $encoder = 1 if not $encoder and not $decoder;
 
-our %opt = @ARGV;
-
-our $mpo = Data::MessagePack->new();
+#our %opt = @ARGV;
+our %opt;
 
 my $data_set_name;
 srand(0);
-my $chars = join("", "a".."z", "A".."Z") x 2;
+my $chars = join( "", "a" .. "z", "A" .. "Z" ) x 2;
 my @str;
-push @str, substr($chars, int(rand(int(length($chars)/2+1))), 10) for 1..1000;
-my @rand = map rand, 1..1000;
-our %data;
+push @str, substr( $chars, int( rand( int( length($chars) / 2 + 1 ) ) ), 10 )
+  for 1 .. 1000;
+my @rand = map rand, 1 .. 1000;
 
-$data{$_}= make_data() for qw(sereal sereal_func dd1 dd2 ddl mp json_xs storable sereal_snappy sereal_zlib_fast sereal_zlib_small cbor);
+our (
+    $enc, $dec,
+    $enc_snappy,        $dec_snappy,
+    $enc_zlib_fast,     $dec_zlib_fast,
+    $enc_zlib_small,    $dec_zlib_small,
+    $jsonxs, $msgpack, $dd_noindent, $dd_indent, $cbor
+);
+my $storable_tag= "strbl";
+my $sereal_tag= "srl";
+my %meta = (
+    jxs => {
+        enc  => '$::jsonxs->encode($data);',
+        dec  => '$::jsonxs->decode($encoded);',
+        name => 'JSON::XS OO',
+        init => sub {
+            $jsonxs = JSON::XS->new()->allow_nonref();
+        },
+        use => 'use JSON::XS qw(decode_json encode_json);',
+    },
+    ddl => {
+        enc  => 'DumpLimited($data);',
+        dec  => 'Data::Undump::undump($encoded);',
+        name => 'Data::Dump::Limited',
+        use  => [
+                    'use Data::Undump qw(undump);',
+                    'use Data::Dumper::Limited qw(DumpLimited);',
+                ],
+    },
+    mp => {
+        enc  => '$::msgpack->pack($data);',
+        dec  => '$::msgpack->unpack($encoded);',
+        name => 'Data::MsgPack',
+        use  => 'use Data::MessagePack;',
+        init => sub {
+            $msgpack = Data::MessagePack->new();
+        },
+    },
+    cbor => {
+        enc  => '$::cbor->encode($data);',
+        dec  => '$::cbor->decode($encoded);',
+        name => 'CBOR::XS',
+        use => 'use CBOR::XS qw(encode_cbor decode_cbor);',
+        init => sub {
+            $cbor= CBOR::XS->new();
+        },
+    },
+    dd_noind => {
+        enc  => 'Data::Dumper->new([$data])->Indent(0)->Dump();',
+        dec  => 'eval $encoded;',
+        name => 'Data::Dumper no-indent',
+    },
+    dd => {
+        enc  => 'Dumper($data);',
+        dec  => 'eval $encoded;',
+        name => 'Data::Dumper indented',
+    },
+    $storable_tag => {
+        enc  => 'nfreeze($data);',
+        dec  => 'thaw($encoded);',
+        name => 'Storable',
+    },
+    srl_func => {
+        enc  => 'encode_sereal($data, $opt);',
+        dec  => 'decode_sereal($encoded, $opt);',
+        name => 'Sereal functional',
+    },
+    srl_fwo => {
+        enc  => 'sereal_encode_with_object($::enc,$data);',
+        dec  => 'sereal_decode_with_object($::dec,$encoded);',
+        name => 'Sereal functional with object',
+    },
+    $sereal_tag => {
+        enc  => '$::enc->encode($data);',
+        dec  => '$::dec->decode($encoded);',
+        name => 'Sereal OO',
+        init => sub {
+            $enc = Sereal::Encoder->new( %opt ? \%opt : () );
+            $dec = Sereal::Decoder->new( \%opt ? \%opt : () );
+        },
+    },
+    srl_snpy => {
+        enc  => '$::enc_snappy->encode($data);',
+        dec  => '$::dec_snappy->decode($encoded);',
+        name => 'Sereal OO snappy',
+        init => sub {
+            $enc_snappy = Sereal::Encoder->new(
+                {
+                    %opt,
+                    compress => Sereal::Encoder::SRL_SNAPPY
+                }
+            );
+            $dec_snappy = Sereal::Decoder->new( %opt ? \%opt : () );
+        },
+    },
+    srl_zfast => {
+        enc  => '$::enc_zlib_fast->encode($data);',
+        dec  => '$::dec_zlib_fast->decode($encoded);',
+        name => 'Sereal OO zlib fast',
+        init => sub {
+            $enc_zlib_fast = Sereal::Encoder->new(
+                {
+                    %opt,
+                    compress           => Sereal::Encoder::SRL_ZLIB,
+                    compress_level     => 1,
+                    compress_threshold => 0,
+                }
+            );
+            $dec_zlib_fast = Sereal::Decoder->new( %opt ? \%opt : () );
+        },
+    },
+    srl_zbest => {
+        enc  => '$::enc_zlib_small->encode($data);',
+        dec  => '$::dec_zlib_small->decode($encoded);',
+        name => 'Sereal OO zib best',
+        init => sub {
+            $enc_zlib_small = Sereal::Encoder->new(
+                {
+                    %opt,
+                    compress           => Sereal::Encoder::SRL_ZLIB,
+                    compress_level     => 10,
+                    compress_threshold => 0,
+                }
+            );
+            $dec_zlib_small = Sereal::Decoder->new( %opt ? \%opt : () );
+        },
+    },
+);
+if ($only) {
+    my @pat= map { split /\s*,\s*/, $_ } @$only;
+    $only = {};
+    foreach my $key (keys %meta) {
+        $key=~/$_/ and $only->{$key}= 1
+            for @pat;
+    }
+    die "Only [@pat] produced no matches!" unless keys %$only;
+}
+if ($exclude) {
+    my @pat= map { split /\s*,\s*/, $_ } @$exclude;
+    $exclude = {};
+    foreach my $key (keys %meta) {
+        $key=~/$_/ and $exclude->{$key}= 1
+            for @pat;
+    }
+    die "Exclude [@pat] produced no matches!" unless keys %$exclude;
+}
 
-our $enc = Sereal::Encoder->new(\%opt);
-our $enc_snappy = Sereal::Encoder->new({%opt, compress => Sereal::Encoder::SRL_SNAPPY});
-our $enc_zlib_fast = Sereal::Encoder->new({%opt, compress => Sereal::Encoder::SRL_ZLIB, compress_level => 1, compress_threshold => 0});
-our $enc_zlib_small = Sereal::Encoder->new({%opt, compress => Sereal::Encoder::SRL_ZLIB, compress_level => 10, compress_threshold => 0});
-our $dec = Sereal::Decoder->new(\%opt);
+our %data;
+our %encoded;
+our %decoded;
+our %enc_bench;
+our %dec_bench;
+foreach my $key ( sort keys %meta ) {
+    my $info = $meta{$key};
+    $info->{tag}= $key;
+    next if $only    and not $only->{$key}    and $key ne $storable_tag;
+    next if $exclude and     $exclude->{$key} and $key ne $storable_tag;
+    if (my $use= $info->{use}) {
+        $use= [$use] unless ref $use;
+        $use= join ";\n", @$use, 1;
+        unless (eval $use) {
+            warn "Can't load dependencies for $info->{name}, skipping\n";
+            next;
+        }
+    }
+    $info->{enc}=~s/\$data/\$::data{$key}/g;
+    $info->{dec}=~s/\$encoded/\$::encoded{$key}/g;
+    $info->{enc}=~s/\$opt/%opt ? "\\%::opt" : ""/ge;
+    $info->{dec}=~s/\$opt/%opt ? "\\%::opt" : ""/ge;
 
-our ($json_xs, $dd1, $dd2, $ddl, $sereal, $storable, $mp, $sereal_snappy, $sereal_zlib_fast, $sereal_zlib_small, $cbor);
-# do this first before any of the other dumpers "contaminate" the iv/pv issue
-$sereal            = $enc->encode($data{sereal});
-$sereal_snappy     = $enc_snappy->encode($data{sereal_snappy});
-$sereal_zlib_fast  = $enc_zlib_fast->encode($data{sereal_zlib_fast});
-$sereal_zlib_small = $enc_zlib_small->encode($data{sereal_zlib_small});
-if (!SEREAL_ONLY) {
-    $json_xs  = encode_json($data{json_xs}) if !$medium_data or $nobless;
-    $dd1      = Data::Dumper->new([$data{dd1}])->Indent(0)->Dump();
-    $dd2      = Dumper($data{dd2});
-    $ddl      = DumpLimited($data{ddl}) if !$medium_data or $nobless;
-    $mp       = $mpo->pack($data{mp}) if !$medium_data or $nobless;
-    $cbor     = encode_cbor($data{cbor}) if !$medium_data or $nobless;
-    $storable = nfreeze($data{storable});
+    $data{$key}    = make_data();
+    $info->{init}->() if $info->{init};
+    $encoded{$key} = eval $info->{enc}
+      or die "Failed to eval $info->{enc}: $@";
+    $decoded{$key} = eval '$::x = ' . $info->{dec} . '; 1'
+      or die "Failed to eval $info->{dec}: $@\n$encoded{$key}\n";
+    $info->{size}    = bytes::length( $encoded{$key} );
+    next if $only    and not $only->{$key};
+    next if $exclude and     $exclude->{$key};
+    $enc_bench{$key} = '$::x_' . $key . ' = ' . $info->{enc};
+    $dec_bench{$key} = '$::x_' . $key . ' = ' . $info->{dec};
 }
+
+my $sereal = $encoded{$sereal_tag};
 print($sereal), exit if $dump;
 
-my $sereal_len= bytes::length($sereal);
-require bytes;
-my @size_datasets;
-if (!SEREAL_ONLY) {
-    @size_datasets = (
-        (($medium_data && !$nobless) ? () : (
-            ["JSON::XS",  bytes::length($json_xs)],
-            ["Data::Dumper::Limited", bytes::length($ddl)],
-            ["Data::MessagePack", bytes::length($mp)],
-            ["CBOR",  bytes::length($cbor)],
-        )),
-        ["Data::Dumper (1)", bytes::length($dd1)],
-        ["Data::Dumper (2)", bytes::length($dd2)],
-        ["Storable", bytes::length($storable)],
-        ["Sereal::Encoder",  bytes::length($sereal)],
-        ["Sereal::Encoder, Snappy",  bytes::length($sereal_snappy)],
-        ["Sereal::Encoder, Zlib (fast)",  bytes::length($sereal_zlib_fast)],
-        ["Sereal::Encoder, Zlib (small)",  bytes::length($sereal_zlib_small)],
-    );
-    for my $tuple (@size_datasets) {
-        my ($name, $size) = @$tuple;
-        printf "%-40s %12d bytes %.2f%% of sereal\n", $name, $size, $size/$sereal_len *100;
+my $storable_len = bytes::length($encoded{$storable_tag});
+foreach my $info (
+    sort { $a->{size} <=> $b->{size} || $a->{name} cmp $b->{name} }
+    grep { defined $_->{size} }
+    values %meta
+) {
+    next unless $info->{size};
+    if ($info->{tag} eq $storable_tag) {
+        printf "%-40s %12d bytes\n",
+            $info->{name} . " ($info->{tag})", $info->{size};
+    } else {
+        printf "%-40s %12d bytes %6.2f%% of $storable_tag\n",
+            $info->{name} . " ($info->{tag})", $info->{size},
+            $info->{size} / $storable_len * 100;
     }
 }
 
 our $x;
-my ($encoder_result, $decoder_result);
+my ( $encoder_result, $decoder_result );
 if ($encoder) {
-    $encoder_result = cmpthese(
-        $duration,
-        {
-            (!SEREAL_ONLY
-                ? (
-                    ($medium_data && !$nobless ? () : (
-                        json_xs => '$::x = encode_json($::data{json_xs});',
-                        ddl => '$::x = DumpLimited($::data{ddl});',
-                        msgpack => '$::x = $::mpo->pack($::data{mp});',
-                        cbor => '$::x = encode_cbor($::data{cbor});',
-                    )),
-                    dd_noindent => '$::x = Data::Dumper->new([$::data{dd1}])->Indent(0)->Dump();',
-                    dd => '$::x = Dumper($::data{dd2});',
-                    storable => '$::x = nfreeze($::data{storable});',
-                ) : ()),
-            sereal_func => '$::x = encode_sereal($::data{sereal_func}, \%::opt);',
-            sereal => '$::x = $::enc->encode($::data{sereal});',
-            sereal_snappy => '$::x = $::enc_snappy->encode($::data{sereal_snappy});',
-            sereal_zlib_fast => '$::x = $::enc_zlib_fast->encode($::data{sereal_zlib_fast});',
-            sereal_zlib_small => '$::x = $::enc_zlib_small->encode($::data{sereal_zlib_small});',
-        }
-    );
+    print "\n* Timing encoders\n";
+    $encoder_result = cmpthese( $duration, \%enc_bench );
 }
 
 if ($decoder) {
-    $decoder_result = cmpthese(
-        $duration,
-        {
-            (!SEREAL_ONLY
-                ? (
-                    ($medium_data && !$nobless ? () : (
-                        json_xs => '$::x = decode_json($::json_xs);',
-                        undump_ddl => '$::x = Data::Undump::undump($::ddl);',
-                        msgpack => '$::x = $::mpo->unpack($::mp);',
-                        cbor => '$::x = decode_cbor($::cbor);',
-                    )),
-                    eval_dd => '$::x = eval $::dd1;',
-                    storable => '$::x = thaw($::storable);',
-                ) : ()),
-            sereal_func => '$::x = decode_sereal($::sereal, \%::opt);',
-            sereal => '$::x = $::dec->decode($::sereal);',
-            sereal_snappy => '$::x = $::dec->decode($::sereal_snappy);',
-            sereal_zlib_fast => '$::x = $::dec->decode($::sereal_zlib_fast);',
-            sereal_zlib_small => '$::x = $::dec->decode($::sereal_zlib_small);',
-        }
-    );
+    print "\n* Timing decoders\n";
+    $decoder_result = cmpthese( $duration, \%dec_bench );
 }
 
 sub make_data {
@@ -173,52 +268,116 @@ sub make_data {
     }
     elsif ($small_data) {
         $data_set_name = "small hash";
-        return { foo=> 1, bar => [100,101,102], str => "this is a \x{df} string which has to be serialized" };
+        return {
+            foo => 1,
+            bar => [ 100, 101, 102 ],
+            str => "this is a \x{df} string which has to be serialized"
+        };
     }
     elsif ($medium_data) {
         my @obj = (
-            { foo => 1, bar => [100,101,102], str => "this is a \x{df} string which has to be serialized" },
-            { foo => 2, bar => [103,103,106,999], str2 => "this is a \x{df} aaaaaastring which has to be serialized" },
-            { foozle => 3, bar => [100], str3 => "this is a \x{df} string which haaaaadsadas to be serialized" },
-            { foozle => 3, bar => [], st4r => "this is a \x{df} string which has to be sdassdaerialized" },
-            { foo => 1, bar => [100,101,102], s5tr => "this is a \x{df} string which has to be serialized" },
-            { foo => 2, bar => [103,103,106,999], str => "this is a \x{df} aaaaaastring which has to be serialized" },
-            { foozle => 3, bar => [100], str => "this is a \x{df} string which haaaaadsadas to be serialized" },
-            { foozle => 3, bar => [], str2 => "this is a \x{df} string which has to be sdassdaerialized" },
-            { foo2 => -99999, bar => [100,101,102], str2 => "this is a \x{df} string which has to be serialized" },
-            { foo2 => 213, bar => [103,103,106,999], str => "this is a \x{df} aaaaaastring which has to be serialized" },
-            { foozle2 => undef, bar => [100], str => "this is a \x{df} string which haaaaadsadas to be serialized" },
-            { foozle2 => undef, bar => [1..20], str => "this is a \x{df} string which has to be sdassdaerialized" },
+            {
+                foo => 1,
+                bar => [ 100, 101, 102 ],
+                str => "this is a \x{df} string which has to be serialized"
+            },
+            {
+                foo => 2,
+                bar => [ 103, 103, 106, 999 ],
+                str2 =>
+                  "this is a \x{df} aaaaaastring which has to be serialized"
+            },
+            {
+                foozle => 3,
+                bar    => [100],
+                str3 =>
+                  "this is a \x{df} string which haaaaadsadas to be serialized"
+            },
+            {
+                foozle => 3,
+                bar    => [],
+                st4r =>
+                  "this is a \x{df} string which has to be sdassdaerialized"
+            },
+            {
+                foo  => 1,
+                bar  => [ 100, 101, 102 ],
+                s5tr => "this is a \x{df} string which has to be serialized"
+            },
+            {
+                foo => 2,
+                bar => [ 103, 103, 106, 999 ],
+                str =>
+                  "this is a \x{df} aaaaaastring which has to be serialized"
+            },
+            {
+                foozle => 3,
+                bar    => [100],
+                str =>
+                  "this is a \x{df} string which haaaaadsadas to be serialized"
+            },
+            {
+                foozle => 3,
+                bar    => [],
+                str2 =>
+                  "this is a \x{df} string which has to be sdassdaerialized"
+            },
+            {
+                foo2 => -99999,
+                bar  => [ 100, 101, 102 ],
+                str2 => "this is a \x{df} string which has to be serialized"
+            },
+            {
+                foo2 => 213,
+                bar  => [ 103, 103, 106, 999 ],
+                str =>
+                  "this is a \x{df} aaaaaastring which has to be serialized"
+            },
+            {
+                foozle2 => undef,
+                bar     => [100],
+                str =>
+                  "this is a \x{df} string which haaaaadsadas to be serialized"
+            },
+            {
+                foozle2 => undef,
+                bar     => [ 1 .. 20 ],
+                str =>
+                  "this is a \x{df} string which has to be sdassdaerialized"
+            },
         );
         my @classes = qw(Baz Baz Baz3 Baz2 Baz Baz Baz3 Baz2 Baz Baz Baz3 Baz2);
-        if (!$nobless) {
-            bless($obj[$_], $classes[$_]) for 0..$#obj;
-            $data_set_name = "array of small objects with relations";
+        if ( $nobless ) {
+            $data_set_name = "array of small hashes with relations";
         }
         else {
-            $data_set_name = "array of small hashes with relations";
+            bless( $obj[$_], $classes[$_] ) for 0 .. $#obj;
+            $data_set_name = "array of small objects with relations";
         }
-        foreach my $i (1..$#obj) {
-            $obj[$i]->{parent} = $obj[$i-1];
+        foreach my $i ( 1 .. $#obj ) {
+            $obj[$i]->{parent} = $obj[ $i - 1 ];
         }
         return \@obj;
     }
-    elsif ($very_large_data) { # "large data"
+    elsif ($very_large_data) {    # "large data"
         $data_set_name = "really rather large data structure";
         my @refs = (
-            [1..10000], {@str}, {@str}, [1..10000],
+            [ 1 .. 10000 ],
+            {@str}, {@str}, [ 1 .. 10000 ],
             {@str}, [@rand], {@str}, {@str},
         );
         return [
-            \@refs, \@refs, [map {[reverse 1..100]} (0..1000)], [map {+{foo => "bar", baz => "buz"}} 1..2000]
-        ]
+            \@refs, \@refs,
+            [ map { [ reverse 1 .. 100 ] } ( 0 .. 1000 ) ],
+            [ map { +{ foo => "bar", baz => "buz" } } 1 .. 2000 ]
+        ];
     }
-    else { # "large data"
+    else {    # "large data"
         $data_set_name = "large data structure";
         return [
-            [1..10000], {@str}, {@str}, [1..10000],
+            [ 1 .. 10000 ], {@str}, {@str}, [ 1 .. 10000 ],
             {@str}, [@rand], {@str}, {@str},
-        ]
+        ];
     }
 }
 
@@ -227,49 +386,52 @@ if ($diagrams) {
     SOOT::Init(0);
     SOOT->import(":all");
 
-    my ($enc_data, $dec_data);
+    my ( $enc_data, $dec_data );
     $enc_data = cmpthese_to_sanity($encoder_result) if $encoder_result;
     $dec_data = cmpthese_to_sanity($decoder_result) if $decoder_result;
 
-    foreach my $dia (["Encoder performance [1/s]", $enc_data],
-                     ["Decoder performance [1/s]", $dec_data],)
+    foreach my $dia (
+        [ "Encoder performance [1/s]", $enc_data ],
+        [ "Decoder performance [1/s]", $dec_data ],
+      )
     {
-        my ($title, $d) = @$dia;
+        my ( $title, $d ) = @$dia;
         next if not $d;
         $_->[0] =~ s/_/ /g, $_->[0] =~ s/sereal /sereal, / for @$d;
         make_bar_chart(
-            substr($title, 0, 3),
+            substr( $title, 0, 3 ),
             $d,
             {
-                title => $title,
+                title    => $title,
                 filename => do {
                     my $x = $title;
                     $x =~ s/\[1\/s\]/per second/;
-                    $data_set_name . " - " . $x
+                    $data_set_name . " - " . $x;
                 },
             }
         );
     }
 
     my %names = (
-        "JSON::XS" => 'json xs',
-        "Data::Dumper::Limited" => 'ddl',
-        "Data::MessagePack" => "msgpack",
-        "Data::Dumper (1)" => "dd noindent",
-        "Data::Dumper (2)" => "dd",
-        "Storable" => 'storable',
-        "Sereal::Encoder" => 'sereal',
+        "JSON::XS"                => 'json xs',
+        "Data::Dumper::Limited"   => 'ddl',
+        "Data::MessagePack"       => "msgpack",
+        "Data::Dumper (1)"        => "dd noindent",
+        "Data::Dumper (2)"        => "dd",
+        "Storable"                => 'storable',
+        "Sereal::Encoder"         => 'sereal',
         "Sereal::Encoder, Snappy" => 'sereal, snappy',
     );
 
     make_bar_chart(
         "size",
         [
-            sort {$b->[1] <=> $a->[1]} map [ $names{$_->[0]}||die, $_->[1] ], @size_datasets
+            sort { $b->[1] <=> $a->[1] }
+            map { $_->{size} ? [ $_->{name}, $_->{size} ] : () } values %meta
         ],
         {
-            title => "Encoded output sizes [bytes]",
-            color => kRed(),
+            title    => "Encoded output sizes [bytes]",
+            color    => kRed(),
             filename => $data_set_name . " - Encoded output sizes in bytes",
         },
     );
@@ -277,21 +439,23 @@ if ($diagrams) {
 }
 
 sub make_bar_chart {
-    my ($name, $data, $opts) = @_;
-    my $h = TH1D->new($name, ($opts->{title}||$name), scalar(@$data), -0.5, scalar(@$data)-0.5);
+    my ( $name, $data, $opts ) = @_;
+    my $h = TH1D->new( $name, ( $opts->{title} || $name ),
+        scalar(@$data), -0.5, scalar(@$data) - 0.5 );
     $h->keep;
-    $h->SetFillColor($opts->{color} || kBlue());
+    $h->SetFillColor( $opts->{color} || kBlue() );
     $h->SetBarOffset(0.12);
     $h->SetBarWidth(0.74);
     $h->SetStats(0);
     $h->GetXaxis()->SetLabelSize(0.06);
     $h->GetXaxis()->SetLabelOffset(0.009);
-    $h->GetYaxis()->SetTitle($opts->{title}) if defined $opts->{title};
+    $h->GetYaxis()->SetTitle( $opts->{title} ) if defined $opts->{title};
     $h->GetYaxis()->SetTitleSize(0.045);
-    for my $i (1..@$data) {
-        my ($label, $rate) = @{ $data->[$i-1] };
-        $h->GetXaxis()->SetBinLabel($i, $label);
-        $h->SetBinContent($i, 0+$rate);
+
+    for my $i ( 1 .. @$data ) {
+        my ( $label, $rate ) = @{ $data->[ $i - 1 ] };
+        $h->GetXaxis()->SetBinLabel( $i, $label );
+        $h->SetBinContent( $i, 0 + $rate );
     }
     my $c = TCanvas->new->keep;
     $c->GetPad(0)->SetBottomMargin(0.175);
@@ -302,20 +466,21 @@ sub make_bar_chart {
     if ($diagram_output_dir) {
         require File::Path;
         File::Path::mkpath($diagram_output_dir);
-        my $file = $opts->{filename} || do {my $f = $opts->{title}; $f =~ s/[^a-zA-Z0-9_\ ]/_/g; $f};
+        my $file = $opts->{filename}
+          || do { my $f = $opts->{title}; $f =~ s/[^a-zA-Z0-9_\ ]/_/g; $f };
         $c->SaveAs("$diagram_output_dir/$file.png");
     }
 }
 
 sub cmpthese_to_sanity {
-    my $res = shift;
+    my $res  = shift;
     my @rows = map {
         my $rate = $_->[1];
-        if (not $rate =~ s/\s*\/\s*s$//) {
-            $rate = 1/$rate;
+        if ( not $rate =~ s/\s*\/\s*s$// ) {
+            $rate = 1 / $rate;
         }
-        [$_->[0], $rate]
-    } grep {defined $_->[0] and $_->[0] =~ /\S/} @$res;
+        [ $_->[0], $rate ]
+    } grep { defined $_->[0] and $_->[0] =~ /\S/ } @$res;
     return \@rows;
 }
-
+print "\n";
@@ -0,0 +1,249 @@
+#!/usr/bin/perl -w
+
+# This script is for testing Sereal decode speeds, with various
+# generated test inputs (which are first encoded).  Sample usages:
+#
+# decode.pl --build --output=data.srl
+#
+# will (1) build a "graph" (a hash of small strings, really,
+# which can be seen as an adjacency list representation of
+# a graph, the vertex and its neighbors) of 1e5 vertices
+# (2) decode the encoded blob 5 times (the 'graph', 1e5, and 5
+# being the defaults).
+#
+# Other inputs types (--type=T) are
+# aoi (array of int) (value == key)
+# aof (array of float) (rand())
+# aos (array of string) (value eq key)
+# hoi (hash of int)
+# hof (hash of float)
+# hos (hash of string)
+#
+# The 'base' number of elements in each case is controlled by --elem=N.
+# For the array and hash the number of elements is trivial, for the graph
+# the total number of elements (in its hash-of-hashes) is O(N log N).
+#
+# The number decode repeats is controlled by --repeat=N.
+#
+# The encode input needs to be built only once, the --output tells
+# where to save the encoded blob.  The encode blob can be read back
+# from the save file with --input, much faster, especially in the case
+# of the graph input.
+
+use strict;
+
+use Time::HiRes qw[time];
+use Sereal::Encoder;
+use Sereal::Decoder;
+use Getopt::Long;
+use Devel::Size qw[total_size];
+use Fcntl qw[O_RDONLY O_WRONLY O_CREAT O_TRUNC];
+
+sub MB () { 2 ** 20 }
+
+my %Opt;
+my @Opt = ('input=s', 'output=s', 'type=s', 'elem=f', 'build', 'repeat=i', 'size');
+my %OptO = map { my ($n) = /^(\w+)/; $_ => \$Opt{$n} } @Opt;
+my @OptU = map { "--$_" } @Opt;
+
+GetOptions(%OptO) or die "GetOptions: @OptU\n";
+
+my $data;
+my $blob;
+my $size;
+my $data_size;
+my $blob_size;
+my $dt;
+
+if (defined $Opt{build}) {
+    die "$0: --input with --build makes no sense\n" if defined $Opt{input};
+    $Opt{elem} //= 1e5;
+} else {
+    die "$0: --output without --build makes no sense\n" if defined $Opt{output};
+    die "$0: --elem without --build makes no sense\n" if defined $Opt{elem};
+    die "$0: Must specify either --build or --input\n" unless defined $Opt{input};
+}
+if (defined ($Opt{output})) {
+    die "$0: --input with --output makes no sense\n" if defined $Opt{input};
+}
+
+$Opt{type} //= 'graph';
+$Opt{repeat} //= 5;
+
+my %TYPE = map { $_ => 1 } qw[aoi aof aos hoi hof graph];
+
+die "$0: Unexpected --repeat=$Opt{repeat}\n" if $Opt{repeat} < 1;
+die "$0: Unexpected --type=$Opt{type}\n$0: Expected --type=@{[join('|', sort keys %TYPE)]}\n"
+    unless exists $TYPE{$Opt{type}};
+
+sub timeit {
+    my $code = shift;
+    my $t0 = time();
+    my @res = $code->(@_);
+    my $dt = time() - $t0;
+    return $dt;
+}
+
+if (defined $Opt{build}) {
+    print "building data\n";
+    if ($Opt{type} eq 'graph') {
+	print "building graph\n";
+	my $V = $Opt{elem};
+	my $E = int($V * log($V)/log(2));
+	printf("data of %d (%.1fM) vertices %d (%.1fM) edges\n",
+	       $V, $V / MB, $E, $E / MB);
+	$dt = timeit(
+	    sub {
+		for my $i (1..$E) {
+		    my $a = int(rand($V));
+		    my $b = int(rand($V));
+		    $data->{$a}{$b}++;
+		}
+	    });
+	printf("build %.3f sec (%.1f edges/sec)\n", $dt, $E / $dt);
+    } elsif ($Opt{type} eq 'aoi') {
+	print "building aoi\n";
+	my $E = $Opt{elem};
+	$dt = timeit(
+	    sub {
+		for my $i (1..$E) {
+		    push @$data, $i;
+		}
+	    });
+	printf("build %.3f sec (%.1f elements/sec)\n", $dt, $E / $dt);
+    } elsif ($Opt{type} eq 'aof') {
+	print "building aof\n";
+	my $E = $Opt{elem};
+	$dt = timeit(
+	    sub {
+		for my $i (1..$E) {
+		    push @$data, rand();
+		}
+	    });
+	printf("build %.3f sec (%.1f elements/sec)\n", $dt, $E / $dt);
+    } elsif ($Opt{type} eq 'aos') {
+	print "building aos\n";
+	my $E = $Opt{elem};
+	$dt = timeit(
+	    sub {
+		for my $i (1..$E) {
+		    push @$data, rand() . $$;
+		}
+	    });
+	printf("build %.3f sec (%.1f elements/sec)\n", $dt, $E / $dt);
+    } elsif ($Opt{type} eq 'hoi') {
+	print "building hoi\n";
+	my $E = $Opt{elem};
+	$dt = timeit(
+	    sub {
+		for my $i (1..$E) {
+		    $data->{$i} = "$i";
+		}
+	    });
+	printf("build %.3f sec (%.1f elements/sec)\n", $dt, $E / $dt);
+    } elsif ($Opt{type} eq 'hof') {
+	print "building hof\n";
+	my $E = $Opt{elem};
+	$dt = timeit(
+	    sub {
+		for my $i (1..$E) {
+		    $data->{$i} = rand();
+		}
+	    });
+	printf("build %.3f sec (%.1f elements/sec)\n", $dt, $E / $dt);
+    } elsif ($Opt{type} eq 'hos') {
+	print "building hos\n";
+	my $E = $Opt{elem};
+	$dt = timeit(
+	    sub {
+		for my $i (1..$E) {
+		    $data->{$i} = "$i";
+		}
+	    });
+	printf("build %.3f sec (%.1f elements/sec)\n", $dt, $E / $dt);
+    } else {
+	die "$0: Unexpected type '$Opt{type}'\n";
+    }
+    if ($Opt{size}) {
+	$dt = timeit(sub { $data_size = total_size($data);});
+	printf("data size %d bytes (%.1fMB) %.1f sec\n",
+	       $data_size, $data_size / MB, $dt);
+    }
+
+    my $encoder = Sereal::Encoder->new;
+
+    {
+	print "encoding data\n";
+	$dt = timeit(
+	    sub {
+		$blob = $encoder->encode($data);
+	    });
+	$blob_size = length($blob);
+	printf("encode to %d bytes (%.1fMB) %.3f sec (%.1f MB/sec)\n",
+	       $blob_size, $blob_size / MB, $dt, $blob_size / (MB * $dt));
+    }
+
+    if (defined $Opt{output}) {
+	print "opening output\n";
+	my $fh;
+	sysopen($fh, $Opt{output}, O_WRONLY|O_CREAT|O_TRUNC)
+	    or die qq[sysopen "$Opt{output}": $!\n];
+	print "writing blob\n";
+	$dt = timeit(
+	    sub {
+		syswrite($fh, $blob)
+		    or die qq[syswrite "$Opt{otput}": $!\n] });
+	$blob_size = length($blob);
+	printf("wrote %d bytes (%.1f MB) %.3f sec (%.1f MB/sec)\n",
+	       $blob_size, $blob_size / MB, $dt, $blob_size / (MB * $dt));
+    }
+} elsif (defined $Opt{input}) {
+    print "opening input\n";
+    my $fh;
+    sysopen($fh, $Opt{input}, O_RDONLY) or die qq[sysopen "$Opt{input}": $!\n];
+    print "reading blob\n";
+    $dt = timeit(
+	sub {
+	    sysread($fh, $blob, -s $fh)
+		or die qq[sysread "$Opt{input}": $!\n];
+	});
+    $blob_size = length($blob);
+    printf("read %d bytes (%.1f MB) %.3f sec (%.1f MB/sec)\n",
+	   $blob_size, $blob_size / MB, $dt, $blob_size / (MB * $dt));
+}
+
+my $decoder = Sereal::Decoder->new;
+
+{
+    print "decoding blob\n";
+    my @dt;
+    $blob_size = length($blob);
+    for my $i (1..$Opt{repeat}) {
+	$dt = timeit(sub { $data = $decoder->decode($blob); });
+	printf("%d/%d: decode from %d bytes (%.1fM) %.3f sec (%.f MB/sec)\n",
+	       $i, $Opt{repeat}, $blob_size, $blob_size / MB,
+	       $dt, $blob_size / (MB * $dt));
+	push @dt, $dt;
+    }
+    if (@dt) {
+	my $sum = 0;
+	for my $t (@dt) {
+	    $sum += $t;
+	}
+	my $avg = $sum / @dt;
+	my $sqsum = 0; 
+	for my $t (@dt) {
+	    $sqsum += ($avg - $t) ** 2;
+	}
+	my $stddev = sqrt($sqsum / @dt);
+	printf("decode avg %.2f sec (%.1f MB/sec) stddev %.2f sec (%.2f)\n",
+	       $avg, $blob_size / (MB * $avg), $stddev, $stddev / $avg); 
+    }
+    if ($Opt{size}) {
+	$dt = timeit(sub { $data_size = total_size($data); });
+	printf("data size %d bytes (%.1fMB) %.1f sec\n",
+	       $data_size, $data_size / MB, $dt);
+    }
+}
+
+exit(0);
@@ -6,18 +6,35 @@ use Data::Dumper;
 use Getopt::Long qw(GetOptions);
 our @constants;
 BEGIN {
-    my $err;
-    eval '
-        use Sereal::Encoder::Constants qw(:all);
-        @constants= @Sereal::Encoder::Constants::EXPORT_OK;
-        print "Loaded constants from $INC{q(Sereal/Encoder/Constants.pm)}\n";
-        1;
-    ' or do { $err= $@; eval '
-        use Sereal::Decoder::Constants qw(:all);
-        @constants= @Sereal::Decoder::Constants::EXPORT_OK;
-        print "Loaded constants from $INC{q(Sereal/Decoder/Constants.pm)}\n";
-        1;
-    ' } or die "No encoder/decoder constants: $err\n$@";
+    my $add_use_blib= "";
+    my $use= "";
+    my @check;
+    for my $type ("Decoder","Encoder") {
+        if (-e "blib/lib/Sereal/$type/Constants.pm") {
+            $add_use_blib="use blib;";
+            @check= ($type);
+            last;
+        }
+        push @check, $type;
+    }
+
+    my @err;
+    foreach my $check (@check) {
+        if (eval(my $code= sprintf '
+                %s
+                use Sereal::%s::Constants qw(:all);
+                @constants= @Sereal::%s::Constants::EXPORT_OK;
+                print "Loaded constants from $INC{q(Sereal/%s/Constants.pm)}\n";
+                1;
+            ', $add_use_blib, ($check) x 3))
+        {
+            @err= ();
+            last;
+        } else {
+            push @err, "Error:",$@ || "Zombie Error","\nCode:\n$code";
+        }
+    }
+    die @err if @err;
 }
 
 my $done;
@@ -246,9 +263,7 @@ sub parse_av {
   printf "(%u)\n", $len;
   $ind .= "  ";
   while ($len--) {
-    my $t = substr($data, 0, 1);
-    my $o = ord($t);
-      parse_sv($ind);
+    parse_sv($ind,\$len);
   }
 }
 
@@ -259,8 +274,6 @@ sub parse_hv {
   $ind .= "  ";
   my $flipflop = 0;
   while ($len--) {
-    my $t = substr($data, 0, 1);
-    my $o = ord($t);
     printf  "$fmt2%s:\n",("") x $lead_items, $ind, ($flipflop++ %2 == 1 ? "VALUE" : "KEY");
     parse_sv($ind."  ");
   }
@@ -288,12 +301,12 @@ sub varint {
   return $x;
 }
 
-BEGIN{
-my $_shift= length(pack"j",0) * 8 - 1;
-sub zigzag {
-    my $n= varint();
-    return ($n >> 1) ^ (-($n & 1));
+sub _zigzag {
+    my $n= $_[0];
+    return $n & 1 ? -(($n >> 1)+1) : ($n >> 1);
 }
+sub zigzag {
+    return _zigzag(varint());
 }
 
 GetOptions(
@@ -4,6 +4,7 @@ use warnings;
 use Data::Dumper;
 my (
     @meta,
+    %range,                     # base types.
     %name_to_value,             # just the names in the srl_protocol.h
     %name_to_value_expanded,    # names from srl_protocol, but with the LOW/HIGH data expanded
     %value_to_name_expanded,    # values from srl_protocol_expanded, mapping back, note value points at FIRST name
@@ -11,7 +12,7 @@ my (
 );
 my $max_name_length= 0;
 
-sub fill_ranges {
+sub fill_range {
     my $pfx= shift;
     $pfx=~s/_LOW//;
     defined(my $ofs= $name_to_value_expanded{$pfx})
@@ -27,6 +28,8 @@ sub fill_ranges {
         $meta[$value]{value}= $value;
         $meta[$value]{type_name}= $pfx;
         $meta[$value]{type_value}= $ofs;
+
+        push @{$range{$pfx}}, $meta[$value];
         #$meta[$value]{comment}= $value_to_comment_expanded{ $ofs }
         #    if exists $value_to_comment_expanded{ $ofs };
 
@@ -51,7 +54,7 @@ sub read_protocol {
             $value_to_comment_expanded{$value} ||= $comment;
             push @fill, $name if substr($name, -4) eq '_LOW';
 
-            if ( $value < 128 ) {
+            if ( $value < 128 && !($name=~/_LOW/ or $name=~/_HIGH/)) {
                 $meta[$value]{name}= $name;
                 $meta[$value]{value}= $value;
                 $meta[$value]{type_name}= $name;
@@ -61,7 +64,7 @@ sub read_protocol {
         }
     }
     close $fh;
-    fill_ranges($_) for @fill;
+    fill_range($_) for @fill;
     foreach my $pfx (keys %name_to_value_expanded) {
         $max_name_length= length($pfx) if $max_name_length < length($pfx);
     }
@@ -85,7 +88,10 @@ sub replace_block {
         print $out $_;
         last if /^=for autoupdater start/ || /^# start autoupdated section/;
     }
-    $blob=~s/\s+$//mg;
+
+    $blob =~ s/[ \t]+$//mg;
+    $blob =~ s/\s+\z//;
+
     print $out "\n$blob\n\n";
     while (<$in>) {
         if (/^=for autoupdater stop/ || /^# stop autoupdated section/) {
@@ -99,8 +105,9 @@ sub replace_block {
     close $out;
     close $in;
 }
+
 sub update_buildtools {
-    my $dump= Data::Dumper->new([\@meta],['*TAG_INFO_ARRAY'])->Indent(1)->Dump();
+    my $dump= Data::Dumper->new([\@meta],['*TAG_INFO_ARRAY'])->Sortkeys(1)->Useqq(1)->Indent(1)->Dump();
     $dump =~ s/^(\s*)\{/$1# autoupdated by $0 do not modify directly!\n$1\{/mg;
     return replace_block(
         "Perl/shared/inc/Sereal/BuildTools.pm",
@@ -111,11 +118,13 @@ sub update_buildtools {
             "push \@EXPORT_OK, qw(%TAG_INFO_HASH \@TAG_INFO_ARRAY);",
     )
 }
-sub update_srl_decoder_h {
-    replace_block("Perl/Decoder/srl_decoder.h",
+
+sub update_srl_taginfo_h {
+    replace_block("Perl/shared/srl_taginfo.h",
         join("\n",
             "* NOTE this section is autoupdated by $0",
             "*/",
+            "",
             "static const char * const tag_name[] = {",
             ( map {
                 my $str= Data::Dumper::qquote(chr($_));
@@ -124,16 +133,37 @@ sub update_srl_decoder_h {
                     $max_name_length+3, qq("$value_to_name_expanded{$_}") . ($_==127 ? " " : ","), $str, $_, $_, $_
             } 0 .. 127 ),
             "};",
+            "",
+            (
+                map {
+                    sprintf "#define SRL_HDR_%-*s %3d",
+                        $max_name_length+3, $_->{name}, $_->{value}
+                } grep { $_->{masked} } @meta
+            ),
+            "",
+            ( map {
+                my $n = $_;
+                my $v = $range{$n};
+                my $c =
+                        join "    \\\n   ",
+                        "#define CASE_SRL_HDR_$n",
+                        join ":    \\\n   ",
+                        map { "case SRL_HDR_$_->{name}" } @$v;
+
+                $c."\n\n";
+            } sort keys %range ),
+            "",
             "/*",
             "* NOTE the above section is auto-updated by $0",
         )
-    )
+    );
 }
 
+
 sub update_JavaSerealHeader {
     my $declarations = "* NOTE this section is autoupdated by $0 */\n";
 
-    for my $name (sort { $name_to_value{$a} <=> $name_to_value{$b} } keys %name_to_value) {
+    for my $name (sort { $name_to_value{$a} <=> $name_to_value{$b} || $a cmp $b } keys %name_to_value) {
         my $byte = $name_to_value{$name};
         my $decl = sprintf("static final byte SRL_HDR_%-*s = (byte) %3d;", $max_name_length, $name, $byte);
         $declarations .= sprintf("\t%s /* %3d 0x%02x 0b%08b %s */\n",
@@ -173,7 +203,7 @@ chdir "$git_dir/.."
     or die "Failed to chdir to root of repo '$git_dir/..': $!";
 read_protocol();
 update_buildtools();
-update_srl_decoder_h();
+update_srl_taginfo_h();
 update_table("sereal_spec.pod");
 update_table("Perl/shared/srl_protocol.h");
 update_JavaSerealHeader();
@@ -8,7 +8,7 @@ constant(sv)
 #endif
 	STRLEN		len;
         int		type;
-	IV		iv;
+	IV		iv = 0;
 	/* NV		nv;	Uncomment this if you need to return NVs */
 	/* const char	*pv;	Uncomment this if you need to return PVs */
     INPUT:
@@ -72,6 +72,20 @@ sub generate_constant_includes {
         NAME => $constant_namespace,
         NAMES => \@int_const,
     );
+    {
+        open my $ifh, "<", "const-xs.inc"
+            or die "Can't read const-xs.inc: $!";
+        open my $ofh, ">", "const-xs.new"
+            or die "Can't write const-xs.new: $!";
+        while (<$ifh>) {
+            s/(IV\s+)iv;/${1}iv = 0;/g;
+            print $ofh $_;
+        }
+        close $ofh;
+        close $ifh;
+        rename "const-xs.new","const-xs.inc"
+            or die "Can't rename const-xs.new => const-xs.inc: $!";
+    }
     open my $ofh, ">", $file or die $!;
     print $ofh <<HERE;
 # Genereated code! Do not modify! See inc/Sereal/BuildTools.pm instead
@@ -117,1138 +131,1137 @@ our (%TAG_INFO_HASH, @TAG_INFO_ARRAY);
 @TAG_INFO_ARRAY = (
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'comment' => 'small positive integer - value in low 4 bits (identity)',
-    'value' => 0,
-    'name' => 'POS_0',
-    'masked_val' => 0,
-    'type_value' => 0
+    "comment" => "small positive integer - value in low 4 bits (identity)",
+    "masked" => 1,
+    "masked_val" => 0,
+    "name" => "POS_0",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 0
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'value' => 1,
-    'name' => 'POS_1',
-    'masked_val' => 1,
-    'type_value' => 0
+    "masked" => 1,
+    "masked_val" => 1,
+    "name" => "POS_1",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 1
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'value' => 2,
-    'name' => 'POS_2',
-    'masked_val' => 2,
-    'type_value' => 0
+    "masked" => 1,
+    "masked_val" => 2,
+    "name" => "POS_2",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 2
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'value' => 3,
-    'name' => 'POS_3',
-    'masked_val' => 3,
-    'type_value' => 0
+    "masked" => 1,
+    "masked_val" => 3,
+    "name" => "POS_3",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 3
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'value' => 4,
-    'name' => 'POS_4',
-    'masked_val' => 4,
-    'type_value' => 0
+    "masked" => 1,
+    "masked_val" => 4,
+    "name" => "POS_4",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 4
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'value' => 5,
-    'name' => 'POS_5',
-    'masked_val' => 5,
-    'type_value' => 0
+    "masked" => 1,
+    "masked_val" => 5,
+    "name" => "POS_5",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 5
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'value' => 6,
-    'name' => 'POS_6',
-    'masked_val' => 6,
-    'type_value' => 0
+    "masked" => 1,
+    "masked_val" => 6,
+    "name" => "POS_6",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 6
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'value' => 7,
-    'name' => 'POS_7',
-    'masked_val' => 7,
-    'type_value' => 0
+    "masked" => 1,
+    "masked_val" => 7,
+    "name" => "POS_7",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 7
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'value' => 8,
-    'name' => 'POS_8',
-    'masked_val' => 8,
-    'type_value' => 0
+    "masked" => 1,
+    "masked_val" => 8,
+    "name" => "POS_8",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 8
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'value' => 9,
-    'name' => 'POS_9',
-    'masked_val' => 9,
-    'type_value' => 0
+    "masked" => 1,
+    "masked_val" => 9,
+    "name" => "POS_9",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 9
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'value' => 10,
-    'name' => 'POS_10',
-    'masked_val' => 10,
-    'type_value' => 0
+    "masked" => 1,
+    "masked_val" => 10,
+    "name" => "POS_10",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 10
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'value' => 11,
-    'name' => 'POS_11',
-    'masked_val' => 11,
-    'type_value' => 0
+    "masked" => 1,
+    "masked_val" => 11,
+    "name" => "POS_11",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 11
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'value' => 12,
-    'name' => 'POS_12',
-    'masked_val' => 12,
-    'type_value' => 0
+    "masked" => 1,
+    "masked_val" => 12,
+    "name" => "POS_12",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 12
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'value' => 13,
-    'name' => 'POS_13',
-    'masked_val' => 13,
-    'type_value' => 0
+    "masked" => 1,
+    "masked_val" => 13,
+    "name" => "POS_13",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 13
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'value' => 14,
-    'name' => 'POS_14',
-    'masked_val' => 14,
-    'type_value' => 0
+    "masked" => 1,
+    "masked_val" => 14,
+    "name" => "POS_14",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 14
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'comment' => 'small positive integer - value in low 4 bits (identity)',
-    'value' => 15,
-    'name' => 'POS_15',
-    'masked_val' => 15,
-    'type_value' => 0
+    "masked" => 1,
+    "masked_val" => 15,
+    "name" => "POS_15",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 15
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'comment' => 'small negative integer - value in low 4 bits (k+32)',
-    'value' => 16,
-    'name' => 'NEG_16',
-    'masked_val' => 16,
-    'type_value' => 16
+    "comment" => "small negative integer - value in low 4 bits (k+32)",
+    "masked" => 1,
+    "masked_val" => 16,
+    "name" => "NEG_16",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 16
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'value' => 17,
-    'name' => 'NEG_15',
-    'masked_val' => 15,
-    'type_value' => 16
+    "masked" => 1,
+    "masked_val" => 15,
+    "name" => "NEG_15",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 17
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'value' => 18,
-    'name' => 'NEG_14',
-    'masked_val' => 14,
-    'type_value' => 16
+    "masked" => 1,
+    "masked_val" => 14,
+    "name" => "NEG_14",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 18
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'value' => 19,
-    'name' => 'NEG_13',
-    'masked_val' => 13,
-    'type_value' => 16
+    "masked" => 1,
+    "masked_val" => 13,
+    "name" => "NEG_13",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 19
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'value' => 20,
-    'name' => 'NEG_12',
-    'masked_val' => 12,
-    'type_value' => 16
+    "masked" => 1,
+    "masked_val" => 12,
+    "name" => "NEG_12",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 20
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'value' => 21,
-    'name' => 'NEG_11',
-    'masked_val' => 11,
-    'type_value' => 16
+    "masked" => 1,
+    "masked_val" => 11,
+    "name" => "NEG_11",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 21
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'value' => 22,
-    'name' => 'NEG_10',
-    'masked_val' => 10,
-    'type_value' => 16
+    "masked" => 1,
+    "masked_val" => 10,
+    "name" => "NEG_10",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 22
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'value' => 23,
-    'name' => 'NEG_9',
-    'masked_val' => 9,
-    'type_value' => 16
+    "masked" => 1,
+    "masked_val" => 9,
+    "name" => "NEG_9",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 23
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'value' => 24,
-    'name' => 'NEG_8',
-    'masked_val' => 8,
-    'type_value' => 16
+    "masked" => 1,
+    "masked_val" => 8,
+    "name" => "NEG_8",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 24
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'value' => 25,
-    'name' => 'NEG_7',
-    'masked_val' => 7,
-    'type_value' => 16
+    "masked" => 1,
+    "masked_val" => 7,
+    "name" => "NEG_7",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 25
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'value' => 26,
-    'name' => 'NEG_6',
-    'masked_val' => 6,
-    'type_value' => 16
+    "masked" => 1,
+    "masked_val" => 6,
+    "name" => "NEG_6",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 26
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'value' => 27,
-    'name' => 'NEG_5',
-    'masked_val' => 5,
-    'type_value' => 16
+    "masked" => 1,
+    "masked_val" => 5,
+    "name" => "NEG_5",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 27
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'value' => 28,
-    'name' => 'NEG_4',
-    'masked_val' => 4,
-    'type_value' => 16
+    "masked" => 1,
+    "masked_val" => 4,
+    "name" => "NEG_4",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 28
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'value' => 29,
-    'name' => 'NEG_3',
-    'masked_val' => 3,
-    'type_value' => 16
+    "masked" => 1,
+    "masked_val" => 3,
+    "name" => "NEG_3",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 29
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'value' => 30,
-    'name' => 'NEG_2',
-    'masked_val' => 2,
-    'type_value' => 16
+    "masked" => 1,
+    "masked_val" => 2,
+    "name" => "NEG_2",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 30
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'comment' => 'small negative integer - value in low 4 bits (k+32)',
-    'value' => 31,
-    'name' => 'NEG_1',
-    'masked_val' => 1,
-    'type_value' => 16
+    "masked" => 1,
+    "masked_val" => 1,
+    "name" => "NEG_1",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 31
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'VARINT',
-    'comment' => '<VARINT> - Varint variable length integer',
-    'value' => 32,
-    'name' => 'VARINT',
-    'type_value' => 32
+    "comment" => "<VARINT> - Varint variable length integer",
+    "name" => "VARINT",
+    "type_name" => "VARINT",
+    "type_value" => 32,
+    "value" => 32
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ZIGZAG',
-    'comment' => '<ZIGZAG-VARINT> - Zigzag variable length integer',
-    'value' => 33,
-    'name' => 'ZIGZAG',
-    'type_value' => 33
+    "comment" => "<ZIGZAG-VARINT> - Zigzag variable length integer",
+    "name" => "ZIGZAG",
+    "type_name" => "ZIGZAG",
+    "type_value" => 33,
+    "value" => 33
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'FLOAT',
-    'comment' => '<IEEE-FLOAT>',
-    'value' => 34,
-    'name' => 'FLOAT',
-    'type_value' => 34
+    "comment" => "<IEEE-FLOAT>",
+    "name" => "FLOAT",
+    "type_name" => "FLOAT",
+    "type_value" => 34,
+    "value" => 34
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'DOUBLE',
-    'comment' => '<IEEE-DOUBLE>',
-    'value' => 35,
-    'name' => 'DOUBLE',
-    'type_value' => 35
+    "comment" => "<IEEE-DOUBLE>",
+    "name" => "DOUBLE",
+    "type_name" => "DOUBLE",
+    "type_value" => 35,
+    "value" => 35
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'LONG_DOUBLE',
-    'comment' => '<IEEE-LONG-DOUBLE>',
-    'value' => 36,
-    'name' => 'LONG_DOUBLE',
-    'type_value' => 36
+    "comment" => "<IEEE-LONG-DOUBLE>",
+    "name" => "LONG_DOUBLE",
+    "type_name" => "LONG_DOUBLE",
+    "type_value" => 36,
+    "value" => 36
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'UNDEF',
-    'comment' => 'None - Perl undef var; eg my $var= undef;',
-    'value' => 37,
-    'name' => 'UNDEF',
-    'type_value' => 37
+    "comment" => "None - Perl undef var; eg my \$var= undef;",
+    "name" => "UNDEF",
+    "type_name" => "UNDEF",
+    "type_value" => 37,
+    "value" => 37
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'BINARY',
-    'comment' => '<LEN-VARINT> <BYTES> - binary/(latin1) string',
-    'value' => 38,
-    'name' => 'BINARY',
-    'type_value' => 38
+    "comment" => "<LEN-VARINT> <BYTES> - binary/(latin1) string",
+    "name" => "BINARY",
+    "type_name" => "BINARY",
+    "type_value" => 38,
+    "value" => 38
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'STR_UTF8',
-    'comment' => '<LEN-VARINT> <UTF8> - utf8 string',
-    'value' => 39,
-    'name' => 'STR_UTF8',
-    'type_value' => 39
+    "comment" => "<LEN-VARINT> <UTF8> - utf8 string",
+    "name" => "STR_UTF8",
+    "type_name" => "STR_UTF8",
+    "type_value" => 39,
+    "value" => 39
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'REFN',
-    'comment' => '<ITEM-TAG>    - ref to next item',
-    'value' => 40,
-    'name' => 'REFN',
-    'type_value' => 40
+    "comment" => "<ITEM-TAG>    - ref to next item",
+    "name" => "REFN",
+    "type_name" => "REFN",
+    "type_value" => 40,
+    "value" => 40
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'REFP',
-    'comment' => '<OFFSET-VARINT> - ref to previous item stored at offset',
-    'value' => 41,
-    'name' => 'REFP',
-    'type_value' => 41
+    "comment" => "<OFFSET-VARINT> - ref to previous item stored at offset",
+    "name" => "REFP",
+    "type_name" => "REFP",
+    "type_value" => 41,
+    "value" => 41
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASH',
-    'comment' => '<COUNT-VARINT> [<KEY-TAG> <ITEM-TAG> ...] - count followed by key/value pairs',
-    'value' => 42,
-    'name' => 'HASH',
-    'type_value' => 42
+    "comment" => "<COUNT-VARINT> [<KEY-TAG> <ITEM-TAG> ...] - count followed by key/value pairs",
+    "name" => "HASH",
+    "type_name" => "HASH",
+    "type_value" => 42,
+    "value" => 42
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAY',
-    'comment' => '<COUNT-VARINT> [<ITEM-TAG> ...] - count followed by items',
-    'value' => 43,
-    'name' => 'ARRAY',
-    'type_value' => 43
+    "comment" => "<COUNT-VARINT> [<ITEM-TAG> ...] - count followed by items",
+    "name" => "ARRAY",
+    "type_name" => "ARRAY",
+    "type_value" => 43,
+    "value" => 43
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'OBJECT',
-    'comment' => '<STR-TAG> <ITEM-TAG> - class, object-item',
-    'value' => 44,
-    'name' => 'OBJECT',
-    'type_value' => 44
+    "comment" => "<STR-TAG> <ITEM-TAG> - class, object-item",
+    "name" => "OBJECT",
+    "type_name" => "OBJECT",
+    "type_value" => 44,
+    "value" => 44
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'OBJECTV',
-    'comment' => '<OFFSET-VARINT> <ITEM-TAG> - offset of previously used classname tag - object-item',
-    'value' => 45,
-    'name' => 'OBJECTV',
-    'type_value' => 45
+    "comment" => "<OFFSET-VARINT> <ITEM-TAG> - offset of previously used classname tag - object-item",
+    "name" => "OBJECTV",
+    "type_name" => "OBJECTV",
+    "type_value" => 45,
+    "value" => 45
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ALIAS',
-    'comment' => '<OFFSET-VARINT> - alias to item defined at offset',
-    'value' => 46,
-    'name' => 'ALIAS',
-    'type_value' => 46
+    "comment" => "<OFFSET-VARINT> - alias to item defined at offset",
+    "name" => "ALIAS",
+    "type_name" => "ALIAS",
+    "type_value" => 46,
+    "value" => 46
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'COPY',
-    'comment' => '<OFFSET-VARINT> - copy of item defined at offset',
-    'value' => 47,
-    'name' => 'COPY',
-    'type_value' => 47
+    "comment" => "<OFFSET-VARINT> - copy of item defined at offset",
+    "name" => "COPY",
+    "type_name" => "COPY",
+    "type_value" => 47,
+    "value" => 47
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'WEAKEN',
-    'comment' => '<REF-TAG> - Weaken the following reference',
-    'value' => 48,
-    'name' => 'WEAKEN',
-    'type_value' => 48
+    "comment" => "<REF-TAG> - Weaken the following reference",
+    "name" => "WEAKEN",
+    "type_name" => "WEAKEN",
+    "type_value" => 48,
+    "value" => 48
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'REGEXP',
-    'comment' => '<PATTERN-STR-TAG> <MODIFIERS-STR-TAG>',
-    'value' => 49,
-    'name' => 'REGEXP',
-    'type_value' => 49
+    "comment" => "<PATTERN-STR-TAG> <MODIFIERS-STR-TAG>",
+    "name" => "REGEXP",
+    "type_name" => "REGEXP",
+    "type_value" => 49,
+    "value" => 49
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'OBJECT_FREEZE',
-    'comment' => '<STR-TAG> <ITEM-TAG> - class, object-item. Need to call "THAW" method on class after decoding',
-    'value' => 50,
-    'name' => 'OBJECT_FREEZE',
-    'type_value' => 50
+    "comment" => "<STR-TAG> <ITEM-TAG> - class, object-item. Need to call \"THAW\" method on class after decoding",
+    "name" => "OBJECT_FREEZE",
+    "type_name" => "OBJECT_FREEZE",
+    "type_value" => 50,
+    "value" => 50
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'OBJECTV_FREEZE',
-    'comment' => '<OFFSET-VARINT> <ITEM-TAG> - (OBJECTV_FREEZE is to OBJECT_FREEZE as OBJECTV is to OBJECT)',
-    'value' => 51,
-    'name' => 'OBJECTV_FREEZE',
-    'type_value' => 51
+    "comment" => "<OFFSET-VARINT> <ITEM-TAG> - (OBJECTV_FREEZE is to OBJECT_FREEZE as OBJECTV is to OBJECT)",
+    "name" => "OBJECTV_FREEZE",
+    "type_name" => "OBJECTV_FREEZE",
+    "type_value" => 51,
+    "value" => 51
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'RESERVED',
-    'masked' => 1,
-    'comment' => 'reserved',
-    'value' => 52,
-    'name' => 'RESERVED_0',
-    'masked_val' => 0,
-    'type_value' => 52
+    "comment" => "reserved",
+    "masked" => 1,
+    "masked_val" => 0,
+    "name" => "RESERVED_0",
+    "type_name" => "RESERVED",
+    "type_value" => 52,
+    "value" => 52
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'RESERVED',
-    'masked' => 1,
-    'value' => 53,
-    'name' => 'RESERVED_1',
-    'masked_val' => 1,
-    'type_value' => 52
+    "masked" => 1,
+    "masked_val" => 1,
+    "name" => "RESERVED_1",
+    "type_name" => "RESERVED",
+    "type_value" => 52,
+    "value" => 53
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'RESERVED',
-    'masked' => 1,
-    'value' => 54,
-    'name' => 'RESERVED_2',
-    'masked_val' => 2,
-    'type_value' => 52
+    "masked" => 1,
+    "masked_val" => 2,
+    "name" => "RESERVED_2",
+    "type_name" => "RESERVED",
+    "type_value" => 52,
+    "value" => 54
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'RESERVED',
-    'masked' => 1,
-    'value' => 55,
-    'name' => 'RESERVED_3',
-    'masked_val' => 3,
-    'type_value' => 52
+    "masked" => 1,
+    "masked_val" => 3,
+    "name" => "RESERVED_3",
+    "type_name" => "RESERVED",
+    "type_value" => 52,
+    "value" => 55
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'RESERVED',
-    'masked' => 1,
-    'value' => 56,
-    'name' => 'RESERVED_4',
-    'masked_val' => 4,
-    'type_value' => 52
+    "masked" => 1,
+    "masked_val" => 4,
+    "name" => "RESERVED_4",
+    "type_name" => "RESERVED",
+    "type_value" => 52,
+    "value" => 56
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'CANONICAL_UNDEF',
-    'comment' => 'undef (PL_sv_undef) - "the" Perl undef (see notes)',
-    'value' => 57,
-    'name' => 'CANONICAL_UNDEF',
-    'type_value' => 57
+    "comment" => "undef (PL_sv_undef) - \"the\" Perl undef (see notes)",
+    "name" => "CANONICAL_UNDEF",
+    "type_name" => "CANONICAL_UNDEF",
+    "type_value" => 57,
+    "value" => 57
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'FALSE',
-    'comment' => 'false (PL_sv_no)',
-    'value' => 58,
-    'name' => 'FALSE',
-    'type_value' => 58
+    "comment" => "false (PL_sv_no)",
+    "name" => "FALSE",
+    "type_name" => "FALSE",
+    "type_value" => 58,
+    "value" => 58
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'TRUE',
-    'comment' => 'true  (PL_sv_yes)',
-    'value' => 59,
-    'name' => 'TRUE',
-    'type_value' => 59
+    "comment" => "true  (PL_sv_yes)",
+    "name" => "TRUE",
+    "type_name" => "TRUE",
+    "type_value" => 59,
+    "value" => 59
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'MANY',
-    'comment' => '<LEN-VARINT> <TYPE-BYTE> <TAG-DATA> - repeated tag (not done yet, will be implemented in version 3)',
-    'value' => 60,
-    'name' => 'MANY',
-    'type_value' => 60
+    "comment" => "<LEN-VARINT> <TYPE-BYTE> <TAG-DATA> - repeated tag (not done yet, will be implemented in version 3)",
+    "name" => "MANY",
+    "type_name" => "MANY",
+    "type_value" => 60,
+    "value" => 60
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'PACKET_START',
-    'comment' => '(first byte of magic string in header)',
-    'value' => 61,
-    'name' => 'PACKET_START',
-    'type_value' => 61
+    "comment" => "(first byte of magic string in header)",
+    "name" => "PACKET_START",
+    "type_name" => "PACKET_START",
+    "type_value" => 61,
+    "value" => 61
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'EXTEND',
-    'comment' => '<BYTE> - for additional tags',
-    'value' => 62,
-    'name' => 'EXTEND',
-    'type_value' => 62
+    "comment" => "<BYTE> - for additional tags",
+    "name" => "EXTEND",
+    "type_name" => "EXTEND",
+    "type_value" => 62,
+    "value" => 62
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'PAD',
-    'comment' => '(ignored tag, skip to next byte)',
-    'value' => 63,
-    'name' => 'PAD',
-    'type_value' => 63
+    "comment" => "(ignored tag, skip to next byte)",
+    "name" => "PAD",
+    "type_name" => "PAD",
+    "type_value" => 63,
+    "value" => 63
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'comment' => '[<ITEM-TAG> ...] - count of items in low 4 bits (ARRAY must be refcnt=1)',
-    'value' => 64,
-    'name' => 'ARRAYREF_0',
-    'masked_val' => 0,
-    'type_value' => 64
+    "comment" => "[<ITEM-TAG> ...] - count of items in low 4 bits (ARRAY must be refcnt=1)",
+    "masked" => 1,
+    "masked_val" => 0,
+    "name" => "ARRAYREF_0",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 64
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'value' => 65,
-    'name' => 'ARRAYREF_1',
-    'masked_val' => 1,
-    'type_value' => 64
+    "masked" => 1,
+    "masked_val" => 1,
+    "name" => "ARRAYREF_1",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 65
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'value' => 66,
-    'name' => 'ARRAYREF_2',
-    'masked_val' => 2,
-    'type_value' => 64
+    "masked" => 1,
+    "masked_val" => 2,
+    "name" => "ARRAYREF_2",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 66
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'value' => 67,
-    'name' => 'ARRAYREF_3',
-    'masked_val' => 3,
-    'type_value' => 64
+    "masked" => 1,
+    "masked_val" => 3,
+    "name" => "ARRAYREF_3",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 67
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'value' => 68,
-    'name' => 'ARRAYREF_4',
-    'masked_val' => 4,
-    'type_value' => 64
+    "masked" => 1,
+    "masked_val" => 4,
+    "name" => "ARRAYREF_4",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 68
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'value' => 69,
-    'name' => 'ARRAYREF_5',
-    'masked_val' => 5,
-    'type_value' => 64
+    "masked" => 1,
+    "masked_val" => 5,
+    "name" => "ARRAYREF_5",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 69
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'value' => 70,
-    'name' => 'ARRAYREF_6',
-    'masked_val' => 6,
-    'type_value' => 64
+    "masked" => 1,
+    "masked_val" => 6,
+    "name" => "ARRAYREF_6",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 70
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'value' => 71,
-    'name' => 'ARRAYREF_7',
-    'masked_val' => 7,
-    'type_value' => 64
+    "masked" => 1,
+    "masked_val" => 7,
+    "name" => "ARRAYREF_7",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 71
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'value' => 72,
-    'name' => 'ARRAYREF_8',
-    'masked_val' => 8,
-    'type_value' => 64
+    "masked" => 1,
+    "masked_val" => 8,
+    "name" => "ARRAYREF_8",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 72
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'value' => 73,
-    'name' => 'ARRAYREF_9',
-    'masked_val' => 9,
-    'type_value' => 64
+    "masked" => 1,
+    "masked_val" => 9,
+    "name" => "ARRAYREF_9",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 73
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'value' => 74,
-    'name' => 'ARRAYREF_10',
-    'masked_val' => 10,
-    'type_value' => 64
+    "masked" => 1,
+    "masked_val" => 10,
+    "name" => "ARRAYREF_10",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 74
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'value' => 75,
-    'name' => 'ARRAYREF_11',
-    'masked_val' => 11,
-    'type_value' => 64
+    "masked" => 1,
+    "masked_val" => 11,
+    "name" => "ARRAYREF_11",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 75
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'value' => 76,
-    'name' => 'ARRAYREF_12',
-    'masked_val' => 12,
-    'type_value' => 64
+    "masked" => 1,
+    "masked_val" => 12,
+    "name" => "ARRAYREF_12",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 76
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'value' => 77,
-    'name' => 'ARRAYREF_13',
-    'masked_val' => 13,
-    'type_value' => 64
+    "masked" => 1,
+    "masked_val" => 13,
+    "name" => "ARRAYREF_13",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 77
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'value' => 78,
-    'name' => 'ARRAYREF_14',
-    'masked_val' => 14,
-    'type_value' => 64
+    "masked" => 1,
+    "masked_val" => 14,
+    "name" => "ARRAYREF_14",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 78
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'value' => 79,
-    'name' => 'ARRAYREF_15',
-    'masked_val' => 15,
-    'type_value' => 64
+    "masked" => 1,
+    "masked_val" => 15,
+    "name" => "ARRAYREF_15",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 79
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'comment' => '[<KEY-TAG> <ITEM-TAG> ...] - count in low 4 bits, key/value pairs (HASH must be refcnt=1)',
-    'value' => 80,
-    'name' => 'HASHREF_0',
-    'masked_val' => 0,
-    'type_value' => 80
+    "comment" => "[<KEY-TAG> <ITEM-TAG> ...] - count in low 4 bits, key/value pairs (HASH must be refcnt=1)",
+    "masked" => 1,
+    "masked_val" => 0,
+    "name" => "HASHREF_0",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 80
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'value' => 81,
-    'name' => 'HASHREF_1',
-    'masked_val' => 1,
-    'type_value' => 80
+    "masked" => 1,
+    "masked_val" => 1,
+    "name" => "HASHREF_1",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 81
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'value' => 82,
-    'name' => 'HASHREF_2',
-    'masked_val' => 2,
-    'type_value' => 80
+    "masked" => 1,
+    "masked_val" => 2,
+    "name" => "HASHREF_2",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 82
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'value' => 83,
-    'name' => 'HASHREF_3',
-    'masked_val' => 3,
-    'type_value' => 80
+    "masked" => 1,
+    "masked_val" => 3,
+    "name" => "HASHREF_3",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 83
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'value' => 84,
-    'name' => 'HASHREF_4',
-    'masked_val' => 4,
-    'type_value' => 80
+    "masked" => 1,
+    "masked_val" => 4,
+    "name" => "HASHREF_4",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 84
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'value' => 85,
-    'name' => 'HASHREF_5',
-    'masked_val' => 5,
-    'type_value' => 80
+    "masked" => 1,
+    "masked_val" => 5,
+    "name" => "HASHREF_5",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 85
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'value' => 86,
-    'name' => 'HASHREF_6',
-    'masked_val' => 6,
-    'type_value' => 80
+    "masked" => 1,
+    "masked_val" => 6,
+    "name" => "HASHREF_6",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 86
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'value' => 87,
-    'name' => 'HASHREF_7',
-    'masked_val' => 7,
-    'type_value' => 80
+    "masked" => 1,
+    "masked_val" => 7,
+    "name" => "HASHREF_7",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 87
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'value' => 88,
-    'name' => 'HASHREF_8',
-    'masked_val' => 8,
-    'type_value' => 80
+    "masked" => 1,
+    "masked_val" => 8,
+    "name" => "HASHREF_8",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 88
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'value' => 89,
-    'name' => 'HASHREF_9',
-    'masked_val' => 9,
-    'type_value' => 80
+    "masked" => 1,
+    "masked_val" => 9,
+    "name" => "HASHREF_9",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 89
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'value' => 90,
-    'name' => 'HASHREF_10',
-    'masked_val' => 10,
-    'type_value' => 80
+    "masked" => 1,
+    "masked_val" => 10,
+    "name" => "HASHREF_10",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 90
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'value' => 91,
-    'name' => 'HASHREF_11',
-    'masked_val' => 11,
-    'type_value' => 80
+    "masked" => 1,
+    "masked_val" => 11,
+    "name" => "HASHREF_11",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 91
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'value' => 92,
-    'name' => 'HASHREF_12',
-    'masked_val' => 12,
-    'type_value' => 80
+    "masked" => 1,
+    "masked_val" => 12,
+    "name" => "HASHREF_12",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 92
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'value' => 93,
-    'name' => 'HASHREF_13',
-    'masked_val' => 13,
-    'type_value' => 80
+    "masked" => 1,
+    "masked_val" => 13,
+    "name" => "HASHREF_13",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 93
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'value' => 94,
-    'name' => 'HASHREF_14',
-    'masked_val' => 14,
-    'type_value' => 80
+    "masked" => 1,
+    "masked_val" => 14,
+    "name" => "HASHREF_14",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 94
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'value' => 95,
-    'name' => 'HASHREF_15',
-    'masked_val' => 15,
-    'type_value' => 80
+    "masked" => 1,
+    "masked_val" => 15,
+    "name" => "HASHREF_15",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 95
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'comment' => '<BYTES> - binary/latin1 string, length encoded in low 5 bits of tag',
-    'value' => 96,
-    'name' => 'SHORT_BINARY_0',
-    'masked_val' => 0,
-    'type_value' => 96
+    "comment" => "<BYTES> - binary/latin1 string, length encoded in low 5 bits of tag",
+    "masked" => 1,
+    "masked_val" => 0,
+    "name" => "SHORT_BINARY_0",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 96
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 97,
-    'name' => 'SHORT_BINARY_1',
-    'masked_val' => 1,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 1,
+    "name" => "SHORT_BINARY_1",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 97
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 98,
-    'name' => 'SHORT_BINARY_2',
-    'masked_val' => 2,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 2,
+    "name" => "SHORT_BINARY_2",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 98
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 99,
-    'name' => 'SHORT_BINARY_3',
-    'masked_val' => 3,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 3,
+    "name" => "SHORT_BINARY_3",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 99
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 100,
-    'name' => 'SHORT_BINARY_4',
-    'masked_val' => 4,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 4,
+    "name" => "SHORT_BINARY_4",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 100
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 101,
-    'name' => 'SHORT_BINARY_5',
-    'masked_val' => 5,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 5,
+    "name" => "SHORT_BINARY_5",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 101
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 102,
-    'name' => 'SHORT_BINARY_6',
-    'masked_val' => 6,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 6,
+    "name" => "SHORT_BINARY_6",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 102
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 103,
-    'name' => 'SHORT_BINARY_7',
-    'masked_val' => 7,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 7,
+    "name" => "SHORT_BINARY_7",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 103
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 104,
-    'name' => 'SHORT_BINARY_8',
-    'masked_val' => 8,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 8,
+    "name" => "SHORT_BINARY_8",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 104
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 105,
-    'name' => 'SHORT_BINARY_9',
-    'masked_val' => 9,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 9,
+    "name" => "SHORT_BINARY_9",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 105
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 106,
-    'name' => 'SHORT_BINARY_10',
-    'masked_val' => 10,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 10,
+    "name" => "SHORT_BINARY_10",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 106
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 107,
-    'name' => 'SHORT_BINARY_11',
-    'masked_val' => 11,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 11,
+    "name" => "SHORT_BINARY_11",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 107
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 108,
-    'name' => 'SHORT_BINARY_12',
-    'masked_val' => 12,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 12,
+    "name" => "SHORT_BINARY_12",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 108
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 109,
-    'name' => 'SHORT_BINARY_13',
-    'masked_val' => 13,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 13,
+    "name" => "SHORT_BINARY_13",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 109
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 110,
-    'name' => 'SHORT_BINARY_14',
-    'masked_val' => 14,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 14,
+    "name" => "SHORT_BINARY_14",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 110
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 111,
-    'name' => 'SHORT_BINARY_15',
-    'masked_val' => 15,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 15,
+    "name" => "SHORT_BINARY_15",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 111
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 112,
-    'name' => 'SHORT_BINARY_16',
-    'masked_val' => 16,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 16,
+    "name" => "SHORT_BINARY_16",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 112
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 113,
-    'name' => 'SHORT_BINARY_17',
-    'masked_val' => 17,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 17,
+    "name" => "SHORT_BINARY_17",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 113
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 114,
-    'name' => 'SHORT_BINARY_18',
-    'masked_val' => 18,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 18,
+    "name" => "SHORT_BINARY_18",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 114
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 115,
-    'name' => 'SHORT_BINARY_19',
-    'masked_val' => 19,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 19,
+    "name" => "SHORT_BINARY_19",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 115
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 116,
-    'name' => 'SHORT_BINARY_20',
-    'masked_val' => 20,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 20,
+    "name" => "SHORT_BINARY_20",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 116
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 117,
-    'name' => 'SHORT_BINARY_21',
-    'masked_val' => 21,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 21,
+    "name" => "SHORT_BINARY_21",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 117
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 118,
-    'name' => 'SHORT_BINARY_22',
-    'masked_val' => 22,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 22,
+    "name" => "SHORT_BINARY_22",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 118
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 119,
-    'name' => 'SHORT_BINARY_23',
-    'masked_val' => 23,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 23,
+    "name" => "SHORT_BINARY_23",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 119
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 120,
-    'name' => 'SHORT_BINARY_24',
-    'masked_val' => 24,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 24,
+    "name" => "SHORT_BINARY_24",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 120
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 121,
-    'name' => 'SHORT_BINARY_25',
-    'masked_val' => 25,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 25,
+    "name" => "SHORT_BINARY_25",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 121
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 122,
-    'name' => 'SHORT_BINARY_26',
-    'masked_val' => 26,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 26,
+    "name" => "SHORT_BINARY_26",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 122
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 123,
-    'name' => 'SHORT_BINARY_27',
-    'masked_val' => 27,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 27,
+    "name" => "SHORT_BINARY_27",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 123
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 124,
-    'name' => 'SHORT_BINARY_28',
-    'masked_val' => 28,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 28,
+    "name" => "SHORT_BINARY_28",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 124
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 125,
-    'name' => 'SHORT_BINARY_29',
-    'masked_val' => 29,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 29,
+    "name" => "SHORT_BINARY_29",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 125
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 126,
-    'name' => 'SHORT_BINARY_30',
-    'masked_val' => 30,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 30,
+    "name" => "SHORT_BINARY_30",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 126
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 127,
-    'name' => 'SHORT_BINARY_31',
-    'masked_val' => 31,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 31,
+    "name" => "SHORT_BINARY_31",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 127
   }
 );
+
 $TAG_INFO_HASH{chr $_}= $TAG_INFO_ARRAY[$_] for 0 .. 127;
 push @EXPORT_OK, qw(%TAG_INFO_HASH @TAG_INFO_ARRAY);
 
@@ -106,1138 +106,1137 @@ our (%TAG_INFO_HASH, @TAG_INFO_ARRAY);
 @TAG_INFO_ARRAY = (
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'comment' => 'small positive integer - value in low 4 bits (identity)',
-    'value' => 0,
-    'name' => 'POS_0',
-    'masked_val' => 0,
-    'type_value' => 0
+    "comment" => "small positive integer - value in low 4 bits (identity)",
+    "masked" => 1,
+    "masked_val" => 0,
+    "name" => "POS_0",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 0
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'value' => 1,
-    'name' => 'POS_1',
-    'masked_val' => 1,
-    'type_value' => 0
+    "masked" => 1,
+    "masked_val" => 1,
+    "name" => "POS_1",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 1
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'value' => 2,
-    'name' => 'POS_2',
-    'masked_val' => 2,
-    'type_value' => 0
+    "masked" => 1,
+    "masked_val" => 2,
+    "name" => "POS_2",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 2
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'value' => 3,
-    'name' => 'POS_3',
-    'masked_val' => 3,
-    'type_value' => 0
+    "masked" => 1,
+    "masked_val" => 3,
+    "name" => "POS_3",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 3
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'value' => 4,
-    'name' => 'POS_4',
-    'masked_val' => 4,
-    'type_value' => 0
+    "masked" => 1,
+    "masked_val" => 4,
+    "name" => "POS_4",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 4
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'value' => 5,
-    'name' => 'POS_5',
-    'masked_val' => 5,
-    'type_value' => 0
+    "masked" => 1,
+    "masked_val" => 5,
+    "name" => "POS_5",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 5
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'value' => 6,
-    'name' => 'POS_6',
-    'masked_val' => 6,
-    'type_value' => 0
+    "masked" => 1,
+    "masked_val" => 6,
+    "name" => "POS_6",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 6
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'value' => 7,
-    'name' => 'POS_7',
-    'masked_val' => 7,
-    'type_value' => 0
+    "masked" => 1,
+    "masked_val" => 7,
+    "name" => "POS_7",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 7
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'value' => 8,
-    'name' => 'POS_8',
-    'masked_val' => 8,
-    'type_value' => 0
+    "masked" => 1,
+    "masked_val" => 8,
+    "name" => "POS_8",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 8
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'value' => 9,
-    'name' => 'POS_9',
-    'masked_val' => 9,
-    'type_value' => 0
+    "masked" => 1,
+    "masked_val" => 9,
+    "name" => "POS_9",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 9
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'value' => 10,
-    'name' => 'POS_10',
-    'masked_val' => 10,
-    'type_value' => 0
+    "masked" => 1,
+    "masked_val" => 10,
+    "name" => "POS_10",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 10
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'value' => 11,
-    'name' => 'POS_11',
-    'masked_val' => 11,
-    'type_value' => 0
+    "masked" => 1,
+    "masked_val" => 11,
+    "name" => "POS_11",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 11
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'value' => 12,
-    'name' => 'POS_12',
-    'masked_val' => 12,
-    'type_value' => 0
+    "masked" => 1,
+    "masked_val" => 12,
+    "name" => "POS_12",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 12
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'value' => 13,
-    'name' => 'POS_13',
-    'masked_val' => 13,
-    'type_value' => 0
+    "masked" => 1,
+    "masked_val" => 13,
+    "name" => "POS_13",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 13
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'value' => 14,
-    'name' => 'POS_14',
-    'masked_val' => 14,
-    'type_value' => 0
+    "masked" => 1,
+    "masked_val" => 14,
+    "name" => "POS_14",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 14
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'POS',
-    'masked' => 1,
-    'comment' => 'small positive integer - value in low 4 bits (identity)',
-    'value' => 15,
-    'name' => 'POS_15',
-    'masked_val' => 15,
-    'type_value' => 0
+    "masked" => 1,
+    "masked_val" => 15,
+    "name" => "POS_15",
+    "type_name" => "POS",
+    "type_value" => 0,
+    "value" => 15
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'comment' => 'small negative integer - value in low 4 bits (k+32)',
-    'value' => 16,
-    'name' => 'NEG_16',
-    'masked_val' => 16,
-    'type_value' => 16
+    "comment" => "small negative integer - value in low 4 bits (k+32)",
+    "masked" => 1,
+    "masked_val" => 16,
+    "name" => "NEG_16",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 16
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'value' => 17,
-    'name' => 'NEG_15',
-    'masked_val' => 15,
-    'type_value' => 16
+    "masked" => 1,
+    "masked_val" => 15,
+    "name" => "NEG_15",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 17
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'value' => 18,
-    'name' => 'NEG_14',
-    'masked_val' => 14,
-    'type_value' => 16
+    "masked" => 1,
+    "masked_val" => 14,
+    "name" => "NEG_14",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 18
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'value' => 19,
-    'name' => 'NEG_13',
-    'masked_val' => 13,
-    'type_value' => 16
+    "masked" => 1,
+    "masked_val" => 13,
+    "name" => "NEG_13",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 19
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'value' => 20,
-    'name' => 'NEG_12',
-    'masked_val' => 12,
-    'type_value' => 16
+    "masked" => 1,
+    "masked_val" => 12,
+    "name" => "NEG_12",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 20
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'value' => 21,
-    'name' => 'NEG_11',
-    'masked_val' => 11,
-    'type_value' => 16
+    "masked" => 1,
+    "masked_val" => 11,
+    "name" => "NEG_11",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 21
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'value' => 22,
-    'name' => 'NEG_10',
-    'masked_val' => 10,
-    'type_value' => 16
+    "masked" => 1,
+    "masked_val" => 10,
+    "name" => "NEG_10",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 22
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'value' => 23,
-    'name' => 'NEG_9',
-    'masked_val' => 9,
-    'type_value' => 16
+    "masked" => 1,
+    "masked_val" => 9,
+    "name" => "NEG_9",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 23
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'value' => 24,
-    'name' => 'NEG_8',
-    'masked_val' => 8,
-    'type_value' => 16
+    "masked" => 1,
+    "masked_val" => 8,
+    "name" => "NEG_8",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 24
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'value' => 25,
-    'name' => 'NEG_7',
-    'masked_val' => 7,
-    'type_value' => 16
+    "masked" => 1,
+    "masked_val" => 7,
+    "name" => "NEG_7",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 25
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'value' => 26,
-    'name' => 'NEG_6',
-    'masked_val' => 6,
-    'type_value' => 16
+    "masked" => 1,
+    "masked_val" => 6,
+    "name" => "NEG_6",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 26
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'value' => 27,
-    'name' => 'NEG_5',
-    'masked_val' => 5,
-    'type_value' => 16
+    "masked" => 1,
+    "masked_val" => 5,
+    "name" => "NEG_5",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 27
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'value' => 28,
-    'name' => 'NEG_4',
-    'masked_val' => 4,
-    'type_value' => 16
+    "masked" => 1,
+    "masked_val" => 4,
+    "name" => "NEG_4",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 28
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'value' => 29,
-    'name' => 'NEG_3',
-    'masked_val' => 3,
-    'type_value' => 16
+    "masked" => 1,
+    "masked_val" => 3,
+    "name" => "NEG_3",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 29
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'value' => 30,
-    'name' => 'NEG_2',
-    'masked_val' => 2,
-    'type_value' => 16
+    "masked" => 1,
+    "masked_val" => 2,
+    "name" => "NEG_2",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 30
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'NEG',
-    'masked' => 1,
-    'comment' => 'small negative integer - value in low 4 bits (k+32)',
-    'value' => 31,
-    'name' => 'NEG_1',
-    'masked_val' => 1,
-    'type_value' => 16
+    "masked" => 1,
+    "masked_val" => 1,
+    "name" => "NEG_1",
+    "type_name" => "NEG",
+    "type_value" => 16,
+    "value" => 31
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'VARINT',
-    'comment' => '<VARINT> - Varint variable length integer',
-    'value' => 32,
-    'name' => 'VARINT',
-    'type_value' => 32
+    "comment" => "<VARINT> - Varint variable length integer",
+    "name" => "VARINT",
+    "type_name" => "VARINT",
+    "type_value" => 32,
+    "value" => 32
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ZIGZAG',
-    'comment' => '<ZIGZAG-VARINT> - Zigzag variable length integer',
-    'value' => 33,
-    'name' => 'ZIGZAG',
-    'type_value' => 33
+    "comment" => "<ZIGZAG-VARINT> - Zigzag variable length integer",
+    "name" => "ZIGZAG",
+    "type_name" => "ZIGZAG",
+    "type_value" => 33,
+    "value" => 33
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'FLOAT',
-    'comment' => '<IEEE-FLOAT>',
-    'value' => 34,
-    'name' => 'FLOAT',
-    'type_value' => 34
+    "comment" => "<IEEE-FLOAT>",
+    "name" => "FLOAT",
+    "type_name" => "FLOAT",
+    "type_value" => 34,
+    "value" => 34
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'DOUBLE',
-    'comment' => '<IEEE-DOUBLE>',
-    'value' => 35,
-    'name' => 'DOUBLE',
-    'type_value' => 35
+    "comment" => "<IEEE-DOUBLE>",
+    "name" => "DOUBLE",
+    "type_name" => "DOUBLE",
+    "type_value" => 35,
+    "value" => 35
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'LONG_DOUBLE',
-    'comment' => '<IEEE-LONG-DOUBLE>',
-    'value' => 36,
-    'name' => 'LONG_DOUBLE',
-    'type_value' => 36
+    "comment" => "<IEEE-LONG-DOUBLE>",
+    "name" => "LONG_DOUBLE",
+    "type_name" => "LONG_DOUBLE",
+    "type_value" => 36,
+    "value" => 36
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'UNDEF',
-    'comment' => 'None - Perl undef var; eg my $var= undef;',
-    'value' => 37,
-    'name' => 'UNDEF',
-    'type_value' => 37
+    "comment" => "None - Perl undef var; eg my \$var= undef;",
+    "name" => "UNDEF",
+    "type_name" => "UNDEF",
+    "type_value" => 37,
+    "value" => 37
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'BINARY',
-    'comment' => '<LEN-VARINT> <BYTES> - binary/(latin1) string',
-    'value' => 38,
-    'name' => 'BINARY',
-    'type_value' => 38
+    "comment" => "<LEN-VARINT> <BYTES> - binary/(latin1) string",
+    "name" => "BINARY",
+    "type_name" => "BINARY",
+    "type_value" => 38,
+    "value" => 38
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'STR_UTF8',
-    'comment' => '<LEN-VARINT> <UTF8> - utf8 string',
-    'value' => 39,
-    'name' => 'STR_UTF8',
-    'type_value' => 39
+    "comment" => "<LEN-VARINT> <UTF8> - utf8 string",
+    "name" => "STR_UTF8",
+    "type_name" => "STR_UTF8",
+    "type_value" => 39,
+    "value" => 39
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'REFN',
-    'comment' => '<ITEM-TAG>    - ref to next item',
-    'value' => 40,
-    'name' => 'REFN',
-    'type_value' => 40
+    "comment" => "<ITEM-TAG>    - ref to next item",
+    "name" => "REFN",
+    "type_name" => "REFN",
+    "type_value" => 40,
+    "value" => 40
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'REFP',
-    'comment' => '<OFFSET-VARINT> - ref to previous item stored at offset',
-    'value' => 41,
-    'name' => 'REFP',
-    'type_value' => 41
+    "comment" => "<OFFSET-VARINT> - ref to previous item stored at offset",
+    "name" => "REFP",
+    "type_name" => "REFP",
+    "type_value" => 41,
+    "value" => 41
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASH',
-    'comment' => '<COUNT-VARINT> [<KEY-TAG> <ITEM-TAG> ...] - count followed by key/value pairs',
-    'value' => 42,
-    'name' => 'HASH',
-    'type_value' => 42
+    "comment" => "<COUNT-VARINT> [<KEY-TAG> <ITEM-TAG> ...] - count followed by key/value pairs",
+    "name" => "HASH",
+    "type_name" => "HASH",
+    "type_value" => 42,
+    "value" => 42
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAY',
-    'comment' => '<COUNT-VARINT> [<ITEM-TAG> ...] - count followed by items',
-    'value' => 43,
-    'name' => 'ARRAY',
-    'type_value' => 43
+    "comment" => "<COUNT-VARINT> [<ITEM-TAG> ...] - count followed by items",
+    "name" => "ARRAY",
+    "type_name" => "ARRAY",
+    "type_value" => 43,
+    "value" => 43
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'OBJECT',
-    'comment' => '<STR-TAG> <ITEM-TAG> - class, object-item',
-    'value' => 44,
-    'name' => 'OBJECT',
-    'type_value' => 44
+    "comment" => "<STR-TAG> <ITEM-TAG> - class, object-item",
+    "name" => "OBJECT",
+    "type_name" => "OBJECT",
+    "type_value" => 44,
+    "value" => 44
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'OBJECTV',
-    'comment' => '<OFFSET-VARINT> <ITEM-TAG> - offset of previously used classname tag - object-item',
-    'value' => 45,
-    'name' => 'OBJECTV',
-    'type_value' => 45
+    "comment" => "<OFFSET-VARINT> <ITEM-TAG> - offset of previously used classname tag - object-item",
+    "name" => "OBJECTV",
+    "type_name" => "OBJECTV",
+    "type_value" => 45,
+    "value" => 45
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ALIAS',
-    'comment' => '<OFFSET-VARINT> - alias to item defined at offset',
-    'value' => 46,
-    'name' => 'ALIAS',
-    'type_value' => 46
+    "comment" => "<OFFSET-VARINT> - alias to item defined at offset",
+    "name" => "ALIAS",
+    "type_name" => "ALIAS",
+    "type_value" => 46,
+    "value" => 46
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'COPY',
-    'comment' => '<OFFSET-VARINT> - copy of item defined at offset',
-    'value' => 47,
-    'name' => 'COPY',
-    'type_value' => 47
+    "comment" => "<OFFSET-VARINT> - copy of item defined at offset",
+    "name" => "COPY",
+    "type_name" => "COPY",
+    "type_value" => 47,
+    "value" => 47
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'WEAKEN',
-    'comment' => '<REF-TAG> - Weaken the following reference',
-    'value' => 48,
-    'name' => 'WEAKEN',
-    'type_value' => 48
+    "comment" => "<REF-TAG> - Weaken the following reference",
+    "name" => "WEAKEN",
+    "type_name" => "WEAKEN",
+    "type_value" => 48,
+    "value" => 48
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'REGEXP',
-    'comment' => '<PATTERN-STR-TAG> <MODIFIERS-STR-TAG>',
-    'value' => 49,
-    'name' => 'REGEXP',
-    'type_value' => 49
+    "comment" => "<PATTERN-STR-TAG> <MODIFIERS-STR-TAG>",
+    "name" => "REGEXP",
+    "type_name" => "REGEXP",
+    "type_value" => 49,
+    "value" => 49
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'OBJECT_FREEZE',
-    'comment' => '<STR-TAG> <ITEM-TAG> - class, object-item. Need to call "THAW" method on class after decoding',
-    'value' => 50,
-    'name' => 'OBJECT_FREEZE',
-    'type_value' => 50
+    "comment" => "<STR-TAG> <ITEM-TAG> - class, object-item. Need to call \"THAW\" method on class after decoding",
+    "name" => "OBJECT_FREEZE",
+    "type_name" => "OBJECT_FREEZE",
+    "type_value" => 50,
+    "value" => 50
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'OBJECTV_FREEZE',
-    'comment' => '<OFFSET-VARINT> <ITEM-TAG> - (OBJECTV_FREEZE is to OBJECT_FREEZE as OBJECTV is to OBJECT)',
-    'value' => 51,
-    'name' => 'OBJECTV_FREEZE',
-    'type_value' => 51
+    "comment" => "<OFFSET-VARINT> <ITEM-TAG> - (OBJECTV_FREEZE is to OBJECT_FREEZE as OBJECTV is to OBJECT)",
+    "name" => "OBJECTV_FREEZE",
+    "type_name" => "OBJECTV_FREEZE",
+    "type_value" => 51,
+    "value" => 51
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'RESERVED',
-    'masked' => 1,
-    'comment' => 'reserved',
-    'value' => 52,
-    'name' => 'RESERVED_0',
-    'masked_val' => 0,
-    'type_value' => 52
+    "comment" => "reserved",
+    "masked" => 1,
+    "masked_val" => 0,
+    "name" => "RESERVED_0",
+    "type_name" => "RESERVED",
+    "type_value" => 52,
+    "value" => 52
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'RESERVED',
-    'masked' => 1,
-    'value' => 53,
-    'name' => 'RESERVED_1',
-    'masked_val' => 1,
-    'type_value' => 52
+    "masked" => 1,
+    "masked_val" => 1,
+    "name" => "RESERVED_1",
+    "type_name" => "RESERVED",
+    "type_value" => 52,
+    "value" => 53
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'RESERVED',
-    'masked' => 1,
-    'value' => 54,
-    'name' => 'RESERVED_2',
-    'masked_val' => 2,
-    'type_value' => 52
+    "masked" => 1,
+    "masked_val" => 2,
+    "name" => "RESERVED_2",
+    "type_name" => "RESERVED",
+    "type_value" => 52,
+    "value" => 54
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'RESERVED',
-    'masked' => 1,
-    'value' => 55,
-    'name' => 'RESERVED_3',
-    'masked_val' => 3,
-    'type_value' => 52
+    "masked" => 1,
+    "masked_val" => 3,
+    "name" => "RESERVED_3",
+    "type_name" => "RESERVED",
+    "type_value" => 52,
+    "value" => 55
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'RESERVED',
-    'masked' => 1,
-    'value' => 56,
-    'name' => 'RESERVED_4',
-    'masked_val' => 4,
-    'type_value' => 52
+    "masked" => 1,
+    "masked_val" => 4,
+    "name" => "RESERVED_4",
+    "type_name" => "RESERVED",
+    "type_value" => 52,
+    "value" => 56
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'CANONICAL_UNDEF',
-    'comment' => 'undef (PL_sv_undef) - "the" Perl undef (see notes)',
-    'value' => 57,
-    'name' => 'CANONICAL_UNDEF',
-    'type_value' => 57
+    "comment" => "undef (PL_sv_undef) - \"the\" Perl undef (see notes)",
+    "name" => "CANONICAL_UNDEF",
+    "type_name" => "CANONICAL_UNDEF",
+    "type_value" => 57,
+    "value" => 57
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'FALSE',
-    'comment' => 'false (PL_sv_no)',
-    'value' => 58,
-    'name' => 'FALSE',
-    'type_value' => 58
+    "comment" => "false (PL_sv_no)",
+    "name" => "FALSE",
+    "type_name" => "FALSE",
+    "type_value" => 58,
+    "value" => 58
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'TRUE',
-    'comment' => 'true  (PL_sv_yes)',
-    'value' => 59,
-    'name' => 'TRUE',
-    'type_value' => 59
+    "comment" => "true  (PL_sv_yes)",
+    "name" => "TRUE",
+    "type_name" => "TRUE",
+    "type_value" => 59,
+    "value" => 59
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'MANY',
-    'comment' => '<LEN-VARINT> <TYPE-BYTE> <TAG-DATA> - repeated tag (not done yet, will be implemented in version 3)',
-    'value' => 60,
-    'name' => 'MANY',
-    'type_value' => 60
+    "comment" => "<LEN-VARINT> <TYPE-BYTE> <TAG-DATA> - repeated tag (not done yet, will be implemented in version 3)",
+    "name" => "MANY",
+    "type_name" => "MANY",
+    "type_value" => 60,
+    "value" => 60
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'PACKET_START',
-    'comment' => '(first byte of magic string in header)',
-    'value' => 61,
-    'name' => 'PACKET_START',
-    'type_value' => 61
+    "comment" => "(first byte of magic string in header)",
+    "name" => "PACKET_START",
+    "type_name" => "PACKET_START",
+    "type_value" => 61,
+    "value" => 61
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'EXTEND',
-    'comment' => '<BYTE> - for additional tags',
-    'value' => 62,
-    'name' => 'EXTEND',
-    'type_value' => 62
+    "comment" => "<BYTE> - for additional tags",
+    "name" => "EXTEND",
+    "type_name" => "EXTEND",
+    "type_value" => 62,
+    "value" => 62
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'PAD',
-    'comment' => '(ignored tag, skip to next byte)',
-    'value' => 63,
-    'name' => 'PAD',
-    'type_value' => 63
+    "comment" => "(ignored tag, skip to next byte)",
+    "name" => "PAD",
+    "type_name" => "PAD",
+    "type_value" => 63,
+    "value" => 63
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'comment' => '[<ITEM-TAG> ...] - count of items in low 4 bits (ARRAY must be refcnt=1)',
-    'value' => 64,
-    'name' => 'ARRAYREF_0',
-    'masked_val' => 0,
-    'type_value' => 64
+    "comment" => "[<ITEM-TAG> ...] - count of items in low 4 bits (ARRAY must be refcnt=1)",
+    "masked" => 1,
+    "masked_val" => 0,
+    "name" => "ARRAYREF_0",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 64
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'value' => 65,
-    'name' => 'ARRAYREF_1',
-    'masked_val' => 1,
-    'type_value' => 64
+    "masked" => 1,
+    "masked_val" => 1,
+    "name" => "ARRAYREF_1",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 65
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'value' => 66,
-    'name' => 'ARRAYREF_2',
-    'masked_val' => 2,
-    'type_value' => 64
+    "masked" => 1,
+    "masked_val" => 2,
+    "name" => "ARRAYREF_2",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 66
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'value' => 67,
-    'name' => 'ARRAYREF_3',
-    'masked_val' => 3,
-    'type_value' => 64
+    "masked" => 1,
+    "masked_val" => 3,
+    "name" => "ARRAYREF_3",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 67
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'value' => 68,
-    'name' => 'ARRAYREF_4',
-    'masked_val' => 4,
-    'type_value' => 64
+    "masked" => 1,
+    "masked_val" => 4,
+    "name" => "ARRAYREF_4",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 68
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'value' => 69,
-    'name' => 'ARRAYREF_5',
-    'masked_val' => 5,
-    'type_value' => 64
+    "masked" => 1,
+    "masked_val" => 5,
+    "name" => "ARRAYREF_5",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 69
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'value' => 70,
-    'name' => 'ARRAYREF_6',
-    'masked_val' => 6,
-    'type_value' => 64
+    "masked" => 1,
+    "masked_val" => 6,
+    "name" => "ARRAYREF_6",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 70
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'value' => 71,
-    'name' => 'ARRAYREF_7',
-    'masked_val' => 7,
-    'type_value' => 64
+    "masked" => 1,
+    "masked_val" => 7,
+    "name" => "ARRAYREF_7",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 71
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'value' => 72,
-    'name' => 'ARRAYREF_8',
-    'masked_val' => 8,
-    'type_value' => 64
+    "masked" => 1,
+    "masked_val" => 8,
+    "name" => "ARRAYREF_8",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 72
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'value' => 73,
-    'name' => 'ARRAYREF_9',
-    'masked_val' => 9,
-    'type_value' => 64
+    "masked" => 1,
+    "masked_val" => 9,
+    "name" => "ARRAYREF_9",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 73
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'value' => 74,
-    'name' => 'ARRAYREF_10',
-    'masked_val' => 10,
-    'type_value' => 64
+    "masked" => 1,
+    "masked_val" => 10,
+    "name" => "ARRAYREF_10",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 74
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'value' => 75,
-    'name' => 'ARRAYREF_11',
-    'masked_val' => 11,
-    'type_value' => 64
+    "masked" => 1,
+    "masked_val" => 11,
+    "name" => "ARRAYREF_11",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 75
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'value' => 76,
-    'name' => 'ARRAYREF_12',
-    'masked_val' => 12,
-    'type_value' => 64
+    "masked" => 1,
+    "masked_val" => 12,
+    "name" => "ARRAYREF_12",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 76
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'value' => 77,
-    'name' => 'ARRAYREF_13',
-    'masked_val' => 13,
-    'type_value' => 64
+    "masked" => 1,
+    "masked_val" => 13,
+    "name" => "ARRAYREF_13",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 77
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'value' => 78,
-    'name' => 'ARRAYREF_14',
-    'masked_val' => 14,
-    'type_value' => 64
+    "masked" => 1,
+    "masked_val" => 14,
+    "name" => "ARRAYREF_14",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 78
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'ARRAYREF',
-    'masked' => 1,
-    'value' => 79,
-    'name' => 'ARRAYREF_15',
-    'masked_val' => 15,
-    'type_value' => 64
+    "masked" => 1,
+    "masked_val" => 15,
+    "name" => "ARRAYREF_15",
+    "type_name" => "ARRAYREF",
+    "type_value" => 64,
+    "value" => 79
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'comment' => '[<KEY-TAG> <ITEM-TAG> ...] - count in low 4 bits, key/value pairs (HASH must be refcnt=1)',
-    'value' => 80,
-    'name' => 'HASHREF_0',
-    'masked_val' => 0,
-    'type_value' => 80
+    "comment" => "[<KEY-TAG> <ITEM-TAG> ...] - count in low 4 bits, key/value pairs (HASH must be refcnt=1)",
+    "masked" => 1,
+    "masked_val" => 0,
+    "name" => "HASHREF_0",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 80
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'value' => 81,
-    'name' => 'HASHREF_1',
-    'masked_val' => 1,
-    'type_value' => 80
+    "masked" => 1,
+    "masked_val" => 1,
+    "name" => "HASHREF_1",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 81
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'value' => 82,
-    'name' => 'HASHREF_2',
-    'masked_val' => 2,
-    'type_value' => 80
+    "masked" => 1,
+    "masked_val" => 2,
+    "name" => "HASHREF_2",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 82
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'value' => 83,
-    'name' => 'HASHREF_3',
-    'masked_val' => 3,
-    'type_value' => 80
+    "masked" => 1,
+    "masked_val" => 3,
+    "name" => "HASHREF_3",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 83
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'value' => 84,
-    'name' => 'HASHREF_4',
-    'masked_val' => 4,
-    'type_value' => 80
+    "masked" => 1,
+    "masked_val" => 4,
+    "name" => "HASHREF_4",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 84
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'value' => 85,
-    'name' => 'HASHREF_5',
-    'masked_val' => 5,
-    'type_value' => 80
+    "masked" => 1,
+    "masked_val" => 5,
+    "name" => "HASHREF_5",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 85
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'value' => 86,
-    'name' => 'HASHREF_6',
-    'masked_val' => 6,
-    'type_value' => 80
+    "masked" => 1,
+    "masked_val" => 6,
+    "name" => "HASHREF_6",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 86
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'value' => 87,
-    'name' => 'HASHREF_7',
-    'masked_val' => 7,
-    'type_value' => 80
+    "masked" => 1,
+    "masked_val" => 7,
+    "name" => "HASHREF_7",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 87
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'value' => 88,
-    'name' => 'HASHREF_8',
-    'masked_val' => 8,
-    'type_value' => 80
+    "masked" => 1,
+    "masked_val" => 8,
+    "name" => "HASHREF_8",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 88
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'value' => 89,
-    'name' => 'HASHREF_9',
-    'masked_val' => 9,
-    'type_value' => 80
+    "masked" => 1,
+    "masked_val" => 9,
+    "name" => "HASHREF_9",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 89
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'value' => 90,
-    'name' => 'HASHREF_10',
-    'masked_val' => 10,
-    'type_value' => 80
+    "masked" => 1,
+    "masked_val" => 10,
+    "name" => "HASHREF_10",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 90
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'value' => 91,
-    'name' => 'HASHREF_11',
-    'masked_val' => 11,
-    'type_value' => 80
+    "masked" => 1,
+    "masked_val" => 11,
+    "name" => "HASHREF_11",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 91
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'value' => 92,
-    'name' => 'HASHREF_12',
-    'masked_val' => 12,
-    'type_value' => 80
+    "masked" => 1,
+    "masked_val" => 12,
+    "name" => "HASHREF_12",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 92
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'value' => 93,
-    'name' => 'HASHREF_13',
-    'masked_val' => 13,
-    'type_value' => 80
+    "masked" => 1,
+    "masked_val" => 13,
+    "name" => "HASHREF_13",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 93
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'value' => 94,
-    'name' => 'HASHREF_14',
-    'masked_val' => 14,
-    'type_value' => 80
+    "masked" => 1,
+    "masked_val" => 14,
+    "name" => "HASHREF_14",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 94
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'HASHREF',
-    'masked' => 1,
-    'value' => 95,
-    'name' => 'HASHREF_15',
-    'masked_val' => 15,
-    'type_value' => 80
+    "masked" => 1,
+    "masked_val" => 15,
+    "name" => "HASHREF_15",
+    "type_name" => "HASHREF",
+    "type_value" => 80,
+    "value" => 95
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'comment' => '<BYTES> - binary/latin1 string, length encoded in low 5 bits of tag',
-    'value' => 96,
-    'name' => 'SHORT_BINARY_0',
-    'masked_val' => 0,
-    'type_value' => 96
+    "comment" => "<BYTES> - binary/latin1 string, length encoded in low 5 bits of tag",
+    "masked" => 1,
+    "masked_val" => 0,
+    "name" => "SHORT_BINARY_0",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 96
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 97,
-    'name' => 'SHORT_BINARY_1',
-    'masked_val' => 1,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 1,
+    "name" => "SHORT_BINARY_1",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 97
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 98,
-    'name' => 'SHORT_BINARY_2',
-    'masked_val' => 2,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 2,
+    "name" => "SHORT_BINARY_2",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 98
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 99,
-    'name' => 'SHORT_BINARY_3',
-    'masked_val' => 3,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 3,
+    "name" => "SHORT_BINARY_3",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 99
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 100,
-    'name' => 'SHORT_BINARY_4',
-    'masked_val' => 4,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 4,
+    "name" => "SHORT_BINARY_4",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 100
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 101,
-    'name' => 'SHORT_BINARY_5',
-    'masked_val' => 5,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 5,
+    "name" => "SHORT_BINARY_5",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 101
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 102,
-    'name' => 'SHORT_BINARY_6',
-    'masked_val' => 6,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 6,
+    "name" => "SHORT_BINARY_6",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 102
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 103,
-    'name' => 'SHORT_BINARY_7',
-    'masked_val' => 7,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 7,
+    "name" => "SHORT_BINARY_7",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 103
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 104,
-    'name' => 'SHORT_BINARY_8',
-    'masked_val' => 8,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 8,
+    "name" => "SHORT_BINARY_8",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 104
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 105,
-    'name' => 'SHORT_BINARY_9',
-    'masked_val' => 9,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 9,
+    "name" => "SHORT_BINARY_9",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 105
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 106,
-    'name' => 'SHORT_BINARY_10',
-    'masked_val' => 10,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 10,
+    "name" => "SHORT_BINARY_10",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 106
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 107,
-    'name' => 'SHORT_BINARY_11',
-    'masked_val' => 11,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 11,
+    "name" => "SHORT_BINARY_11",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 107
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 108,
-    'name' => 'SHORT_BINARY_12',
-    'masked_val' => 12,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 12,
+    "name" => "SHORT_BINARY_12",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 108
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 109,
-    'name' => 'SHORT_BINARY_13',
-    'masked_val' => 13,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 13,
+    "name" => "SHORT_BINARY_13",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 109
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 110,
-    'name' => 'SHORT_BINARY_14',
-    'masked_val' => 14,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 14,
+    "name" => "SHORT_BINARY_14",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 110
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 111,
-    'name' => 'SHORT_BINARY_15',
-    'masked_val' => 15,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 15,
+    "name" => "SHORT_BINARY_15",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 111
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 112,
-    'name' => 'SHORT_BINARY_16',
-    'masked_val' => 16,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 16,
+    "name" => "SHORT_BINARY_16",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 112
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 113,
-    'name' => 'SHORT_BINARY_17',
-    'masked_val' => 17,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 17,
+    "name" => "SHORT_BINARY_17",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 113
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 114,
-    'name' => 'SHORT_BINARY_18',
-    'masked_val' => 18,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 18,
+    "name" => "SHORT_BINARY_18",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 114
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 115,
-    'name' => 'SHORT_BINARY_19',
-    'masked_val' => 19,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 19,
+    "name" => "SHORT_BINARY_19",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 115
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 116,
-    'name' => 'SHORT_BINARY_20',
-    'masked_val' => 20,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 20,
+    "name" => "SHORT_BINARY_20",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 116
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 117,
-    'name' => 'SHORT_BINARY_21',
-    'masked_val' => 21,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 21,
+    "name" => "SHORT_BINARY_21",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 117
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 118,
-    'name' => 'SHORT_BINARY_22',
-    'masked_val' => 22,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 22,
+    "name" => "SHORT_BINARY_22",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 118
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 119,
-    'name' => 'SHORT_BINARY_23',
-    'masked_val' => 23,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 23,
+    "name" => "SHORT_BINARY_23",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 119
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 120,
-    'name' => 'SHORT_BINARY_24',
-    'masked_val' => 24,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 24,
+    "name" => "SHORT_BINARY_24",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 120
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 121,
-    'name' => 'SHORT_BINARY_25',
-    'masked_val' => 25,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 25,
+    "name" => "SHORT_BINARY_25",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 121
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 122,
-    'name' => 'SHORT_BINARY_26',
-    'masked_val' => 26,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 26,
+    "name" => "SHORT_BINARY_26",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 122
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 123,
-    'name' => 'SHORT_BINARY_27',
-    'masked_val' => 27,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 27,
+    "name" => "SHORT_BINARY_27",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 123
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 124,
-    'name' => 'SHORT_BINARY_28',
-    'masked_val' => 28,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 28,
+    "name" => "SHORT_BINARY_28",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 124
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 125,
-    'name' => 'SHORT_BINARY_29',
-    'masked_val' => 29,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 29,
+    "name" => "SHORT_BINARY_29",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 125
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 126,
-    'name' => 'SHORT_BINARY_30',
-    'masked_val' => 30,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 30,
+    "name" => "SHORT_BINARY_30",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 126
   },
   # autoupdated by author_tools/update_from_header.pl do not modify directly!
   {
-    'type_name' => 'SHORT_BINARY',
-    'masked' => 1,
-    'value' => 127,
-    'name' => 'SHORT_BINARY_31',
-    'masked_val' => 31,
-    'type_value' => 96
+    "masked" => 1,
+    "masked_val" => 31,
+    "name" => "SHORT_BINARY_31",
+    "type_name" => "SHORT_BINARY",
+    "type_value" => 96,
+    "value" => 127
   }
 );
+
 $TAG_INFO_HASH{chr $_}= $TAG_INFO_ARRAY[$_] for 0 .. 127;
 push @EXPORT_OK, qw(%TAG_INFO_HASH @TAG_INFO_ARRAY);
 
@@ -5,7 +5,7 @@ use warnings;
 use Carp qw/croak/;
 use XSLoader;
 
-our $VERSION = '3.003'; # Don't forget to update the TestCompat set for testing against installed encoders!
+our $VERSION = '3.005'; # Don't forget to update the TestCompat set for testing against installed encoders!
 our $XS_VERSION = $VERSION; $VERSION= eval $VERSION;
 
 # not for public consumption, just for testing.
@@ -70,31 +70,26 @@ struct PTABLE_iter {
     struct PTABLE_entry     *cur_entry;
 };
 
-
-STATIC PTABLE_t * PTABLE_new(void);
-STATIC PTABLE_t * PTABLE_new_size(const U8 size_base2_exponent);
-STATIC PTABLE_ENTRY_t * PTABLE_find(PTABLE_t *tbl, const void *key);
-STATIC void * PTABLE_fetch(PTABLE_t *tbl, const void *key);
-STATIC void PTABLE_store(PTABLE_t *tbl, void *key, void *value);
-STATIC void PTABLE_delete(PTABLE_t *tbl, void *key);
-STATIC void PTABLE_grow(PTABLE_t *tbl);
-STATIC void PTABLE_clear(PTABLE_t *tbl);
-STATIC void PTABLE_clear_dec(pTHX_ PTABLE_t *tbl);
-STATIC void PTABLE_free(PTABLE_t *tbl);
-
-STATIC PTABLE_ITER_t * PTABLE_iter_new(PTABLE_t *tbl);
-STATIC PTABLE_ITER_t * PTABLE_iter_new_flags(PTABLE_t *tbl, int flags);
-STATIC PTABLE_ENTRY_t * PTABLE_iter_next(PTABLE_ITER_t *iter);
-STATIC void PTABLE_iter_free(PTABLE_ITER_t *iter);
+/*
+SRL_STATIC_INLINE PTABLE_t * PTABLE_new(void);
+SRL_STATIC_INLINE PTABLE_t * PTABLE_new_size(const U8 size_base2_exponent);
+SRL_STATIC_INLINE PTABLE_ENTRY_t * PTABLE_find(PTABLE_t *tbl, const void *key);
+SRL_STATIC_INLINE void * PTABLE_fetch(PTABLE_t *tbl, const void *key);
+SRL_STATIC_INLINE PTABLE_ENTRY_t * PTABLE_store(PTABLE_t *tbl, void *key, void *value);
+SRL_STATIC_INLINE void PTABLE_delete(PTABLE_t *tbl, void *key);
+SRL_STATIC_INLINE void PTABLE_grow(PTABLE_t *tbl);
+SRL_STATIC_INLINE void PTABLE_clear(PTABLE_t *tbl);
+SRL_STATIC_INLINE void PTABLE_clear_dec(pTHX_ PTABLE_t *tbl);
+SRL_STATIC_INLINE void PTABLE_free(PTABLE_t *tbl);
+
+SRL_STATIC_INLINE PTABLE_ITER_t * PTABLE_iter_new(PTABLE_t *tbl);
+SRL_STATIC_INLINE PTABLE_ITER_t * PTABLE_iter_new_flags(PTABLE_t *tbl, int flags);
+SRL_STATIC_INLINE PTABLE_ENTRY_t * PTABLE_iter_next(PTABLE_ITER_t *iter);
+SRL_STATIC_INLINE void PTABLE_iter_free(PTABLE_ITER_t *iter);
+*/
 
 /* create a new pointer => pointer table */
 SRL_STATIC_INLINE PTABLE_t *
-PTABLE_new(void)
-{
-    return PTABLE_new_size(9);
-}
-
-STATIC PTABLE_t *
 PTABLE_new_size(const U8 size_base2_exponent)
 {
     PTABLE_t *tbl;
@@ -106,8 +101,14 @@ PTABLE_new_size(const U8 size_base2_exponent)
     return tbl;
 }
 
+SRL_STATIC_INLINE PTABLE_t *
+PTABLE_new(void)
+{
+    return PTABLE_new_size(9);
+}
+
 /* map an existing pointer using a table */
-STATIC PTABLE_ENTRY_t *
+SRL_STATIC_INLINE PTABLE_ENTRY_t *
 PTABLE_find(PTABLE_t *tbl, const void *key) {
     PTABLE_ENTRY_t *tblent;
     const UV hash = PTABLE_HASH(key);
@@ -126,33 +127,9 @@ PTABLE_fetch(PTABLE_t *tbl, const void *key)
     return tblent ? tblent->value : NULL;
 }
 
-/* add a new entry to a pointer => pointer table */
-
-STATIC void
-PTABLE_store(PTABLE_t *tbl, void *key, void *value)
-{
-    PTABLE_ENTRY_t *tblent = PTABLE_find(tbl, key);
-
-    if (tblent) {
-        tblent->value = value;
-    } else {
-        const UV entry = PTABLE_HASH(key) & tbl->tbl_max;
-        Newx(tblent, 1, PTABLE_ENTRY_t);
-
-        tblent->key = key;
-        tblent->value = value;
-        tblent->next = tbl->tbl_ary[entry];
-        tbl->tbl_ary[entry] = tblent;
-        tbl->tbl_items++;
-        if (tblent->next && (tbl->tbl_items > tbl->tbl_max))
-            PTABLE_grow(tbl);
-    }
-
-}
-
 /* double the hash bucket size of an existing ptr table */
 
-STATIC void
+SRL_STATIC_INLINE void
 PTABLE_grow(PTABLE_t *tbl)
 {
     PTABLE_ENTRY_t **ary = tbl->tbl_ary;
@@ -183,9 +160,35 @@ PTABLE_grow(PTABLE_t *tbl)
     }
 }
 
+/* add a new entry to a pointer => pointer table */
+
+SRL_STATIC_INLINE PTABLE_ENTRY_t *
+PTABLE_store(PTABLE_t *tbl, void *key, void *value)
+{
+    PTABLE_ENTRY_t *tblent = PTABLE_find(tbl, key);
+
+    if (tblent) {
+        tblent->value = value;
+    } else {
+        const UV entry = PTABLE_HASH(key) & tbl->tbl_max;
+        Newx(tblent, 1, PTABLE_ENTRY_t);
+
+        tblent->key = key;
+        tblent->value = value;
+        tblent->next = tbl->tbl_ary[entry];
+        tbl->tbl_ary[entry] = tblent;
+        tbl->tbl_items++;
+        if (tblent->next && (tbl->tbl_items > tbl->tbl_max))
+            PTABLE_grow(tbl);
+    }
+
+    return tblent;
+}
+
+
 /* remove all the entries from a ptr table */
 
-STATIC void
+SRL_STATIC_INLINE void
 PTABLE_clear(PTABLE_t *tbl)
 {
     if (tbl && tbl->tbl_items) {
@@ -213,7 +216,7 @@ PTABLE_clear(PTABLE_t *tbl)
     }
 }
 
-STATIC void
+SRL_STATIC_INLINE void
 PTABLE_clear_dec(pTHX_ PTABLE_t *tbl)
 {
     if (tbl && tbl->tbl_items) {
@@ -245,7 +248,7 @@ PTABLE_clear_dec(pTHX_ PTABLE_t *tbl)
 
 /* remove one entry from a ptr table */
 
-STATIC void
+SRL_STATIC_INLINE void
 PTABLE_delete(PTABLE_t *tbl, void *key)
 {
     PTABLE_ENTRY_t *tblent;
@@ -274,23 +277,6 @@ PTABLE_delete(PTABLE_t *tbl, void *key)
     }
 }
 
-/* clear and free a ptr table */
-
-STATIC void
-PTABLE_free(PTABLE_t *tbl)
-{
-    if (!tbl)
-        return;
-
-    PTABLE_clear(tbl);
-    if (tbl->cur_iter) {
-        PTABLE_ITER_t *it = tbl->cur_iter;
-        tbl->cur_iter = NULL; /* avoid circular checks */
-        PTABLE_iter_free(it);
-    }
-    Safefree(tbl->tbl_ary);
-    Safefree(tbl);
-}
 
 
 #define PTABLE_ITER_NEXT_ELEM(iter, tbl)                                    \
@@ -310,13 +296,7 @@ PTABLE_free(PTABLE_t *tbl)
     } STMT_END
 
 /* Create new iterator object */
-STATIC PTABLE_ITER_t *
-PTABLE_iter_new(PTABLE_t *tbl)
-{
-    return PTABLE_iter_new_flags(tbl, 0);
-}
-
-STATIC PTABLE_ITER_t *
+SRL_STATIC_INLINE PTABLE_ITER_t *
 PTABLE_iter_new_flags(PTABLE_t *tbl, int flags)
 {
     PTABLE_ITER_t *iter;
@@ -338,8 +318,15 @@ PTABLE_iter_new_flags(PTABLE_t *tbl, int flags)
     return iter;
 }
 
+SRL_STATIC_INLINE PTABLE_ITER_t *
+PTABLE_iter_new(PTABLE_t *tbl)
+{
+    return PTABLE_iter_new_flags(tbl, 0);
+}
+
+
 /* Return next item from hash, NULL if at end */
-STATIC PTABLE_ENTRY_t *
+SRL_STATIC_INLINE PTABLE_ENTRY_t *
 PTABLE_iter_next(PTABLE_ITER_t *iter)
 {
     PTABLE_ENTRY_t *retval = iter->cur_entry;
@@ -349,7 +336,7 @@ PTABLE_iter_next(PTABLE_ITER_t *iter)
 }
 
 /* Free iterator object */
-STATIC void
+SRL_STATIC_INLINE void
 PTABLE_iter_free(PTABLE_ITER_t *iter)
 {
     /* If we're the iterator that can be auto-cleaned by the PTABLE,
@@ -360,7 +347,7 @@ PTABLE_iter_free(PTABLE_ITER_t *iter)
     Safefree(iter);
 }
 
-STATIC void
+SRL_STATIC_INLINE void
 PTABLE_debug_dump(PTABLE_t *tbl, void (*func)(PTABLE_ENTRY_t *e))
 {
     PTABLE_ENTRY_t *e;
@@ -371,4 +358,22 @@ PTABLE_debug_dump(PTABLE_t *tbl, void (*func)(PTABLE_ENTRY_t *e))
     PTABLE_iter_free(iter);
 }
 
+/* clear and free a ptr table */
+
+SRL_STATIC_INLINE void
+PTABLE_free(PTABLE_t *tbl)
+{
+    if (!tbl)
+        return;
+
+    PTABLE_clear(tbl);
+    if (tbl->cur_iter) {
+        PTABLE_ITER_t *it = tbl->cur_iter;
+        tbl->cur_iter = NULL; /* avoid circular checks */
+        PTABLE_iter_free(it);
+    }
+    Safefree(tbl->tbl_ary);
+    Safefree(tbl);
+}
+
 #endif
@@ -53,7 +53,7 @@
  * traps (silently) do not happen.
  *
  * The Linux kernel and the Solarix x86 set the "AM".  The Windows and
- * OX X do not.  The *BSD behavior is unknown, though suspecting they do.
+ * OS X do not.  The *BSD behavior is unknown, though suspecting they do.
  *
  * http://en.wikipedia.org/wiki/Control_register
  * http://en.wikipedia.org/wiki/FLAGS_register_(computing)
@@ -43,6 +43,9 @@ extern "C" {
 #if (PERL_VERSION < 10)
 #   define FIXUP_RITER 1
 #endif
+#if (PERL_VERSION >= 10)
+#   define FAST_IV 1
+#endif
 #define DEFAULT_MAX_RECUR_DEPTH 10000
 
 #include "srl_decoder.h"
@@ -50,6 +53,8 @@ extern "C" {
 #include "srl_common.h"
 #include "ptable.h"
 #include "srl_protocol.h"
+#include "srl_taginfo.h"
+#include "srl_error.h"
 
 #if defined(HAVE_CSNAPPY)
 #include <csnappy.h>
@@ -99,7 +104,7 @@ SRL_STATIC_INLINE UV srl_read_varint_uv_length(pTHX_ srl_decoder_t *dec, const c
 SRL_STATIC_INLINE SV *srl_fetch_item(pTHX_ srl_decoder_t *dec, UV item, const char * const tag_name);
 
 /* these three are "Public" */
-srl_decoder_t *srl_build_decoder_struct(pTHX_ HV *opt);             /* constructor - called from ->new() */
+srl_decoder_t *srl_build_decoder_struct(pTHX_ HV *opt, sv_with_hash *options);  /* constructor - called from ->new() */
 void srl_destroy_decoder(pTHX_ srl_decoder_t *dec);                 /* destructor  - called from ->DESTROY() */
 void srl_decoder_destructor_hook(pTHX_ void *p);                    /* destructor hook - called automagically */
 
@@ -107,9 +112,7 @@ void srl_decoder_destructor_hook(pTHX_ void *p);                    /* destructo
 /* srl_begin_decoding: set up the decoder to handle a given var */
 SRL_STATIC_INLINE srl_decoder_t *srl_begin_decoding(pTHX_ srl_decoder_t *dec, SV *src, UV start_offset);
 SRL_STATIC_INLINE void srl_read_header(pTHX_ srl_decoder_t *dec, SV *header_user_data); /* read/validate header */
-SRL_STATIC_INLINE void srl_read_single_value(pTHX_ srl_decoder_t *dec, SV* into);   /* main recursive dump routine */
-SRL_STATIC_INLINE void srl_read_single_value_into_container(pTHX_ srl_decoder_t *dec,
-        SV** container);   /* wrapper for main recursive dump routine for handling aliasing  */
+SRL_STATIC_INLINE void srl_read_single_value(pTHX_ srl_decoder_t *dec, SV* into, SV** container); /* main recursive dump routine */
 SRL_STATIC_INLINE void srl_finalize_structure(pTHX_ srl_decoder_t *dec);             /* optional finalize structure logic */
 SRL_STATIC_INLINE void srl_clear_decoder(pTHX_ srl_decoder_t *dec);                 /* clean up decoder after a dump */
 SRL_STATIC_INLINE void srl_clear_decoder_body_state(pTHX_ srl_decoder_t *dec);      /* clean up after each document body */
@@ -132,23 +135,31 @@ SRL_STATIC_INLINE void srl_read_long_double(pTHX_ srl_decoder_t *dec, SV* into);
 SRL_STATIC_INLINE void srl_read_double(pTHX_ srl_decoder_t *dec, SV* into);
 SRL_STATIC_INLINE void srl_read_float(pTHX_ srl_decoder_t *dec, SV* into);
 SRL_STATIC_INLINE void srl_read_string(pTHX_ srl_decoder_t *dec, int is_utf8, SV* into);
-SRL_STATIC_INLINE void srl_read_varint(pTHX_ srl_decoder_t *dec, SV* into);
-SRL_STATIC_INLINE void srl_read_zigzag(pTHX_ srl_decoder_t *dec, SV* into);
+SRL_STATIC_INLINE void srl_read_varint_into(pTHX_ srl_decoder_t *dec, SV* into, SV** container);
+SRL_STATIC_INLINE void srl_read_zigzag_into(pTHX_ srl_decoder_t *dec, SV* into, SV** container);
 SRL_STATIC_INLINE void srl_read_reserved(pTHX_ srl_decoder_t *dec, U8 tag, SV* into);
 SRL_STATIC_INLINE void srl_read_object(pTHX_ srl_decoder_t *dec, SV* into, U8 obj_tag);
 SRL_STATIC_INLINE void srl_read_objectv(pTHX_ srl_decoder_t *dec, SV* into, U8 obj_tag);
 
-SRL_STATIC_INLINE void srl_track_sv(pTHX_ srl_decoder_t *dec, U8 *track_pos, SV *sv);
+SRL_STATIC_INLINE void srl_track_sv(pTHX_ srl_decoder_t *dec, const U8 *track_pos, SV *sv);
 SRL_STATIC_INLINE void srl_read_frozen_object(pTHX_ srl_decoder_t *dec, HV *class_stash, SV *into);
 
 /* FIXME unimplemented!!! */
 SRL_STATIC_INLINE SV *srl_read_extend(pTHX_ srl_decoder_t *dec, SV* into);
 
+#define DEPTH_INCREMENT(dec) STMT_START {                                           \
+    if (expect_false(++dec->recursion_depth > dec->max_recursion_depth)) {                        \
+            SRL_ERRORf1("Reached recursion limit (%"UVuf") during deserialization",     \
+            (UV)dec->max_recursion_depth);                               \
+    }                                                                               \
+} STMT_END
+
+#define DEPTH_DECREMENT(dec) dec->recursion_depth--
 
 #define ASSERT_BUF_SPACE(dec,len,msg) STMT_START {                  \
     if (expect_false( (UV)BUF_SPACE((dec)) < (UV)(len) )) {         \
         SRL_ERRORf3("Unexpected termination of packet%s, "          \
-                    "want %lu bytes, only have %lu available",      \
+                    "want %"UVuf" bytes, only have %"UVuf" available",      \
                     (msg), (UV)(len), (UV)BUF_SPACE((dec)));        \
     }                                                               \
 } STMT_END
@@ -171,27 +182,35 @@ STATIC void
 srl_ptable_debug_callback(PTABLE_ENTRY_t *e)
 {
     dTHX;
-    printf("KEY=%lu\nVALUE:\n", (unsigned long)e->key);
+    printf("KEY=%"UVuf"\nVALUE:\n", (UV)e->key);
     sv_dump((SV *)e->value);
     printf("\n");
 }
 
-STATIC void
+SRL_STATIC_INLINE void
 srl_ptable_debug_dump(pTHX_ PTABLE_t *tbl)
 {
     PTABLE_debug_dump(tbl, srl_ptable_debug_callback);
 }
 
+#define my_hv_fetchs(he,val,opt,idx) STMT_START {                   \
+    he = hv_fetch_ent(opt, options[idx].sv, 0, options[idx].hash);  \
+    if (he)                                                         \
+        val= HeVAL(he);                                             \
+    else                                                            \
+        val= NULL;                                                  \
+} STMT_END
 
 /* PUBLIC ROUTINES */
 
 /* Builds the C-level configuration and state struct.
  * Automatically freed at scope boundary. */
 srl_decoder_t *
-srl_build_decoder_struct(pTHX_ HV *opt)
+srl_build_decoder_struct(pTHX_ HV *opt, sv_with_hash *options)
 {
     srl_decoder_t *dec;
-    SV **svp;
+    SV *val;
+    HE *he;
 
     Newxz(dec, 1, srl_decoder_t);
 
@@ -201,28 +220,36 @@ srl_build_decoder_struct(pTHX_ HV *opt)
 
     /* load options */
     if (opt != NULL) {
-        if ( (svp = hv_fetchs(opt, "refuse_snappy", 0)) && SvTRUE(*svp))
+        my_hv_fetchs(he,val,opt, SRL_DEC_OPT_IDX_REFUSE_SNAPPY);
+        if ( val && SvTRUE(val) )
             SRL_DEC_SET_OPTION(dec, SRL_F_DECODER_REFUSE_SNAPPY);
 
-        if ( (svp = hv_fetchs(opt, "refuse_zlib", 0)) && SvTRUE(*svp))
+        my_hv_fetchs(he,val,opt, SRL_DEC_OPT_IDX_REFUSE_ZLIB);
+        if ( val && SvTRUE(val) )
             SRL_DEC_SET_OPTION(dec, SRL_F_DECODER_REFUSE_ZLIB);
 
-        if ( (svp = hv_fetchs(opt, "refuse_objects", 0)) && SvTRUE(*svp))
+        my_hv_fetchs(he,val,opt, SRL_DEC_OPT_IDX_REFUSE_OBJECTS);
+        if ( val && SvTRUE(val) )
             SRL_DEC_SET_OPTION(dec, SRL_F_DECODER_REFUSE_OBJECTS);
 
-        if ( (svp = hv_fetchs(opt, "no_bless_objects", 0)) && SvTRUE(*svp))
+        my_hv_fetchs(he,val,opt, SRL_DEC_OPT_IDX_NO_BLESS_OBJECTS);
+        if ( val && SvTRUE(val) )
             SRL_DEC_SET_OPTION(dec, SRL_F_DECODER_NO_BLESS_OBJECTS);
 
-        if ( (svp = hv_fetchs(opt, "validate_utf8", 0)) && SvTRUE(*svp))
+        my_hv_fetchs(he,val,opt, SRL_DEC_OPT_IDX_VALIDATE_UTF8);
+        if ( val && SvTRUE(val) )
             SRL_DEC_SET_OPTION(dec, SRL_F_DECODER_VALIDATE_UTF8);
 
-        if ( (svp = hv_fetchs(opt, "max_recursion_depth", 0)) && SvTRUE(*svp))
-            dec->max_recursion_depth = SvUV(*svp);
+        my_hv_fetchs(he,val,opt, SRL_DEC_OPT_IDX_MAX_RECURSION_DEPTH);
+        if ( val && SvTRUE(val) )
+            dec->max_recursion_depth = SvUV(val);
 
-        if ( (svp = hv_fetchs(opt, "max_num_hash_entries", 0)) && SvTRUE(*svp))
-            dec->max_num_hash_entries = SvUV(*svp);
+        my_hv_fetchs(he,val,opt, SRL_DEC_OPT_IDX_MAX_NUM_HASH_ENTRIES);
+        if ( val && SvTRUE(val) )
+            dec->max_num_hash_entries = SvUV(val);
 
-        if ( (svp = hv_fetchs(opt, "incremental", 0)) && SvTRUE(*svp))
+        my_hv_fetchs(he,val,opt, SRL_DEC_OPT_IDX_DESTRUCTIVE_INCREMENTAL);
+        if ( val && SvTRUE(val) )
             SRL_DEC_SET_OPTION(dec,SRL_F_DECODER_DESTRUCTIVE_INCREMENTAL);
 
         /* see if they want us to alias varints, value is an unsigned integer.
@@ -230,21 +257,37 @@ srl_build_decoder_struct(pTHX_ HV *opt)
          * using the "alias_smallint" option. Setting it to a true value larger
          * than 15 enables aliasing of smallints, and implies "alias_smallint" as
          * well. */
-        if ( (svp = hv_fetchs(opt, "alias_varint_under", 0)) && SvTRUE(*svp)) {
+        my_hv_fetchs(he,val,opt, SRL_DEC_OPT_IDX_ALIAS_VARINT_UNDER);
+        if ( val && SvTRUE(val)) {
             /* if they use this then they automatically imply doing it for
              * smallint as well */
             SRL_DEC_SET_OPTION(dec,SRL_F_DECODER_ALIAS_SMALLINT);
             SRL_DEC_SET_OPTION(dec,SRL_F_DECODER_ALIAS_VARINT);
-            if (SvUV(*svp) < 16) {
+            if (SvUV(val) < 16) {
                 /* too small, just enable for SMALLINT (POS/NEG)*/
                 dec->alias_varint_under= 16;
             } else {
                 /* larger than POS/NEG range, also alias some VARINTs */
                 /* anything smaller than this number will be aliased */
-                dec->alias_varint_under= SvUV(*svp);
+                dec->alias_varint_under= SvUV(val);
             }
             /* create the alias cache */
             dec->alias_cache= newAV();
+        }
+        /* they can enable aliasing of SMALLINT's alone */
+        if ( !SRL_DEC_HAVE_OPTION(dec,SRL_F_DECODER_ALIAS_SMALLINT) ) {
+            my_hv_fetchs(he,val,opt, SRL_DEC_OPT_IDX_ALIAS_SMALLINT);
+            if (val && SvTRUE(val))
+            {
+                /* set the flag */
+                SRL_DEC_SET_OPTION(dec,SRL_F_DECODER_ALIAS_SMALLINT);
+                /* create the alias cache */
+                dec->alias_cache= newAV();
+                dec->alias_varint_under=16;
+            }
+        }
+
+        if (dec->alias_varint_under) {
             /* extend it to the right size 16 for NEG,
              * dec->alias_varint_under is at least 15, and 1 more for zero,
              * so we allocate enough for POS/NEG as well as for the additional varints*/
@@ -252,33 +295,26 @@ srl_build_decoder_struct(pTHX_ HV *opt)
             AvFILLp(dec->alias_cache)= 16 + dec->alias_varint_under - 1; /* remove 1 as this is $#ary */
         }
 
-        /* they can enable aliasing of SMALLINT's alone */
-        if ( !SRL_DEC_HAVE_OPTION(dec,SRL_F_DECODER_ALIAS_SMALLINT) &&
-             (svp = hv_fetchs(opt, "alias_smallint", 0)) && SvTRUE(*svp)
-        ) {
-            /* set the flag */
-            SRL_DEC_SET_OPTION(dec,SRL_F_DECODER_ALIAS_SMALLINT);
-            /* create the alias cache */
-            dec->alias_cache= newAV();
-            /* extend it to the right size of 32 items */
-            av_extend(dec->alias_cache,32);
-            AvFILLp(dec->alias_cache)= 31; /* $#ary == 32 */
-        }
         /* check if they want us to use &PL_sv_undef for SRL_HEADER_UNDEF
          * even if this might break referential integrity. */
-        if ( (svp = hv_fetchs(opt, "use_undef", 0)) && SvTRUE(*svp))
+        my_hv_fetchs(he,val,opt, SRL_DEC_OPT_IDX_USE_UNDEF);
+        if ( val && SvTRUE(val))
             SRL_DEC_SET_OPTION(dec,SRL_F_DECODER_USE_UNDEF);
 
         /* check if they want us to set all SVs readonly. */
-        if ( (svp = hv_fetchs(opt, "set_readonly", 0)) && SvTRUE(*svp))
+        my_hv_fetchs(he,val,opt, SRL_DEC_OPT_IDX_SET_READONLY);
+        if ( val && SvTRUE(val))
             SRL_DEC_SET_OPTION(dec, SRL_F_DECODER_SET_READONLY);
 
         /* check if they want us to set normal scalars readonly. */
-        if ( (svp = hv_fetchs(opt, "set_readonly_scalars", 0)) && SvTRUE(*svp))
+        my_hv_fetchs(he,val,opt, SRL_DEC_OPT_IDX_SET_READONLY_SCALARS);
+        if ( val && SvTRUE(val))
             SRL_DEC_SET_OPTION(dec, SRL_F_DECODER_SET_READONLY_SCALARS);
 
     }
-
+    dec->flags_readonly= SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_SET_READONLY ) ? 1 :
+                         SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_SET_READONLY_SCALARS) ? 2 :
+                         0;
     return dec;
 }
 
@@ -376,7 +412,7 @@ SRL_STATIC_INLINE void
 srl_decompress_body_snappy(pTHX_ srl_decoder_t *dec)
 {
     uint32_t dest_len;
-    unsigned char *old_pos;
+    const unsigned char *old_pos;
     const ptrdiff_t sereal_header_len = dec->pos - dec->buf_start;
     const STRLEN compressed_packet_len =
         dec->encoding_flags == SRL_PROTOCOL_ENCODING_SNAPPY_INCREMENTAL
@@ -417,7 +453,7 @@ srl_decompress_body_snappy(pTHX_ srl_decoder_t *dec)
 SRL_STATIC_INLINE void
 srl_decompress_body_zlib(pTHX_ srl_decoder_t *dec)
 {
-    unsigned char *old_pos;
+    const unsigned char *old_pos;
     const ptrdiff_t sereal_header_len = dec->pos - dec->buf_start;
     const STRLEN uncompressed_packet_len = (STRLEN)srl_read_varint_uv(aTHX_ dec);
     const STRLEN compressed_packet_len =
@@ -469,7 +505,7 @@ srl_decode_into_internal(pTHX_ srl_decoder_t *origdec, SV *src, SV *header_into,
     }
 
     /* The actual document body deserialization: */
-    srl_read_single_value(aTHX_ dec, body_into);
+    srl_read_single_value(aTHX_ dec, body_into, NULL);
     if (expect_false(SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_NEEDS_FINALIZE))) {
         srl_finalize_structure(aTHX_ dec);
     }
@@ -504,13 +540,20 @@ srl_decode_header_into(pTHX_ srl_decoder_t *origdec, SV *src, SV* header_into, U
     return header_into;
 }
 
+/* this SHOULD be newSV_type(SVt_NULL) but newSV(0) is faster :-( */
+#if 1
+#define FRESH_SV() newSV(0)
+#else
+#define FRESH_SV() newSV_type(SVt_NULL);
+#endif
+
 /* This is the main routine to deserialize a Sereal document
  * w/o data in header. */
 SV *
 srl_decode_into(pTHX_ srl_decoder_t *dec, SV *src, SV* body_into, UV start_offset)
 {
     if (expect_true(!body_into))
-        body_into= sv_2mortal(newSV_type(SVt_NULL));
+        body_into= sv_2mortal(FRESH_SV());
     srl_decode_into_internal(aTHX_ dec, src, NULL, body_into, start_offset);
     return body_into;
 }
@@ -651,7 +694,7 @@ srl_read_header(pTHX_ srl_decoder_t *dec, SV *header_user_data)
     UV header_len;
     IV proto_version_and_encoding_flags_int= srl_validate_header_version_pv_len(aTHX_ (char *)BUF_POS(dec), BUF_SPACE(dec));
 
-    if ( proto_version_and_encoding_flags_int < 1 ) {
+    if ( expect_false(proto_version_and_encoding_flags_int < 1) ) {
         if (proto_version_and_encoding_flags_int == 0)
             SRL_ERROR("Bad Sereal header: It seems your document was accidentally UTF-8 encoded");
         else
@@ -708,7 +751,7 @@ srl_read_header(pTHX_ srl_decoder_t *dec, SV *header_user_data)
             if (bitfield & SRL_PROTOCOL_HDR_USER_DATA && header_user_data != NULL) {
                 /* Do an actual document body deserialization for the user data: */
                 SRL_UPDATE_BODY_POS(dec);
-                srl_read_single_value(aTHX_ dec, header_user_data);
+                srl_read_single_value(aTHX_ dec, header_user_data, NULL);
                 if (expect_false(SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_NEEDS_FINALIZE))) {
                     srl_finalize_structure(aTHX_ dec);
                 }
@@ -808,23 +851,52 @@ srl_read_varint_uv_safe(pTHX_ srl_decoder_t *dec)
     if (expect_true( BUF_NOT_DONE(dec) )) {
         uv |= ((UV)*dec->pos++ << lshift);
     } else {
-        SRL_ERROR("varint terminated prematurely");
+        SRL_ERROR("end of packet reached before varint parsed");
     }
     return uv;
 }
 
-#define SET_UV_FROM_VARINT(uv, from) STMT_START {       \
-    if (*from < 0x80) {                                 \
-        uv= (UV)*from++;                                \
-    } else {                                            \
-        unsigned int lshift= 7;                         \
-        uv= (UV)(*from++ & 0x7f);                       \
-        while (*from & 0x80){                           \
-            uv |= ((UV)(*from++ & 0x7F) << lshift);     \
-            lshift += 7;                                \
-        }                                               \
-        uv |= ((UV)(*from++) << lshift);                \
-    }                                                   \
+#define SET_UV_FROM_VARINT(uv, ptr) STMT_START {       \
+    U32 b;                                                                  \
+                                                                            \
+    /* Splitting into 32-bit pieces gives better performance on 32-bit      \
+       processors. */                                                       \
+    U32 part0 = 0, part1 = 0, part2 = 0;                                    \
+    do { \
+                                                                            \
+    b = *(ptr++); part0  = b      ; if (!(b & 0x80)) break;             \
+    part0 -= 0x80;                                                          \
+    b = *(ptr++); part0 += b <<  7; if (!(b & 0x80)) break;             \
+    part0 -= 0x80 << 7;                                                     \
+    b = *(ptr++); part0 += b << 14; if (!(b & 0x80)) break;             \
+    part0 -= 0x80 << 14;                                                    \
+    b = *(ptr++); part0 += b << 21; if (!(b & 0x80)) break;             \
+    part0 -= 0x80 << 21;                                                    \
+                                                                            \
+    b = *(ptr++); part1  = b      ; if (!(b & 0x80)) break;             \
+    part1 -= 0x80;                                                          \
+    b = *(ptr++); part1 += b <<  7; if (!(b & 0x80)) break;             \
+    part1 -= 0x80 << 7;                                                     \
+    b = *(ptr++); part1 += b << 14; if (!(b & 0x80)) break;             \
+    part1 -= 0x80 << 14;                                                    \
+    b = *(ptr++); part1 += b << 21; if (!(b & 0x80)) break;             \
+    part1 -= 0x80 << 21;                                                    \
+                                                                            \
+    b = *(ptr++); part2  = b      ; if (!(b & 0x80)) break;             \
+    part2 -= 0x80;                                                          \
+    b = *(ptr++); part2 += b <<  7; if (!(b & 0x80)) break;             \
+    /* "part2 -= 0x80 << 7" is irrelevant because (0x80 << 7) << 56 is 0. */\
+                                                                            \
+    /* We have overrun the maximum size of a varint (10 bytes).  The data   \
+        must be corrupt. */                                                 \
+    SRL_ERROR("varint not terminated in time, corrupt packet");             \
+                                                                            \
+    } while (0);                                                            \
+                                                                            \
+    uv= (((UV)part0)      ) |                                               \
+        (((UV)part1) << 28) |                                               \
+        (((UV)part2) << 56);                                                \
+                                                                            \
 } STMT_END
 
 SRL_STATIC_INLINE UV
@@ -844,12 +916,58 @@ srl_read_varint_uv_nocheck(pTHX_ srl_decoder_t *dec)
 }
 
 SRL_STATIC_INLINE UV
+srl_read_varint_u32_nocheck(pTHX_ srl_decoder_t *dec)
+{
+    const U8* ptr = dec->pos;
+    U32 b;
+
+    U32 part0 = 0;
+
+    b = *(ptr++); part0  = b      ; if (!(b & 0x80)) goto done;
+    part0 -= 0x80;
+    b = *(ptr++); part0 += b <<  7; if (!(b & 0x80)) goto done;
+    part0 -= 0x80 << 7;
+    b = *(ptr++); part0 += b << 14; if (!(b & 0x80)) goto done;
+    part0 -= 0x80 << 14;
+    b = *(ptr++); part0 += b << 21; if (!(b & 0x80)) goto done;
+    part0 -= 0x80 << 21;
+    b = *(ptr++); part0 += b << 28; if (b < 16) goto done;
+
+    SRL_ERROR("varint overflows U32, cannot restore packet");
+
+   done:
+    dec->pos= (U8*)ptr;
+
+    return part0;
+}
+
+SRL_STATIC_INLINE UV
+srl_read_varint_u64_nocheck(pTHX_ srl_decoder_t *dec)
+{
+    UV uv;
+    const U8* ptr = dec->pos;
+
+    SET_UV_FROM_VARINT(uv, ptr);
+
+    dec->pos= (U8*)ptr;
+
+    return uv;
+}
+
+
+
+SRL_STATIC_INLINE UV
 srl_read_varint_uv(pTHX_ srl_decoder_t *dec)
 {
-    if (expect_true( dec->buf_end - dec->pos > 10 ))
-        return srl_read_varint_uv_nocheck(aTHX_ dec);
-    else
+    if (expect_true( dec->buf_end - dec->pos >= 10 ) || (dec->buf_end[-1] & 0x80)) {
+        if (sizeof(UV)==sizeof(U32)) {
+            return srl_read_varint_u32_nocheck(aTHX_ dec);
+        } else {
+            return srl_read_varint_u64_nocheck(aTHX_ dec);
+        }
+    } else {
         return srl_read_varint_uv_safe(aTHX_ dec);
+    }
 }
 
 SRL_STATIC_INLINE UV
@@ -858,8 +976,8 @@ srl_read_varint_uv_offset(pTHX_ srl_decoder_t *dec, const char * const errstr)
     UV len= srl_read_varint_uv(aTHX_ dec);
 
     if (dec->body_pos + len >= dec->pos) {
-        SRL_ERRORf4("Corrupted packet%s. Offset %lu points past current position %lu in packet with length of %lu bytes long",
-                errstr, (unsigned long)len, (unsigned long)BUF_POS_OFS(dec), (unsigned long)dec->buf_len);
+        SRL_ERRORf4("Corrupted packet%s. Offset %"UVuf" points past current position %"UVuf" in packet with length of %"UVuf" bytes long",
+                errstr, (UV)len, (UV)BUF_POS_OFS(dec), (UV)dec->buf_len);
     }
     return len;
 }
@@ -880,14 +998,14 @@ srl_read_varint_uv_count(pTHX_ srl_decoder_t *dec, const char * const errstr)
 {
     UV len= srl_read_varint_uv(aTHX_ dec);
     if (len > I32_MAX) {
-        SRL_ERRORf3("Corrupted packet%s. Count %lu exceeds I32_MAX (%i), which is impossible.",
+        SRL_ERRORf3("Corrupted packet%s. Count %"UVuf" exceeds I32_MAX (%i), which is impossible.",
                 errstr, len, I32_MAX);
     }
     return len;
 }
 
 SRL_STATIC_INLINE void
-srl_track_thawed(srl_decoder_t *dec, U8 *track_pos, SV *sv)
+srl_track_thawed(srl_decoder_t *dec, const U8 *track_pos, SV *sv)
 {
     if (!dec->ref_thawhash)
         dec->ref_thawhash = PTABLE_new();
@@ -907,7 +1025,7 @@ srl_fetch_thawed(srl_decoder_t *dec, UV item)
 }
 
 SRL_STATIC_INLINE void
-srl_track_sv(pTHX_ srl_decoder_t *dec, U8 *track_pos, SV *sv)
+srl_track_sv(pTHX_ srl_decoder_t *dec, const U8 *track_pos, SV *sv)
 {
     PTABLE_store(dec->ref_seenhash, (void *)(track_pos - dec->body_pos), (void *)sv);
 }
@@ -919,7 +1037,7 @@ srl_fetch_item(pTHX_ srl_decoder_t *dec, UV item, const char * const tag_name)
     SV *sv= (SV *)PTABLE_fetch(dec->ref_seenhash, (void *)item);
     if (expect_false( !sv )) {
         /*srl_ptable_debug_dump(aTHX_ dec->ref_seenhash);*/
-        SRL_ERRORf2("%s(%d) references an unknown item", tag_name, (int)item);
+        SRL_ERRORf2("%s(%"UVuf") references an unknown item", tag_name, item);
     }
     return sv;
 }
@@ -927,13 +1045,72 @@ srl_fetch_item(pTHX_ srl_decoder_t *dec, UV item, const char * const tag_name)
 /****************************************************************************
  * PRIVATE WORKER SUBS FOR DEPARSING                                        *
  ****************************************************************************/
+SRL_STATIC_INLINE void
+srl_alias_iv(pTHX_ srl_decoder_t *dec, SV **container, IV iv)
+{
+    SV *alias;
+    SV **av_array= AvARRAY(dec->alias_cache);
+    U32 ofs = iv + 16; /* we always cover from -16 up so we add 16 */
+
+    assert( IS_IV_ALIAS(dec,iv) );
+
+    if (!av_array[ofs] || av_array[ofs] == &PL_sv_undef) {
+        alias= newSViv(iv);
+        /* mark it as readonly so people dont try to modify it */
+        SvREADONLY_on(alias);
+        /* store it in the alias_cache array */
+        av_array[ofs]= alias;
+    } else {
+        alias= av_array[ofs];
+    }
+
+    SvREFCNT_inc(alias);
+
+    if (*container && *container != &PL_sv_undef)
+        SvREFCNT_dec(*container);
+    *container= alias;
+}
+
+
 
 SRL_STATIC_INLINE void
-srl_read_varint(pTHX_ srl_decoder_t *dec, SV* into)
+srl_setiv(pTHX_ srl_decoder_t *dec, SV *into, SV **container, IV iv)
+{
+    if ( expect_false( container && IS_IV_ALIAS(dec,iv) )) {
+        srl_alias_iv(aTHX_ dec, container, iv);
+    } else {
+        /* unroll sv_setiv() for the SVt_NULL case, which we will
+         * see regularly - this wins about 35% speedup for us
+         * but involve gratuitious intimacy with the internals.
+         * */
+#ifdef FAST_IV
+        if ( SvTYPE(into) == SVt_NULL ) {
+            /* XXX: dont need to do this, we are null already */
+            /* SvFLAGS(into) &= ~SVTYPEMASK; */
+            assert(
+                (SVt_NULL == 0) &&
+                ((SvFLAGS(into) & (SVTYPEMASK|SVf_OOK|SVf_OK|SVf_IVisUV|SVf_UTF8)) == 0)
+            );
+            SvANY(into) = (XPVIV*)((char*)&(into->sv_u.svu_iv) - STRUCT_OFFSET(XPVIV, xiv_iv));
+            /* replace this: */
+            /* SvIOK_only(into); */
+            /* with this: */
+            SvFLAGS(into) |= (SVt_IV | SVf_IOK | SVp_IOK);
+            SvIV_set(into, iv);
+        } else
+#endif
+        {
+            sv_setiv(into, iv);
+        }
+    }
+}
+
+SRL_STATIC_INLINE void
+srl_read_varint_into(pTHX_ srl_decoder_t *dec, SV* into, SV **container)
 {
     UV uv= srl_read_varint_uv(aTHX_ dec);
-    if (uv <= (UV)IV_MAX) {
-        sv_setiv(into, (IV)uv);
+    if (expect_true(uv <= (UV)IV_MAX)) {
+        srl_setiv(aTHX_ dec, into, container, (IV)uv);
     } else {
         /* grr, this is ridiculous! */
         sv_setiv(into, 0);
@@ -943,12 +1120,18 @@ srl_read_varint(pTHX_ srl_decoder_t *dec, SV* into)
 }
 
 
-SRL_STATIC_INLINE void
-srl_read_zigzag(pTHX_ srl_decoder_t *dec, SV* into)
+SRL_STATIC_INLINE IV
+srl_read_zigzag_iv(pTHX_ srl_decoder_t *dec)
 {
     UV n= srl_read_varint_uv(aTHX_ dec);
     IV i= (n >> 1) ^ (-(n & 1));
-    sv_setiv(into, i);
+    return i;
+}
+
+SRL_STATIC_INLINE void
+srl_read_zigzag_into(pTHX_ srl_decoder_t *dec, SV* into, SV **container)
+{
+    srl_setiv(aTHX_ dec, into, container, srl_read_zigzag_iv(aTHX_ dec));
 }
 
 
@@ -956,7 +1139,7 @@ SRL_STATIC_INLINE void
 srl_read_string(pTHX_ srl_decoder_t *dec, int is_utf8, SV* into)
 {
     UV len= srl_read_varint_uv_length(aTHX_ dec, " while reading string");
-    if (is_utf8 && SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_VALIDATE_UTF8)) {
+    if (expect_false(is_utf8 && SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_VALIDATE_UTF8))) {
         /* checks for invalid byte sequences. */
         if (expect_false( !is_utf8_string((U8*)dec->pos, len) )) {
             SRL_ERROR("Invalid UTF8 byte sequence");
@@ -1037,6 +1220,7 @@ srl_read_array(pTHX_ srl_decoder_t *dec, SV *into, U8 tag) {
         len= tag & 15;
         SRL_sv_set_rv_to(into, referent);
         into= referent;
+        DEPTH_INCREMENT(dec);
     } else {
         len= srl_read_varint_uv_count(aTHX_ dec," while reading ARRAY");
         (void)SvUPGRADE(into, SVt_PVAV);
@@ -1057,9 +1241,12 @@ srl_read_array(pTHX_ srl_decoder_t *dec, SV *into, U8 tag) {
         av_end= av_array + len;
 
         for ( ; av_array < av_end ; av_array++) {
-            srl_read_single_value_into_container(aTHX_ dec, av_array);
+            *av_array = FRESH_SV();
+            srl_read_single_value(aTHX_ dec, *av_array, av_array);
         }
     }
+    if (tag)
+        DEPTH_DECREMENT(dec);
 }
 
 #ifndef HV_FETCH_LVALUE
@@ -1067,6 +1254,10 @@ srl_read_array(pTHX_ srl_decoder_t *dec, SV *into, U8 tag) {
 #define IS_LVALUE 1
 #endif
 
+#ifndef HvRITER_set
+#define HvRITER_set(sv,v) HvRITER(sv) = v
+#endif
+
 SRL_STATIC_INLINE void
 srl_read_hash(pTHX_ srl_decoder_t *dec, SV* into, U8 tag) {
     UV num_keys;
@@ -1075,6 +1266,7 @@ srl_read_hash(pTHX_ srl_decoder_t *dec, SV* into, U8 tag) {
         num_keys= tag & 15;
         SRL_sv_set_rv_to(into, referent);
         into= referent;
+        DEPTH_INCREMENT(dec);
     } else {
         num_keys= srl_read_varint_uv_count(aTHX_ dec," while reading HASH");
         (void)SvUPGRADE(into, SVt_PVHV);
@@ -1082,11 +1274,7 @@ srl_read_hash(pTHX_ srl_decoder_t *dec, SV* into, U8 tag) {
     /* in some versions of Perl HvRITER() is not properly set on an upgrade SV
      * so we explicitly set it ourselves */
 #ifdef FIXUP_RITER
-#ifdef HvRITER_set
     HvRITER_set(into,-1);
-#else
-    HvRITER(into)= -1;
-#endif
 #endif
 
     /* Limit the maximum number of hash keys that we accept to whetever was configured */
@@ -1103,7 +1291,7 @@ srl_read_hash(pTHX_ srl_decoder_t *dec, SV* into, U8 tag) {
     /* NOTE: contents of hash are stored VALUE/KEY, reverse from normal perl
      * storage, this is because it simplifies the hash storage logic somewhat */
     for (; num_keys > 0 ; num_keys--) {
-        U8 *from;
+        const U8 *from;
         U8 tag;
         SV **fetched_sv;
         I32 key_len;
@@ -1166,8 +1354,10 @@ srl_read_hash(pTHX_ srl_decoder_t *dec, SV* into, U8 tag) {
         if (expect_false( !fetched_sv )) {
             SRL_ERROR_PANIC(dec,"failed to hv_store");
         }
-        srl_read_single_value_into_container(aTHX_ dec, fetched_sv);
+        srl_read_single_value(aTHX_ dec, *fetched_sv, fetched_sv );
     }
+    if (tag)
+        DEPTH_DECREMENT(dec);
 }
 
 
@@ -1203,13 +1393,16 @@ srl_read_refn(pTHX_ srl_decoder_t *dec, SV* into)
         referent= &PL_sv_undef;
     }
     else {
-        referent= newSV(SVt_NULL);
+        referent= FRESH_SV();
         SvTEMP_off(referent);
         tag = 0;
     }
     SRL_sv_set_rv_to(into, referent);
-    if (!tag)
-        srl_read_single_value(aTHX_ dec, referent);
+    if (!tag) {
+        DEPTH_INCREMENT(dec);
+        srl_read_single_value(aTHX_ dec, referent, NULL);
+        DEPTH_DECREMENT(dec);
+    }
 }
 
 SRL_STATIC_INLINE void
@@ -1245,7 +1438,7 @@ srl_read_weaken(pTHX_ srl_decoder_t *dec, SV* into)
     SV* referent;
     /* TODO This really just wants a subset of the states that srl_read_single_value covers, right?
      *      Optimization opportunity? Or robustness against invalid packets issue? */
-    srl_read_single_value(aTHX_ dec, into);
+    srl_read_single_value(aTHX_ dec, into, NULL);
     if (expect_false( !SvROK(into) ))
         SRL_ERROR("WEAKEN op");
     referent= SvRV(into);
@@ -1283,7 +1476,7 @@ srl_read_objectv(pTHX_ srl_decoder_t *dec, SV* into, U8 obj_tag)
                   "preceding OBJECT(_FREEZE) to define classname");
     av= (AV *)PTABLE_fetch(dec->ref_bless_av, (void *)ofs);
     if (expect_false( NULL == av )) {
-        SRL_ERRORf1("Corrupted packet. OBJECTV(_FREEZE) references unknown classname offset: %lu", (unsigned long)ofs);
+        SRL_ERRORf1("Corrupted packet. OBJECTV(_FREEZE) references unknown classname offset: %"UVuf, (UV)ofs);
     }
 
     /* checking tag: SRL_HDR_OBJECTV_FREEZE or SRL_HDR_OBJECTV? */
@@ -1296,7 +1489,7 @@ srl_read_objectv(pTHX_ srl_decoder_t *dec, SV* into, U8 obj_tag)
     }  else {
         /* SRL_HDR_OBJECTV, not SRL_HDR_OBJECTV_FREEZE */
         /* now deparse the thing we are going to bless */
-        srl_read_single_value(aTHX_ dec, into);
+        srl_read_single_value(aTHX_ dec, into, NULL);
 
         /* and also stuff it into the av - we dont have to do any more book-keeping */
         av_push(av, SvREFCNT_inc(into));
@@ -1325,7 +1518,7 @@ srl_read_object(pTHX_ srl_decoder_t *dec, SV* into, U8 obj_tag)
     I32 flags= GV_ADD;
     U8 tag;
     U32 key_len = 0;
-    U8 *from = NULL;
+    const U8 *from = NULL;
 
     if (expect_false( SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_REFUSE_OBJECTS) ))
         SRL_ERROR_REFUSE_OBJECT();
@@ -1414,7 +1607,7 @@ srl_read_object(pTHX_ srl_decoder_t *dec, SV* into, U8 obj_tag)
         /* we have a class stash so we should have a ref_bless_av as well. */
         av= (AV *)PTABLE_fetch(dec->ref_bless_av, (void *)storepos);
         if ( !av )
-            SRL_ERRORf1("Panic, no ref_bless_av for %lu", (unsigned long)storepos);
+            SRL_ERRORf1("Panic, no ref_bless_av for %"UVuf, (UV)storepos);
     }
 
     if (expect_false( obj_tag == SRL_HDR_OBJECT_FREEZE )) {
@@ -1429,7 +1622,7 @@ srl_read_object(pTHX_ srl_decoder_t *dec, SV* into, U8 obj_tag)
         av_push(av, SvREFCNT_inc(into));
 
         /* now deparse the thing we are going to bless */
-        srl_read_single_value(aTHX_ dec, into);
+        srl_read_single_value(aTHX_ dec, into, NULL);
 
 #if USE_588_WORKAROUND
         /* See 'define USE_588_WORKAROUND' above for a discussion of what this does. */
@@ -1459,12 +1652,12 @@ srl_read_frozen_object(pTHX_ srl_decoder_t *dec, HV *class_stash, SV *into)
      * that representation in the refs hash.
      */
 
-    unsigned char *fixup_pos= dec->pos + 1; /* get the tag for the WHATEVER */
+    const unsigned char *fixup_pos= dec->pos + 1; /* get the tag for the WHATEVER */
 
     if (expect_false( method == NULL ))
         SRL_ERRORf1("No THAW method defined for class '%s'", HvNAME(class_stash));
 
-    srl_read_single_value(aTHX_ dec, into);
+    srl_read_single_value(aTHX_ dec, into, NULL);
 
     /* Assert that we got a top level array ref as the spec requires.
      * Not throwing an exception here violates expectations down the line and
@@ -1559,8 +1752,8 @@ srl_read_reserved(pTHX_ srl_decoder_t *dec, U8 tag, SV* into)
 SRL_STATIC_INLINE void
 srl_read_regexp(pTHX_ srl_decoder_t *dec, SV* into)
 {
-    SV *sv_pat= newSV_type(SVt_NULL);
-    srl_read_single_value(aTHX_ dec, sv_pat);
+    SV *sv_pat= FRESH_SV();
+    srl_read_single_value(aTHX_ dec, sv_pat, NULL);
     ASSERT_BUF_SPACE(dec, 1, " while reading regexp modifer tag");
     /* For now we will serialize the flags as ascii strings. Maybe we should use
      * something else but this is easy to debug and understand - since the modifiers
@@ -1682,198 +1875,126 @@ srl_read_copy(pTHX_ srl_decoder_t *dec, SV* into)
     }
     dec->save_pos= dec->pos;
     dec->pos= dec->body_pos + item;
-    srl_read_single_value(aTHX_ dec, into);
+    srl_read_single_value(aTHX_ dec, into, NULL);
     dec->pos= dec->save_pos;
     dec->save_pos= 0;
 }
 
 
-SRL_STATIC_INLINE void
-srl_read_single_value_into_container(pTHX_ srl_decoder_t *dec, SV** container)
-{
-    SV *alias;
-    U32 item;
-    IV iv;
-    U8 tag = *dec->pos;
-    U8 *tag_start= dec->pos;
-
-    /* it helps to think of this somewhat like a switch, except it does
-     * more complicated checks than a single integer expression lookup */
-
-    if (expect_false( tag == SRL_HDR_ALIAS )) {
-        dec->pos++;
-        item= srl_read_varint_uv_offset(aTHX_ dec," while reading ALIAS tag");
-        alias= srl_fetch_item(aTHX_ dec, item, "ALIAS");
-        /* jump forward to the shared aliasing logic */
-        goto do_refcnt_inc_alias;
-    }
-    else
-    if (
-        SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_ALIAS_CHECK_FLAGS)
-    ) {
-
-        if (
-            SRL_DEC_HAVE_OPTION(dec,SRL_F_DECODER_USE_UNDEF) &&
-            tag == SRL_HDR_UNDEF
-        ) {
-            dec->pos++;
-            alias= &PL_sv_undef;
-            /* jump forward to the shared aliasing logic */
-            goto do_alias;
-        }
-        else
-        if (
-            SRL_DEC_HAVE_OPTION(dec,SRL_F_DECODER_ALIAS_SMALLINT) &&
-            tag <= SRL_HDR_NEG_HIGH
-        ) {
-            dec->pos++;
-            if ( tag <= SRL_HDR_POS_HIGH ) {
-                iv= tag;
-            } else {
-                /* must be a SRL_HDR_NEG tag, subtract 32 to get real value */
-                iv= tag - 32;
-            }
-            /* jump forward to the shared iv caching logic */
-            goto do_aliased_iv;
-        }
-        else
-        if (
-            SRL_DEC_HAVE_OPTION(dec,SRL_F_DECODER_ALIAS_VARINT) &&
-            tag == SRL_HDR_VARINT
-        ) {
-            dec->pos++;
-            item= srl_read_varint_uv(aTHX_ dec);
-            if ( item < dec->alias_varint_under ) {
-                iv= (IV)item;
-
-              do_aliased_iv:
-                item = iv + 16; /* we always cover from -16 up so we add 16 */
-                if (!AvARRAY(dec->alias_cache)[item] || AvARRAY(dec->alias_cache)[item] == &PL_sv_undef) {
-                    alias= newSViv(iv);
-                    /* mark it as readonly so people dont try to modify it */
-                    SvREADONLY_on(alias);
-                    /* store it in the alias_cache array */
-                    AvARRAY(dec->alias_cache)[item]= alias;
-                } else {
-                    alias= AvARRAY(dec->alias_cache)[item];
-                }
-
-              do_refcnt_inc_alias:
-                SvREFCNT_inc(alias);
-
-              do_alias:
-                if (*container && *container != &PL_sv_undef)
-                    SvREFCNT_dec(*container);
-                *container= alias;
-                return;
-            }
-            else {
-                /* reset parse pointer and fallthrough */
-                dec->pos= tag_start;
-            }
-        }
-    }
-    if (!*container || *container == &PL_sv_undef)
-        *container = newSV_type(SVt_NULL);
-    srl_read_single_value(aTHX_ dec, *container);
-    return;
-}
 
 /****************************************************************************
  * MAIN DISPATCH SUB - ALL ROADS LEAD HERE                                  *
  ****************************************************************************/
 
+
 SRL_STATIC_INLINE void
-srl_read_single_value(pTHX_ srl_decoder_t *dec, SV* into)
+srl_read_single_value(pTHX_ srl_decoder_t *dec, SV* into, SV** container)
 {
     STRLEN len;
     U8 tag;
     int is_ref = 0;
-    if (++dec->recursion_depth > dec->max_recursion_depth) {
-        SRL_ERRORf1("Reached recursion limit (%lu) during deserialization",
-                (unsigned long)dec->max_recursion_depth);
-    }
 
   read_again:
     if (expect_false( BUF_DONE(dec) ))
         SRL_ERROR("unexpected end of input stream while expecting a single value");
 
-    tag= *dec->pos;
-    if (expect_false(tag & SRL_HDR_TRACK_FLAG)) {
-        tag= tag & ~SRL_HDR_TRACK_FLAG;
-        srl_track_sv(aTHX_ dec, dec->pos, into);
-    }
-    dec->pos++;
+    tag= *dec->pos++;
 
-    if ( tag <= SRL_HDR_POS_HIGH ) {
-        sv_setiv(into, tag); /* it will fit in an iv and they are faster */
-    }
-    else
-    if ( tag <= SRL_HDR_NEG_HIGH) {
-        sv_setiv(into, (IV)(tag - 32));
-    }
-    else
-    if ( IS_SRL_HDR_SHORT_BINARY(tag) ) {
-        len= (STRLEN)SRL_HDR_SHORT_BINARY_LEN_FROM_TAG(tag);
-        ASSERT_BUF_SPACE(dec, len, " while reading ascii string");
-        sv_setpvn(into,(char*)dec->pos,len);
-        dec->pos += len;
-    }
-    else
-    if ( IS_SRL_HDR_HASHREF(tag) ) {
-        srl_read_hash(aTHX_ dec, into, tag);
-        is_ref = 1;
-    }
-    else
-    if ( IS_SRL_HDR_ARRAYREF(tag) ) {
-        srl_read_array(aTHX_ dec, into, tag);
-        is_ref = 1;
-    }
-    else {
-        switch (tag) {
-            case SRL_HDR_VARINT:        srl_read_varint(aTHX_ dec, into);                 break;
-            case SRL_HDR_ZIGZAG:        srl_read_zigzag(aTHX_ dec, into);                 break;
-
-            case SRL_HDR_FLOAT:         srl_read_float(aTHX_ dec, into);                  break;
-            case SRL_HDR_DOUBLE:        srl_read_double(aTHX_ dec, into);                 break;
-            case SRL_HDR_LONG_DOUBLE:   srl_read_long_double(aTHX_ dec, into);            break;
-
-            case SRL_HDR_TRUE:          sv_setsv(into, &PL_sv_yes);                       break;
-            case SRL_HDR_FALSE:         sv_setsv(into, &PL_sv_no);                        break;
-            case SRL_HDR_CANONICAL_UNDEF: /* fallthrough */
-            case SRL_HDR_UNDEF:         sv_setsv(into, &PL_sv_undef);                     break;
-            case SRL_HDR_BINARY:        srl_read_string(aTHX_ dec, 0, into);              break;
-            case SRL_HDR_STR_UTF8:      srl_read_string(aTHX_ dec, 1, into);              break;
-
-            case SRL_HDR_WEAKEN:        srl_read_weaken(aTHX_ dec, into);       is_ref=1; break;
-            case SRL_HDR_REFN:          srl_read_refn(aTHX_ dec, into);         is_ref=1; break;
-            case SRL_HDR_REFP:          srl_read_refp(aTHX_ dec, into);         is_ref=1; break;
-            case SRL_HDR_OBJECT_FREEZE:
-            case SRL_HDR_OBJECT:        srl_read_object(aTHX_ dec, into, tag);  is_ref=1; break;
-            case SRL_HDR_OBJECTV_FREEZE:
-            case SRL_HDR_OBJECTV:       srl_read_objectv(aTHX_ dec, into, tag); is_ref=1; break;
-            case SRL_HDR_COPY:          srl_read_copy(aTHX_ dec, into);                   break;
-            case SRL_HDR_EXTEND:        srl_read_extend(aTHX_ dec, into);                 break;
-            case SRL_HDR_HASH:          srl_read_hash(aTHX_ dec, into, 0);                break;
-            case SRL_HDR_ARRAY:         srl_read_array(aTHX_ dec, into, 0);               break;
-            case SRL_HDR_REGEXP:        srl_read_regexp(aTHX_ dec, into);                 break;
-
-            case SRL_HDR_PAD:           /* no op */
-                while (BUF_NOT_DONE(dec) && *dec->pos == SRL_HDR_PAD)
-                    dec->pos++;
-                goto read_again;
+  read_tag:
+    switch (tag) {
+        CASE_SRL_HDR_POS:
+            srl_setiv(aTHX_ dec, into, container, (IV)tag);
             break;
-            default:
-                SRL_ERROR_UNEXPECTED(dec,tag, " single value");
+        CASE_SRL_HDR_NEG:
+            srl_setiv(aTHX_ dec, into, container, (IV)(tag - 32));
             break;
+        CASE_SRL_HDR_SHORT_BINARY:
+            len= (STRLEN)SRL_HDR_SHORT_BINARY_LEN_FROM_TAG(tag);
+            ASSERT_BUF_SPACE(dec, len, " while reading ascii string");
+            sv_setpvn(into,(char*)dec->pos,len);
+            dec->pos += len;
+            break;
+        CASE_SRL_HDR_HASHREF:       srl_read_hash(aTHX_ dec, into, tag);  is_ref = 1; break;
+        CASE_SRL_HDR_ARRAYREF:      srl_read_array(aTHX_ dec, into, tag); is_ref = 1; break;
+        case SRL_HDR_VARINT:        srl_read_varint_into(aTHX_ dec, into, container); break;
+        case SRL_HDR_ZIGZAG:        srl_read_zigzag_into(aTHX_ dec, into, container); break;
+
+        case SRL_HDR_FLOAT:         srl_read_float(aTHX_ dec, into);                  break;
+        case SRL_HDR_DOUBLE:        srl_read_double(aTHX_ dec, into);                 break;
+        case SRL_HDR_LONG_DOUBLE:   srl_read_long_double(aTHX_ dec, into);            break;
+
+        case SRL_HDR_TRUE:          sv_setsv(into, &PL_sv_yes);                       break;
+        case SRL_HDR_FALSE:         sv_setsv(into, &PL_sv_no);                        break;
+
+        case SRL_HDR_CANONICAL_UNDEF: /* fallthrough (XXX: is this right?)*/
+        case SRL_HDR_UNDEF:
+        {
+            if (container && SRL_DEC_HAVE_OPTION(dec,SRL_F_DECODER_USE_UNDEF)){
+                SvREFCNT_dec(into);
+                *container= &PL_sv_undef;
+            } else {
+                sv_setsv(into, &PL_sv_undef);
+            }
+        }
+        break;
+
+        case SRL_HDR_BINARY:        srl_read_string(aTHX_ dec, 0, into);              break;
+        case SRL_HDR_STR_UTF8:      srl_read_string(aTHX_ dec, 1, into);              break;
+
+        case SRL_HDR_WEAKEN:        srl_read_weaken(aTHX_ dec, into);       is_ref=1; break;
+        case SRL_HDR_REFN:          srl_read_refn(aTHX_ dec, into);         is_ref=1; break;
+        case SRL_HDR_REFP:          srl_read_refp(aTHX_ dec, into);         is_ref=1; break;
+        case SRL_HDR_OBJECT_FREEZE:
+        case SRL_HDR_OBJECT:        srl_read_object(aTHX_ dec, into, tag);  is_ref=1; break;
+        case SRL_HDR_OBJECTV_FREEZE:
+        case SRL_HDR_OBJECTV:       srl_read_objectv(aTHX_ dec, into, tag); is_ref=1; break;
+        case SRL_HDR_COPY:          srl_read_copy(aTHX_ dec, into);                   break;
+        case SRL_HDR_EXTEND:        srl_read_extend(aTHX_ dec, into);                 break;
+        case SRL_HDR_HASH:          srl_read_hash(aTHX_ dec, into, 0);                break;
+        case SRL_HDR_ARRAY:         srl_read_array(aTHX_ dec, into, 0);               break;
+        case SRL_HDR_REGEXP:        srl_read_regexp(aTHX_ dec, into);                 break;
+        case SRL_HDR_ALIAS:
+        {
+            UV offset;
+            SV *alias;
+            if (!container)
+                SRL_ERROR("ALIAS tag not inside container, corrupt packet?");
+            offset= srl_read_varint_uv_offset(aTHX_ dec," while reading ALIAS tag");
+            alias= srl_fetch_item(aTHX_ dec, offset, "ALIAS");
+            SvREFCNT_inc(alias);
+            SvREFCNT_dec(into);
+            *container= alias;
+            return;
         }
+        break;
+        case SRL_HDR_PAD:           /* no op */
+            while (BUF_NOT_DONE(dec) && *dec->pos == SRL_HDR_PAD)
+                dec->pos++;
+            goto read_again;
+        break;
+        default:
+            if (tag & SRL_HDR_TRACK_FLAG) {
+                tag= tag & ~SRL_HDR_TRACK_FLAG;
+                srl_track_sv(aTHX_ dec, dec->pos-1, into);
+                goto read_tag;
+            } else { 
+                SRL_ERROR_UNEXPECTED(dec,tag, " single value");
+            }
+        break;
     }
 
     /* they want us to set all SVs readonly, or only the non-ref */
-    if (  SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_SET_READONLY) ||
-          (SRL_DEC_HAVE_OPTION(dec, SRL_F_DECODER_SET_READONLY_SCALARS) && !is_ref) ) {
-        SvREADONLY_on(into);
-    }
+#define SUPPORT_READONLY 1
+#if SUPPORT_READONLY
+        if ( expect_false(dec->flags_readonly) )
+        {
+            if (
+                 dec->flags_readonly == 1 || !is_ref
+            ) {
+                SvREADONLY_on(into);
+            }
+        }
+#endif
 
-    dec->recursion_depth--;
+    return;
 }
@@ -7,11 +7,11 @@
 
 typedef struct PTABLE * ptable_ptr;
 typedef struct {
-    unsigned char *buf_start;           /* ptr to "physical" start of input buffer */
-    unsigned char *buf_end;             /* ptr to end of input buffer */
-    unsigned char *pos;                 /* ptr to current position within input buffer */
-    unsigned char *save_pos;            /* used for COPY tags */
-    unsigned char *body_pos;            /* in Sereal V2, all offsets are relative to the body */
+    const unsigned char *buf_start;           /* ptr to "physical" start of input buffer */
+    const unsigned char *buf_end;             /* ptr to end of input buffer */
+    const unsigned char *pos;                 /* ptr to current position within input buffer */
+    const unsigned char *save_pos;            /* used for COPY tags */
+    const unsigned char *body_pos;            /* in Sereal V2, all offsets are relative to the body */
     STRLEN buf_len;
 
     U32 flags;                          /* flag-like options: See SRL_F_DECODER_* defines in srl_decoder.c */
@@ -24,19 +24,25 @@ typedef struct {
     AV* weakref_av;
 
     AV* alias_cache; /* used to cache integers of different sizes. */
-    UV alias_varint_under;
+    IV alias_varint_under;
 
     UV bytes_consumed;
     UV recursion_depth;                 /* Recursion depth of current decoder */
     U8 proto_version;
     U8 encoding_flags;
+    U32 flags_readonly;
 } srl_decoder_t;
 
+typedef struct {
+    SV *sv;
+    U32 hash;
+} sv_with_hash;
+
 /* utility routine */
 IV srl_validate_header_version_pv_len(pTHX_ char *strdata, STRLEN len);
 
 /* constructor; don't need destructor, this sets up a callback */
-srl_decoder_t *srl_build_decoder_struct(pTHX_ HV *opt);
+srl_decoder_t *srl_build_decoder_struct(pTHX_ HV *opt, sv_with_hash *options);
 
 /* main routines */
 /* will return a mortal or the new contents of into if that isn't NULL */
@@ -103,27 +109,6 @@ void srl_decoder_destructor_hook(pTHX_ void *p);
         SvROK_on(into);                             \
     } STMT_END
 
-#define SRL_BASE_ERROR_FORMAT "Sereal: Error in %s line %u and char %i of input: "
-#define SRL_BASE_ERROR_ARGS __FILE__, __LINE__, (int)(1 + dec->pos - dec->buf_start)
-
-#define SRL_ERROR(msg)                          croak(SRL_BASE_ERROR_FORMAT "%s", SRL_BASE_ERROR_ARGS, (msg))
-#define SRL_ERRORf1(fmt,var)                    croak(SRL_BASE_ERROR_FORMAT fmt, SRL_BASE_ERROR_ARGS, (var))
-#define SRL_ERRORf2(fmt,var1,var2)              croak(SRL_BASE_ERROR_FORMAT fmt, SRL_BASE_ERROR_ARGS, (var1),(var2))
-#define SRL_ERRORf3(fmt,var1,var2,var3)         croak(SRL_BASE_ERROR_FORMAT fmt, SRL_BASE_ERROR_ARGS, (var1),(var2),(var3))
-#define SRL_ERRORf4(fmt,var1,var2,var3,var4)    croak(SRL_BASE_ERROR_FORMAT fmt, SRL_BASE_ERROR_ARGS, (var1),(var2),(var3),(var4))
-#define SRL_ERROR_UNIMPLEMENTED(dec,tag,str) \
-    SRL_ERRORf3("Tag %u %s is unimplemented at ofs: %lu", (tag), (str), (unsigned long)BUF_POS_OFS(dec))
-#define SRL_ERROR_UNTERMINATED(dec,tag,str)                                                                 \
-    SRL_ERRORf4("Tag SRL_HDR_%s %s was not terminated properly at ofs %lu with %lu to go",                  \
-            tag_name[(tag) & 127], (str), (dec)->pos - (dec)->buf_start, (dec)->buf_end - (dec)->pos)
-#define SRL_ERROR_BAD_COPY(dec, tag) \
-    SRL_ERRORf1("While processing tag SRL_HDR_%s encountered a bad COPY tag", tag_name[(tag) & 127])
-#define SRL_ERROR_UNEXPECTED(dec, tag, msg) \
-    SRL_ERRORf2("Unexpected tag %s while expecting %s", tag_name[(tag) & 127], msg)
-#define SRL_ERROR_REFUSE_OBJECT() \
-    SRL_ERROR("Encountered object in input, but the 'refuse_objects' option is in effect");
-#define SRL_ERROR_PANIC(dec, msg) SRL_ERRORf1("Panic: %s", msg);
-
 /* If set, the decoder struct needs to be cleared instead of freed at
  * the end of a deserialization operation */
 #define SRL_F_REUSE_DECODER                     0x00000001UL
@@ -171,144 +156,58 @@ void srl_decoder_destructor_hook(pTHX_ void *p);
 #define SRL_DEC_VOLATILE_FLAGS (SRL_F_DECODER_NEEDS_FINALIZE|SRL_F_DECODER_DECOMPRESS_SNAPPY|SRL_F_DECODER_PROTOCOL_V1|SRL_F_DECODER_DIRTY|SRL_F_DECODER_DECOMPRESS_ZLIB)
 #define SRL_DEC_RESET_VOLATILE_FLAGS(dec) ((dec)->flags &= ~SRL_DEC_VOLATILE_FLAGS)
 
-/* 
-=for autoupdater start
-
-* NOTE this section is autoupdated by author_tools/update_from_header.pl
-*/
-static const char * const tag_name[] = {
-	"POS_0",             /*        0 0x00 0b00000000 */
-	"POS_1",             /*        1 0x01 0b00000001 */
-	"POS_2",             /*        2 0x02 0b00000010 */
-	"POS_3",             /*        3 0x03 0b00000011 */
-	"POS_4",             /*        4 0x04 0b00000100 */
-	"POS_5",             /*        5 0x05 0b00000101 */
-	"POS_6",             /*        6 0x06 0b00000110 */
-	"POS_7",             /* "\a"   7 0x07 0b00000111 */
-	"POS_8",             /* "\b"   8 0x08 0b00001000 */
-	"POS_9",             /* "\t"   9 0x09 0b00001001 */
-	"POS_10",            /* "\n"  10 0x0a 0b00001010 */
-	"POS_11",            /*       11 0x0b 0b00001011 */
-	"POS_12",            /* "\f"  12 0x0c 0b00001100 */
-	"POS_13",            /* "\r"  13 0x0d 0b00001101 */
-	"POS_14",            /*       14 0x0e 0b00001110 */
-	"POS_15",            /*       15 0x0f 0b00001111 */
-	"NEG_16",            /*       16 0x10 0b00010000 */
-	"NEG_15",            /*       17 0x11 0b00010001 */
-	"NEG_14",            /*       18 0x12 0b00010010 */
-	"NEG_13",            /*       19 0x13 0b00010011 */
-	"NEG_12",            /*       20 0x14 0b00010100 */
-	"NEG_11",            /*       21 0x15 0b00010101 */
-	"NEG_10",            /*       22 0x16 0b00010110 */
-	"NEG_9",             /*       23 0x17 0b00010111 */
-	"NEG_8",             /*       24 0x18 0b00011000 */
-	"NEG_7",             /*       25 0x19 0b00011001 */
-	"NEG_6",             /*       26 0x1a 0b00011010 */
-	"NEG_5",             /* "\e"  27 0x1b 0b00011011 */
-	"NEG_4",             /*       28 0x1c 0b00011100 */
-	"NEG_3",             /*       29 0x1d 0b00011101 */
-	"NEG_2",             /*       30 0x1e 0b00011110 */
-	"NEG_1",             /*       31 0x1f 0b00011111 */
-	"VARINT",            /* " "   32 0x20 0b00100000 */
-	"ZIGZAG",            /* "!"   33 0x21 0b00100001 */
-	"FLOAT",             /* "\""  34 0x22 0b00100010 */
-	"DOUBLE",            /* "#"   35 0x23 0b00100011 */
-	"LONG_DOUBLE",       /* "\$"  36 0x24 0b00100100 */
-	"UNDEF",             /* "%"   37 0x25 0b00100101 */
-	"BINARY",            /* "&"   38 0x26 0b00100110 */
-	"STR_UTF8",          /* "'"   39 0x27 0b00100111 */
-	"REFN",              /* "("   40 0x28 0b00101000 */
-	"REFP",              /* ")"   41 0x29 0b00101001 */
-	"HASH",              /* "*"   42 0x2a 0b00101010 */
-	"ARRAY",             /* "+"   43 0x2b 0b00101011 */
-	"OBJECT",            /* ","   44 0x2c 0b00101100 */
-	"OBJECTV",           /* "-"   45 0x2d 0b00101101 */
-	"ALIAS",             /* "."   46 0x2e 0b00101110 */
-	"COPY",              /* "/"   47 0x2f 0b00101111 */
-	"WEAKEN",            /* "0"   48 0x30 0b00110000 */
-	"REGEXP",            /* "1"   49 0x31 0b00110001 */
-	"OBJECT_FREEZE",     /* "2"   50 0x32 0b00110010 */
-	"OBJECTV_FREEZE",    /* "3"   51 0x33 0b00110011 */
-	"RESERVED_0",        /* "4"   52 0x34 0b00110100 */
-	"RESERVED_1",        /* "5"   53 0x35 0b00110101 */
-	"RESERVED_2",        /* "6"   54 0x36 0b00110110 */
-	"RESERVED_3",        /* "7"   55 0x37 0b00110111 */
-	"RESERVED_4",        /* "8"   56 0x38 0b00111000 */
-	"CANONICAL_UNDEF",   /* "9"   57 0x39 0b00111001 */
-	"FALSE",             /* ":"   58 0x3a 0b00111010 */
-	"TRUE",              /* ";"   59 0x3b 0b00111011 */
-	"MANY",              /* "<"   60 0x3c 0b00111100 */
-	"PACKET_START",      /* "="   61 0x3d 0b00111101 */
-	"EXTEND",            /* ">"   62 0x3e 0b00111110 */
-	"PAD",               /* "?"   63 0x3f 0b00111111 */
-	"ARRAYREF_0",        /* "\@"  64 0x40 0b01000000 */
-	"ARRAYREF_1",        /* "A"   65 0x41 0b01000001 */
-	"ARRAYREF_2",        /* "B"   66 0x42 0b01000010 */
-	"ARRAYREF_3",        /* "C"   67 0x43 0b01000011 */
-	"ARRAYREF_4",        /* "D"   68 0x44 0b01000100 */
-	"ARRAYREF_5",        /* "E"   69 0x45 0b01000101 */
-	"ARRAYREF_6",        /* "F"   70 0x46 0b01000110 */
-	"ARRAYREF_7",        /* "G"   71 0x47 0b01000111 */
-	"ARRAYREF_8",        /* "H"   72 0x48 0b01001000 */
-	"ARRAYREF_9",        /* "I"   73 0x49 0b01001001 */
-	"ARRAYREF_10",       /* "J"   74 0x4a 0b01001010 */
-	"ARRAYREF_11",       /* "K"   75 0x4b 0b01001011 */
-	"ARRAYREF_12",       /* "L"   76 0x4c 0b01001100 */
-	"ARRAYREF_13",       /* "M"   77 0x4d 0b01001101 */
-	"ARRAYREF_14",       /* "N"   78 0x4e 0b01001110 */
-	"ARRAYREF_15",       /* "O"   79 0x4f 0b01001111 */
-	"HASHREF_0",         /* "P"   80 0x50 0b01010000 */
-	"HASHREF_1",         /* "Q"   81 0x51 0b01010001 */
-	"HASHREF_2",         /* "R"   82 0x52 0b01010010 */
-	"HASHREF_3",         /* "S"   83 0x53 0b01010011 */
-	"HASHREF_4",         /* "T"   84 0x54 0b01010100 */
-	"HASHREF_5",         /* "U"   85 0x55 0b01010101 */
-	"HASHREF_6",         /* "V"   86 0x56 0b01010110 */
-	"HASHREF_7",         /* "W"   87 0x57 0b01010111 */
-	"HASHREF_8",         /* "X"   88 0x58 0b01011000 */
-	"HASHREF_9",         /* "Y"   89 0x59 0b01011001 */
-	"HASHREF_10",        /* "Z"   90 0x5a 0b01011010 */
-	"HASHREF_11",        /* "["   91 0x5b 0b01011011 */
-	"HASHREF_12",        /* "\\"  92 0x5c 0b01011100 */
-	"HASHREF_13",        /* "]"   93 0x5d 0b01011101 */
-	"HASHREF_14",        /* "^"   94 0x5e 0b01011110 */
-	"HASHREF_15",        /* "_"   95 0x5f 0b01011111 */
-	"SHORT_BINARY_0",    /* "`"   96 0x60 0b01100000 */
-	"SHORT_BINARY_1",    /* "a"   97 0x61 0b01100001 */
-	"SHORT_BINARY_2",    /* "b"   98 0x62 0b01100010 */
-	"SHORT_BINARY_3",    /* "c"   99 0x63 0b01100011 */
-	"SHORT_BINARY_4",    /* "d"  100 0x64 0b01100100 */
-	"SHORT_BINARY_5",    /* "e"  101 0x65 0b01100101 */
-	"SHORT_BINARY_6",    /* "f"  102 0x66 0b01100110 */
-	"SHORT_BINARY_7",    /* "g"  103 0x67 0b01100111 */
-	"SHORT_BINARY_8",    /* "h"  104 0x68 0b01101000 */
-	"SHORT_BINARY_9",    /* "i"  105 0x69 0b01101001 */
-	"SHORT_BINARY_10",   /* "j"  106 0x6a 0b01101010 */
-	"SHORT_BINARY_11",   /* "k"  107 0x6b 0b01101011 */
-	"SHORT_BINARY_12",   /* "l"  108 0x6c 0b01101100 */
-	"SHORT_BINARY_13",   /* "m"  109 0x6d 0b01101101 */
-	"SHORT_BINARY_14",   /* "n"  110 0x6e 0b01101110 */
-	"SHORT_BINARY_15",   /* "o"  111 0x6f 0b01101111 */
-	"SHORT_BINARY_16",   /* "p"  112 0x70 0b01110000 */
-	"SHORT_BINARY_17",   /* "q"  113 0x71 0b01110001 */
-	"SHORT_BINARY_18",   /* "r"  114 0x72 0b01110010 */
-	"SHORT_BINARY_19",   /* "s"  115 0x73 0b01110011 */
-	"SHORT_BINARY_20",   /* "t"  116 0x74 0b01110100 */
-	"SHORT_BINARY_21",   /* "u"  117 0x75 0b01110101 */
-	"SHORT_BINARY_22",   /* "v"  118 0x76 0b01110110 */
-	"SHORT_BINARY_23",   /* "w"  119 0x77 0b01110111 */
-	"SHORT_BINARY_24",   /* "x"  120 0x78 0b01111000 */
-	"SHORT_BINARY_25",   /* "y"  121 0x79 0b01111001 */
-	"SHORT_BINARY_26",   /* "z"  122 0x7a 0b01111010 */
-	"SHORT_BINARY_27",   /* "{"  123 0x7b 0b01111011 */
-	"SHORT_BINARY_28",   /* "|"  124 0x7c 0b01111100 */
-	"SHORT_BINARY_29",   /* "}"  125 0x7d 0b01111101 */
-	"SHORT_BINARY_30",   /* "~"  126 0x7e 0b01111110 */
-	"SHORT_BINARY_31"    /*      127 0x7f 0b01111111 */
-};
-/*
-* NOTE the above section is auto-updated by author_tools/update_from_header.pl
-
-=for autoupdater stop
-*/
+#define IS_IV_ALIAS(dec,iv)             \
+(                                       \
+    ((dec)->alias_varint_under) &&      \
+    ((iv) >= -16 )&&                    \
+    ((iv) < (dec)->alias_varint_under)  \
+)
+
+/* Options Parsing related code */
+#define SRL_INIT_OPTION(idx, str) STMT_START {                          \
+    MY_CXT.options[idx].sv = newSVpvn((str ""), (sizeof(str) - 1));     \
+    PERL_HASH(MY_CXT.options[idx].hash, (str ""), (sizeof(str) - 1));   \
+} STMT_END
+
+#define SRL_DEC_OPT_STR_ALIAS_SMALLINT              "alias_smallint"
+#define SRL_DEC_OPT_IDX_ALIAS_SMALLINT              0
+
+#define SRL_DEC_OPT_STR_ALIAS_VARINT_UNDER          "alias_varint_under"
+#define SRL_DEC_OPT_IDX_ALIAS_VARINT_UNDER          1
+
+#define SRL_DEC_OPT_STR_DESTRUCTIVE_INCREMENTAL     "incremental"
+#define SRL_DEC_OPT_IDX_DESTRUCTIVE_INCREMENTAL     2
+
+#define SRL_DEC_OPT_STR_MAX_NUM_HASH_ENTRIES        "max_num_hash_entries"
+#define SRL_DEC_OPT_IDX_MAX_NUM_HASH_ENTRIES        3
+
+#define SRL_DEC_OPT_STR_MAX_RECURSION_DEPTH         "max_recursion_depth"
+#define SRL_DEC_OPT_IDX_MAX_RECURSION_DEPTH         4
+
+#define SRL_DEC_OPT_STR_NO_BLESS_OBJECTS            "no_bless_objects"
+#define SRL_DEC_OPT_IDX_NO_BLESS_OBJECTS            5
+
+#define SRL_DEC_OPT_STR_REFUSE_OBJECTS              "refuse_objects"
+#define SRL_DEC_OPT_IDX_REFUSE_OBJECTS              6
+
+#define SRL_DEC_OPT_STR_REFUSE_SNAPPY               "refuse_snappy"
+#define SRL_DEC_OPT_IDX_REFUSE_SNAPPY               7
+
+#define SRL_DEC_OPT_STR_REFUSE_ZLIB                 "refuse_zlib"
+#define SRL_DEC_OPT_IDX_REFUSE_ZLIB                 8
+
+#define SRL_DEC_OPT_STR_SET_READONLY                "set_readonly"
+#define SRL_DEC_OPT_IDX_SET_READONLY                9
+
+#define SRL_DEC_OPT_STR_SET_READONLY_SCALARS        "set_readonly_scalars"
+#define SRL_DEC_OPT_IDX_SET_READONLY_SCALARS        10
+
+#define SRL_DEC_OPT_STR_USE_UNDEF                   "use_undef"
+#define SRL_DEC_OPT_IDX_USE_UNDEF                   11
+
+#define SRL_DEC_OPT_STR_VALIDATE_UTF8               "validate_utf8"
+#define SRL_DEC_OPT_IDX_VALIDATE_UTF8               12
+
+#define SRL_DEC_OPT_COUNT                           13
+
 #endif
@@ -0,0 +1,28 @@
+#ifndef SRL_ERROR_H_
+#define SRL_ERROR_H_
+#include "srl_taginfo.h"
+
+#define SRL_BASE_ERROR_FORMAT "Sereal: Error in %s line %u and char %i of input: "
+#define SRL_BASE_ERROR_ARGS __FILE__, __LINE__, (int) (1 + dec->pos - dec->buf_start)
+
+#define SRL_ERROR(msg)                          croak(SRL_BASE_ERROR_FORMAT "%s", SRL_BASE_ERROR_ARGS, (msg))
+#define SRL_ERRORf1(fmt,var)                    croak(SRL_BASE_ERROR_FORMAT fmt,  SRL_BASE_ERROR_ARGS, (var))
+#define SRL_ERRORf2(fmt,var1,var2)              croak(SRL_BASE_ERROR_FORMAT fmt,  SRL_BASE_ERROR_ARGS, (var1), (var2))
+#define SRL_ERRORf3(fmt,var1,var2,var3)         croak(SRL_BASE_ERROR_FORMAT fmt,  SRL_BASE_ERROR_ARGS, (var1), (var2), (var3))
+#define SRL_ERRORf4(fmt,var1,var2,var3,var4)    croak(SRL_BASE_ERROR_FORMAT fmt,  SRL_BASE_ERROR_ARGS, (var1), (var2), (var3), (var4))
+
+#define SRL_ERROR_UNIMPLEMENTED(dec,tag,str) \
+    SRL_ERRORf3("Tag %u %s is unimplemented at ofs: %lu", (tag), (str), (unsigned long) BUF_POS_OFS(dec))
+
+#define SRL_ERROR_UNTERMINATED(dec,tag,str)                                                                 \
+    SRL_ERRORf4("Tag SRL_HDR_%s %s was not terminated properly at ofs %lu with %lu to go",                  \
+                tag_name[(tag) & 127], (str), (dec)->pos - (dec)->buf_start, (dec)->buf_end - (dec)->pos)
+
+#define SRL_ERROR_BAD_COPY(dec, tag) \
+    SRL_ERRORf1("While processing tag SRL_HDR_%s encountered a bad COPY tag", tag_name[(tag) & 127])
+
+#define SRL_ERROR_UNEXPECTED(dec, tag, msg) SRL_ERRORf2("Unexpected tag %s while expecting %s", tag_name[(tag) & 127], msg)
+#define SRL_ERROR_REFUSE_OBJECT()           SRL_ERROR("Encountered object in input, but the 'refuse_objects' option is in effect");
+#define SRL_ERROR_PANIC(dec, msg)           SRL_ERRORf1("Panic: %s", msg);
+
+#endif
@@ -178,71 +178,71 @@
 /* _LOW and _HIGH versions refering to INCLUSIVE range boundaries */
 
 
-#define SRL_HDR_POS             ((char)0)       /* small positive integer - value in low 4 bits (identity) */
-#define SRL_HDR_POS_LOW         ((char)0)       /* small positive integer - value in low 4 bits (identity) */
-#define SRL_HDR_POS_HIGH        ((char)15)      /* small positive integer - value in low 4 bits (identity) */
-
-#define SRL_HDR_NEG             ((char)16)      /* small negative integer - value in low 4 bits (k+32) */
-#define SRL_HDR_NEG_LOW         ((char)16)      /* small negative integer - value in low 4 bits (k+32) */
-#define SRL_HDR_NEG_HIGH        ((char)31)      /* small negative integer - value in low 4 bits (k+32) */
-
-#define SRL_HDR_VARINT          ((char)32)      /* <VARINT> - Varint variable length integer */
-#define SRL_HDR_ZIGZAG          ((char)33)      /* <ZIGZAG-VARINT> - Zigzag variable length integer */
-#define SRL_HDR_FLOAT           ((char)34)      /* <IEEE-FLOAT> */
-#define SRL_HDR_DOUBLE          ((char)35)      /* <IEEE-DOUBLE> */
-#define SRL_HDR_LONG_DOUBLE     ((char)36)      /* <IEEE-LONG-DOUBLE> */
-#define SRL_HDR_UNDEF           ((char)37)      /* None - Perl undef var; eg my $var= undef; */
-#define SRL_HDR_BINARY          ((char)38)      /* <LEN-VARINT> <BYTES> - binary/(latin1) string */
-#define SRL_HDR_STR_UTF8        ((char)39)      /* <LEN-VARINT> <UTF8> - utf8 string */
-
-#define SRL_HDR_REFN            ((char)40)      /* <ITEM-TAG>    - ref to next item */
-#define SRL_HDR_REFP            ((char)41)      /* <OFFSET-VARINT> - ref to previous item stored at offset */
-#define SRL_HDR_HASH            ((char)42)      /* <COUNT-VARINT> [<KEY-TAG> <ITEM-TAG> ...] - count followed by key/value pairs */
-#define SRL_HDR_ARRAY           ((char)43)      /* <COUNT-VARINT> [<ITEM-TAG> ...] - count followed by items */
-#define SRL_HDR_OBJECT          ((char)44)      /* <STR-TAG> <ITEM-TAG> - class, object-item */
-#define SRL_HDR_OBJECTV         ((char)45)      /* <OFFSET-VARINT> <ITEM-TAG> - offset of previously used classname tag - object-item */
-#define SRL_HDR_ALIAS           ((char)46)      /* <OFFSET-VARINT> - alias to item defined at offset */
-#define SRL_HDR_COPY            ((char)47)      /* <OFFSET-VARINT> - copy of item defined at offset */
-
-#define SRL_HDR_WEAKEN          ((char)48)      /* <REF-TAG> - Weaken the following reference */
-#define SRL_HDR_REGEXP          ((char)49)      /* <PATTERN-STR-TAG> <MODIFIERS-STR-TAG>*/
-
-#define SRL_HDR_OBJECT_FREEZE   ((char)50)      /* <STR-TAG> <ITEM-TAG> - class, object-item. Need to call "THAW" method on class after decoding */
-#define SRL_HDR_OBJECTV_FREEZE  ((char)51)      /* <OFFSET-VARINT> <ITEM-TAG> - (OBJECTV_FREEZE is to OBJECT_FREEZE as OBJECTV is to OBJECT) */
+#define SRL_HDR_POS             ((U8)0)       /* small positive integer - value in low 4 bits (identity) */
+#define SRL_HDR_POS_LOW         ((U8)0)       /* small positive integer - value in low 4 bits (identity) */
+#define SRL_HDR_POS_HIGH        ((U8)15)      /* small positive integer - value in low 4 bits (identity) */
+
+#define SRL_HDR_NEG             ((U8)16)      /* small negative integer - value in low 4 bits (k+32) */
+#define SRL_HDR_NEG_LOW         ((U8)16)      /* small negative integer - value in low 4 bits (k+32) */
+#define SRL_HDR_NEG_HIGH        ((U8)31)      /* small negative integer - value in low 4 bits (k+32) */
+
+#define SRL_HDR_VARINT          ((U8)32)      /* <VARINT> - Varint variable length integer */
+#define SRL_HDR_ZIGZAG          ((U8)33)      /* <ZIGZAG-VARINT> - Zigzag variable length integer */
+#define SRL_HDR_FLOAT           ((U8)34)      /* <IEEE-FLOAT> */
+#define SRL_HDR_DOUBLE          ((U8)35)      /* <IEEE-DOUBLE> */
+#define SRL_HDR_LONG_DOUBLE     ((U8)36)      /* <IEEE-LONG-DOUBLE> */
+#define SRL_HDR_UNDEF           ((U8)37)      /* None - Perl undef var; eg my $var= undef; */
+#define SRL_HDR_BINARY          ((U8)38)      /* <LEN-VARINT> <BYTES> - binary/(latin1) string */
+#define SRL_HDR_STR_UTF8        ((U8)39)      /* <LEN-VARINT> <UTF8> - utf8 string */
+
+#define SRL_HDR_REFN            ((U8)40)      /* <ITEM-TAG>    - ref to next item */
+#define SRL_HDR_REFP            ((U8)41)      /* <OFFSET-VARINT> - ref to previous item stored at offset */
+#define SRL_HDR_HASH            ((U8)42)      /* <COUNT-VARINT> [<KEY-TAG> <ITEM-TAG> ...] - count followed by key/value pairs */
+#define SRL_HDR_ARRAY           ((U8)43)      /* <COUNT-VARINT> [<ITEM-TAG> ...] - count followed by items */
+#define SRL_HDR_OBJECT          ((U8)44)      /* <STR-TAG> <ITEM-TAG> - class, object-item */
+#define SRL_HDR_OBJECTV         ((U8)45)      /* <OFFSET-VARINT> <ITEM-TAG> - offset of previously used classname tag - object-item */
+#define SRL_HDR_ALIAS           ((U8)46)      /* <OFFSET-VARINT> - alias to item defined at offset */
+#define SRL_HDR_COPY            ((U8)47)      /* <OFFSET-VARINT> - copy of item defined at offset */
+
+#define SRL_HDR_WEAKEN          ((U8)48)      /* <REF-TAG> - Weaken the following reference */
+#define SRL_HDR_REGEXP          ((U8)49)      /* <PATTERN-STR-TAG> <MODIFIERS-STR-TAG>*/
+
+#define SRL_HDR_OBJECT_FREEZE   ((U8)50)      /* <STR-TAG> <ITEM-TAG> - class, object-item. Need to call "THAW" method on class after decoding */
+#define SRL_HDR_OBJECTV_FREEZE  ((U8)51)      /* <OFFSET-VARINT> <ITEM-TAG> - (OBJECTV_FREEZE is to OBJECT_FREEZE as OBJECTV is to OBJECT) */
 
 /* Note: Can do reserved check with a range now, but as we start using
  *       them, might have to explicit == check later. */
-#define SRL_HDR_RESERVED        ((char)52)      /* reserved */
-#define SRL_HDR_RESERVED_LOW    ((char)52)
-#define SRL_HDR_RESERVED_HIGH   ((char)56)
+#define SRL_HDR_RESERVED        ((U8)52)      /* reserved */
+#define SRL_HDR_RESERVED_LOW    ((U8)52)
+#define SRL_HDR_RESERVED_HIGH   ((U8)56)
 
-#define SRL_HDR_CANONICAL_UNDEF ((char)57)      /* undef (PL_sv_undef) - "the" Perl undef (see notes) */
-#define SRL_HDR_FALSE           ((char)58)      /* false (PL_sv_no)  */
-#define SRL_HDR_TRUE            ((char)59)      /* true  (PL_sv_yes) */
+#define SRL_HDR_CANONICAL_UNDEF ((U8)57)      /* undef (PL_sv_undef) - "the" Perl undef (see notes) */
+#define SRL_HDR_FALSE           ((U8)58)      /* false (PL_sv_no)  */
+#define SRL_HDR_TRUE            ((U8)59)      /* true  (PL_sv_yes) */
 
-#define SRL_HDR_MANY            ((char)60)      /* <LEN-VARINT> <TYPE-BYTE> <TAG-DATA> - repeated tag (not done yet, will be implemented in version 3) */
-#define SRL_HDR_PACKET_START    ((char)61)      /* (first byte of magic string in header) */
+#define SRL_HDR_MANY            ((U8)60)      /* <LEN-VARINT> <TYPE-BYTE> <TAG-DATA> - repeated tag (not done yet, will be implemented in version 3) */
+#define SRL_HDR_PACKET_START    ((U8)61)      /* (first byte of magic string in header) */
 
 
-#define SRL_HDR_EXTEND          ((char)62)      /* <BYTE> - for additional tags */
-#define SRL_HDR_PAD             ((char)63)      /* (ignored tag, skip to next byte) */
-#define SRL_HDR_ARRAYREF        ((char)64)      /* [<ITEM-TAG> ...] - count of items in low 4 bits (ARRAY must be refcnt=1)*/
-#define SRL_MASK_ARRAYREF_COUNT ((char)15)      /* mask to get low bits from tag */
-#define SRL_HDR_ARRAYREF_LOW    ((char)64)
-#define SRL_HDR_ARRAYREF_HIGH   ((char)79)
+#define SRL_HDR_EXTEND          ((U8)62)      /* <BYTE> - for additional tags */
+#define SRL_HDR_PAD             ((U8)63)      /* (ignored tag, skip to next byte) */
+#define SRL_HDR_ARRAYREF        ((U8)64)      /* [<ITEM-TAG> ...] - count of items in low 4 bits (ARRAY must be refcnt=1)*/
+#define SRL_MASK_ARRAYREF_COUNT ((U8)15)      /* mask to get low bits from tag */
+#define SRL_HDR_ARRAYREF_LOW    ((U8)64)
+#define SRL_HDR_ARRAYREF_HIGH   ((U8)79)
 
 
-#define SRL_HDR_HASHREF         ((char)80)      /* [<KEY-TAG> <ITEM-TAG> ...] - count in low 4 bits, key/value pairs (HASH must be refcnt=1)*/
-#define SRL_MASK_HASHREF_COUNT  ((char)15)      /* mask to get low bits from tag */
-#define SRL_HDR_HASHREF_LOW     ((char)80)
-#define SRL_HDR_HASHREF_HIGH    ((char)95)
+#define SRL_HDR_HASHREF         ((U8)80)      /* [<KEY-TAG> <ITEM-TAG> ...] - count in low 4 bits, key/value pairs (HASH must be refcnt=1)*/
+#define SRL_MASK_HASHREF_COUNT  ((U8)15)      /* mask to get low bits from tag */
+#define SRL_HDR_HASHREF_LOW     ((U8)80)
+#define SRL_HDR_HASHREF_HIGH    ((U8)95)
 
-#define SRL_HDR_SHORT_BINARY    ((char)96)      /* <BYTES> - binary/latin1 string, length encoded in low 5 bits of tag */
-#define SRL_HDR_SHORT_BINARY_LOW       ((char)96)
-#define SRL_HDR_SHORT_BINARY_HIGH      ((char)127)
-#define SRL_MASK_SHORT_BINARY_LEN      ((char)31)      /* mask to get length of SRL_HDR_SHORT_BINARY type tags */
+#define SRL_HDR_SHORT_BINARY    ((U8)96)      /* <BYTES> - binary/latin1 string, length encoded in low 5 bits of tag */
+#define SRL_HDR_SHORT_BINARY_LOW       ((U8)96)
+#define SRL_HDR_SHORT_BINARY_HIGH      ((U8)127)
+#define SRL_MASK_SHORT_BINARY_LEN      ((U8)31)      /* mask to get length of SRL_HDR_SHORT_BINARY type tags */
 
-#define SRL_HDR_TRACK_FLAG      ((char)128)         /* if this bit is set track the item */
+#define SRL_HDR_TRACK_FLAG      ((U8)128)         /* if this bit is set track the item */
 
 /* TODO */
 
@@ -0,0 +1,369 @@
+#ifndef SRL_TAGINFO_H
+#define SRL_TAGINFO_H
+/*
+
+=for autoupdater start
+
+* NOTE this section is autoupdated by author_tools/update_from_header.pl
+*/
+
+static const char * const tag_name[] = {
+	"POS_0",             /*        0 0x00 0b00000000 */
+	"POS_1",             /*        1 0x01 0b00000001 */
+	"POS_2",             /*        2 0x02 0b00000010 */
+	"POS_3",             /*        3 0x03 0b00000011 */
+	"POS_4",             /*        4 0x04 0b00000100 */
+	"POS_5",             /*        5 0x05 0b00000101 */
+	"POS_6",             /*        6 0x06 0b00000110 */
+	"POS_7",             /* "\a"   7 0x07 0b00000111 */
+	"POS_8",             /* "\b"   8 0x08 0b00001000 */
+	"POS_9",             /* "\t"   9 0x09 0b00001001 */
+	"POS_10",            /* "\n"  10 0x0a 0b00001010 */
+	"POS_11",            /*       11 0x0b 0b00001011 */
+	"POS_12",            /* "\f"  12 0x0c 0b00001100 */
+	"POS_13",            /* "\r"  13 0x0d 0b00001101 */
+	"POS_14",            /*       14 0x0e 0b00001110 */
+	"POS_15",            /*       15 0x0f 0b00001111 */
+	"NEG_16",            /*       16 0x10 0b00010000 */
+	"NEG_15",            /*       17 0x11 0b00010001 */
+	"NEG_14",            /*       18 0x12 0b00010010 */
+	"NEG_13",            /*       19 0x13 0b00010011 */
+	"NEG_12",            /*       20 0x14 0b00010100 */
+	"NEG_11",            /*       21 0x15 0b00010101 */
+	"NEG_10",            /*       22 0x16 0b00010110 */
+	"NEG_9",             /*       23 0x17 0b00010111 */
+	"NEG_8",             /*       24 0x18 0b00011000 */
+	"NEG_7",             /*       25 0x19 0b00011001 */
+	"NEG_6",             /*       26 0x1a 0b00011010 */
+	"NEG_5",             /* "\e"  27 0x1b 0b00011011 */
+	"NEG_4",             /*       28 0x1c 0b00011100 */
+	"NEG_3",             /*       29 0x1d 0b00011101 */
+	"NEG_2",             /*       30 0x1e 0b00011110 */
+	"NEG_1",             /*       31 0x1f 0b00011111 */
+	"VARINT",            /* " "   32 0x20 0b00100000 */
+	"ZIGZAG",            /* "!"   33 0x21 0b00100001 */
+	"FLOAT",             /* "\""  34 0x22 0b00100010 */
+	"DOUBLE",            /* "#"   35 0x23 0b00100011 */
+	"LONG_DOUBLE",       /* "\$"  36 0x24 0b00100100 */
+	"UNDEF",             /* "%"   37 0x25 0b00100101 */
+	"BINARY",            /* "&"   38 0x26 0b00100110 */
+	"STR_UTF8",          /* "'"   39 0x27 0b00100111 */
+	"REFN",              /* "("   40 0x28 0b00101000 */
+	"REFP",              /* ")"   41 0x29 0b00101001 */
+	"HASH",              /* "*"   42 0x2a 0b00101010 */
+	"ARRAY",             /* "+"   43 0x2b 0b00101011 */
+	"OBJECT",            /* ","   44 0x2c 0b00101100 */
+	"OBJECTV",           /* "-"   45 0x2d 0b00101101 */
+	"ALIAS",             /* "."   46 0x2e 0b00101110 */
+	"COPY",              /* "/"   47 0x2f 0b00101111 */
+	"WEAKEN",            /* "0"   48 0x30 0b00110000 */
+	"REGEXP",            /* "1"   49 0x31 0b00110001 */
+	"OBJECT_FREEZE",     /* "2"   50 0x32 0b00110010 */
+	"OBJECTV_FREEZE",    /* "3"   51 0x33 0b00110011 */
+	"RESERVED_0",        /* "4"   52 0x34 0b00110100 */
+	"RESERVED_1",        /* "5"   53 0x35 0b00110101 */
+	"RESERVED_2",        /* "6"   54 0x36 0b00110110 */
+	"RESERVED_3",        /* "7"   55 0x37 0b00110111 */
+	"RESERVED_4",        /* "8"   56 0x38 0b00111000 */
+	"CANONICAL_UNDEF",   /* "9"   57 0x39 0b00111001 */
+	"FALSE",             /* ":"   58 0x3a 0b00111010 */
+	"TRUE",              /* ";"   59 0x3b 0b00111011 */
+	"MANY",              /* "<"   60 0x3c 0b00111100 */
+	"PACKET_START",      /* "="   61 0x3d 0b00111101 */
+	"EXTEND",            /* ">"   62 0x3e 0b00111110 */
+	"PAD",               /* "?"   63 0x3f 0b00111111 */
+	"ARRAYREF_0",        /* "\@"  64 0x40 0b01000000 */
+	"ARRAYREF_1",        /* "A"   65 0x41 0b01000001 */
+	"ARRAYREF_2",        /* "B"   66 0x42 0b01000010 */
+	"ARRAYREF_3",        /* "C"   67 0x43 0b01000011 */
+	"ARRAYREF_4",        /* "D"   68 0x44 0b01000100 */
+	"ARRAYREF_5",        /* "E"   69 0x45 0b01000101 */
+	"ARRAYREF_6",        /* "F"   70 0x46 0b01000110 */
+	"ARRAYREF_7",        /* "G"   71 0x47 0b01000111 */
+	"ARRAYREF_8",        /* "H"   72 0x48 0b01001000 */
+	"ARRAYREF_9",        /* "I"   73 0x49 0b01001001 */
+	"ARRAYREF_10",       /* "J"   74 0x4a 0b01001010 */
+	"ARRAYREF_11",       /* "K"   75 0x4b 0b01001011 */
+	"ARRAYREF_12",       /* "L"   76 0x4c 0b01001100 */
+	"ARRAYREF_13",       /* "M"   77 0x4d 0b01001101 */
+	"ARRAYREF_14",       /* "N"   78 0x4e 0b01001110 */
+	"ARRAYREF_15",       /* "O"   79 0x4f 0b01001111 */
+	"HASHREF_0",         /* "P"   80 0x50 0b01010000 */
+	"HASHREF_1",         /* "Q"   81 0x51 0b01010001 */
+	"HASHREF_2",         /* "R"   82 0x52 0b01010010 */
+	"HASHREF_3",         /* "S"   83 0x53 0b01010011 */
+	"HASHREF_4",         /* "T"   84 0x54 0b01010100 */
+	"HASHREF_5",         /* "U"   85 0x55 0b01010101 */
+	"HASHREF_6",         /* "V"   86 0x56 0b01010110 */
+	"HASHREF_7",         /* "W"   87 0x57 0b01010111 */
+	"HASHREF_8",         /* "X"   88 0x58 0b01011000 */
+	"HASHREF_9",         /* "Y"   89 0x59 0b01011001 */
+	"HASHREF_10",        /* "Z"   90 0x5a 0b01011010 */
+	"HASHREF_11",        /* "["   91 0x5b 0b01011011 */
+	"HASHREF_12",        /* "\\"  92 0x5c 0b01011100 */
+	"HASHREF_13",        /* "]"   93 0x5d 0b01011101 */
+	"HASHREF_14",        /* "^"   94 0x5e 0b01011110 */
+	"HASHREF_15",        /* "_"   95 0x5f 0b01011111 */
+	"SHORT_BINARY_0",    /* "`"   96 0x60 0b01100000 */
+	"SHORT_BINARY_1",    /* "a"   97 0x61 0b01100001 */
+	"SHORT_BINARY_2",    /* "b"   98 0x62 0b01100010 */
+	"SHORT_BINARY_3",    /* "c"   99 0x63 0b01100011 */
+	"SHORT_BINARY_4",    /* "d"  100 0x64 0b01100100 */
+	"SHORT_BINARY_5",    /* "e"  101 0x65 0b01100101 */
+	"SHORT_BINARY_6",    /* "f"  102 0x66 0b01100110 */
+	"SHORT_BINARY_7",    /* "g"  103 0x67 0b01100111 */
+	"SHORT_BINARY_8",    /* "h"  104 0x68 0b01101000 */
+	"SHORT_BINARY_9",    /* "i"  105 0x69 0b01101001 */
+	"SHORT_BINARY_10",   /* "j"  106 0x6a 0b01101010 */
+	"SHORT_BINARY_11",   /* "k"  107 0x6b 0b01101011 */
+	"SHORT_BINARY_12",   /* "l"  108 0x6c 0b01101100 */
+	"SHORT_BINARY_13",   /* "m"  109 0x6d 0b01101101 */
+	"SHORT_BINARY_14",   /* "n"  110 0x6e 0b01101110 */
+	"SHORT_BINARY_15",   /* "o"  111 0x6f 0b01101111 */
+	"SHORT_BINARY_16",   /* "p"  112 0x70 0b01110000 */
+	"SHORT_BINARY_17",   /* "q"  113 0x71 0b01110001 */
+	"SHORT_BINARY_18",   /* "r"  114 0x72 0b01110010 */
+	"SHORT_BINARY_19",   /* "s"  115 0x73 0b01110011 */
+	"SHORT_BINARY_20",   /* "t"  116 0x74 0b01110100 */
+	"SHORT_BINARY_21",   /* "u"  117 0x75 0b01110101 */
+	"SHORT_BINARY_22",   /* "v"  118 0x76 0b01110110 */
+	"SHORT_BINARY_23",   /* "w"  119 0x77 0b01110111 */
+	"SHORT_BINARY_24",   /* "x"  120 0x78 0b01111000 */
+	"SHORT_BINARY_25",   /* "y"  121 0x79 0b01111001 */
+	"SHORT_BINARY_26",   /* "z"  122 0x7a 0b01111010 */
+	"SHORT_BINARY_27",   /* "{"  123 0x7b 0b01111011 */
+	"SHORT_BINARY_28",   /* "|"  124 0x7c 0b01111100 */
+	"SHORT_BINARY_29",   /* "}"  125 0x7d 0b01111101 */
+	"SHORT_BINARY_30",   /* "~"  126 0x7e 0b01111110 */
+	"SHORT_BINARY_31"    /*      127 0x7f 0b01111111 */
+};
+
+#define SRL_HDR_POS_0                  0
+#define SRL_HDR_POS_1                  1
+#define SRL_HDR_POS_2                  2
+#define SRL_HDR_POS_3                  3
+#define SRL_HDR_POS_4                  4
+#define SRL_HDR_POS_5                  5
+#define SRL_HDR_POS_6                  6
+#define SRL_HDR_POS_7                  7
+#define SRL_HDR_POS_8                  8
+#define SRL_HDR_POS_9                  9
+#define SRL_HDR_POS_10                10
+#define SRL_HDR_POS_11                11
+#define SRL_HDR_POS_12                12
+#define SRL_HDR_POS_13                13
+#define SRL_HDR_POS_14                14
+#define SRL_HDR_POS_15                15
+#define SRL_HDR_NEG_16                16
+#define SRL_HDR_NEG_15                17
+#define SRL_HDR_NEG_14                18
+#define SRL_HDR_NEG_13                19
+#define SRL_HDR_NEG_12                20
+#define SRL_HDR_NEG_11                21
+#define SRL_HDR_NEG_10                22
+#define SRL_HDR_NEG_9                 23
+#define SRL_HDR_NEG_8                 24
+#define SRL_HDR_NEG_7                 25
+#define SRL_HDR_NEG_6                 26
+#define SRL_HDR_NEG_5                 27
+#define SRL_HDR_NEG_4                 28
+#define SRL_HDR_NEG_3                 29
+#define SRL_HDR_NEG_2                 30
+#define SRL_HDR_NEG_1                 31
+#define SRL_HDR_RESERVED_0            52
+#define SRL_HDR_RESERVED_1            53
+#define SRL_HDR_RESERVED_2            54
+#define SRL_HDR_RESERVED_3            55
+#define SRL_HDR_RESERVED_4            56
+#define SRL_HDR_ARRAYREF_0            64
+#define SRL_HDR_ARRAYREF_1            65
+#define SRL_HDR_ARRAYREF_2            66
+#define SRL_HDR_ARRAYREF_3            67
+#define SRL_HDR_ARRAYREF_4            68
+#define SRL_HDR_ARRAYREF_5            69
+#define SRL_HDR_ARRAYREF_6            70
+#define SRL_HDR_ARRAYREF_7            71
+#define SRL_HDR_ARRAYREF_8            72
+#define SRL_HDR_ARRAYREF_9            73
+#define SRL_HDR_ARRAYREF_10           74
+#define SRL_HDR_ARRAYREF_11           75
+#define SRL_HDR_ARRAYREF_12           76
+#define SRL_HDR_ARRAYREF_13           77
+#define SRL_HDR_ARRAYREF_14           78
+#define SRL_HDR_ARRAYREF_15           79
+#define SRL_HDR_HASHREF_0             80
+#define SRL_HDR_HASHREF_1             81
+#define SRL_HDR_HASHREF_2             82
+#define SRL_HDR_HASHREF_3             83
+#define SRL_HDR_HASHREF_4             84
+#define SRL_HDR_HASHREF_5             85
+#define SRL_HDR_HASHREF_6             86
+#define SRL_HDR_HASHREF_7             87
+#define SRL_HDR_HASHREF_8             88
+#define SRL_HDR_HASHREF_9             89
+#define SRL_HDR_HASHREF_10            90
+#define SRL_HDR_HASHREF_11            91
+#define SRL_HDR_HASHREF_12            92
+#define SRL_HDR_HASHREF_13            93
+#define SRL_HDR_HASHREF_14            94
+#define SRL_HDR_HASHREF_15            95
+#define SRL_HDR_SHORT_BINARY_0        96
+#define SRL_HDR_SHORT_BINARY_1        97
+#define SRL_HDR_SHORT_BINARY_2        98
+#define SRL_HDR_SHORT_BINARY_3        99
+#define SRL_HDR_SHORT_BINARY_4       100
+#define SRL_HDR_SHORT_BINARY_5       101
+#define SRL_HDR_SHORT_BINARY_6       102
+#define SRL_HDR_SHORT_BINARY_7       103
+#define SRL_HDR_SHORT_BINARY_8       104
+#define SRL_HDR_SHORT_BINARY_9       105
+#define SRL_HDR_SHORT_BINARY_10      106
+#define SRL_HDR_SHORT_BINARY_11      107
+#define SRL_HDR_SHORT_BINARY_12      108
+#define SRL_HDR_SHORT_BINARY_13      109
+#define SRL_HDR_SHORT_BINARY_14      110
+#define SRL_HDR_SHORT_BINARY_15      111
+#define SRL_HDR_SHORT_BINARY_16      112
+#define SRL_HDR_SHORT_BINARY_17      113
+#define SRL_HDR_SHORT_BINARY_18      114
+#define SRL_HDR_SHORT_BINARY_19      115
+#define SRL_HDR_SHORT_BINARY_20      116
+#define SRL_HDR_SHORT_BINARY_21      117
+#define SRL_HDR_SHORT_BINARY_22      118
+#define SRL_HDR_SHORT_BINARY_23      119
+#define SRL_HDR_SHORT_BINARY_24      120
+#define SRL_HDR_SHORT_BINARY_25      121
+#define SRL_HDR_SHORT_BINARY_26      122
+#define SRL_HDR_SHORT_BINARY_27      123
+#define SRL_HDR_SHORT_BINARY_28      124
+#define SRL_HDR_SHORT_BINARY_29      125
+#define SRL_HDR_SHORT_BINARY_30      126
+#define SRL_HDR_SHORT_BINARY_31      127
+
+#define CASE_SRL_HDR_ARRAYREF    \
+   case SRL_HDR_ARRAYREF_0:    \
+   case SRL_HDR_ARRAYREF_1:    \
+   case SRL_HDR_ARRAYREF_2:    \
+   case SRL_HDR_ARRAYREF_3:    \
+   case SRL_HDR_ARRAYREF_4:    \
+   case SRL_HDR_ARRAYREF_5:    \
+   case SRL_HDR_ARRAYREF_6:    \
+   case SRL_HDR_ARRAYREF_7:    \
+   case SRL_HDR_ARRAYREF_8:    \
+   case SRL_HDR_ARRAYREF_9:    \
+   case SRL_HDR_ARRAYREF_10:    \
+   case SRL_HDR_ARRAYREF_11:    \
+   case SRL_HDR_ARRAYREF_12:    \
+   case SRL_HDR_ARRAYREF_13:    \
+   case SRL_HDR_ARRAYREF_14:    \
+   case SRL_HDR_ARRAYREF_15
+
+
+#define CASE_SRL_HDR_HASHREF    \
+   case SRL_HDR_HASHREF_0:    \
+   case SRL_HDR_HASHREF_1:    \
+   case SRL_HDR_HASHREF_2:    \
+   case SRL_HDR_HASHREF_3:    \
+   case SRL_HDR_HASHREF_4:    \
+   case SRL_HDR_HASHREF_5:    \
+   case SRL_HDR_HASHREF_6:    \
+   case SRL_HDR_HASHREF_7:    \
+   case SRL_HDR_HASHREF_8:    \
+   case SRL_HDR_HASHREF_9:    \
+   case SRL_HDR_HASHREF_10:    \
+   case SRL_HDR_HASHREF_11:    \
+   case SRL_HDR_HASHREF_12:    \
+   case SRL_HDR_HASHREF_13:    \
+   case SRL_HDR_HASHREF_14:    \
+   case SRL_HDR_HASHREF_15
+
+
+#define CASE_SRL_HDR_NEG    \
+   case SRL_HDR_NEG_16:    \
+   case SRL_HDR_NEG_15:    \
+   case SRL_HDR_NEG_14:    \
+   case SRL_HDR_NEG_13:    \
+   case SRL_HDR_NEG_12:    \
+   case SRL_HDR_NEG_11:    \
+   case SRL_HDR_NEG_10:    \
+   case SRL_HDR_NEG_9:    \
+   case SRL_HDR_NEG_8:    \
+   case SRL_HDR_NEG_7:    \
+   case SRL_HDR_NEG_6:    \
+   case SRL_HDR_NEG_5:    \
+   case SRL_HDR_NEG_4:    \
+   case SRL_HDR_NEG_3:    \
+   case SRL_HDR_NEG_2:    \
+   case SRL_HDR_NEG_1
+
+
+#define CASE_SRL_HDR_POS    \
+   case SRL_HDR_POS_0:    \
+   case SRL_HDR_POS_1:    \
+   case SRL_HDR_POS_2:    \
+   case SRL_HDR_POS_3:    \
+   case SRL_HDR_POS_4:    \
+   case SRL_HDR_POS_5:    \
+   case SRL_HDR_POS_6:    \
+   case SRL_HDR_POS_7:    \
+   case SRL_HDR_POS_8:    \
+   case SRL_HDR_POS_9:    \
+   case SRL_HDR_POS_10:    \
+   case SRL_HDR_POS_11:    \
+   case SRL_HDR_POS_12:    \
+   case SRL_HDR_POS_13:    \
+   case SRL_HDR_POS_14:    \
+   case SRL_HDR_POS_15
+
+
+#define CASE_SRL_HDR_RESERVED    \
+   case SRL_HDR_RESERVED_0:    \
+   case SRL_HDR_RESERVED_1:    \
+   case SRL_HDR_RESERVED_2:    \
+   case SRL_HDR_RESERVED_3:    \
+   case SRL_HDR_RESERVED_4
+
+
+#define CASE_SRL_HDR_SHORT_BINARY    \
+   case SRL_HDR_SHORT_BINARY_0:    \
+   case SRL_HDR_SHORT_BINARY_1:    \
+   case SRL_HDR_SHORT_BINARY_2:    \
+   case SRL_HDR_SHORT_BINARY_3:    \
+   case SRL_HDR_SHORT_BINARY_4:    \
+   case SRL_HDR_SHORT_BINARY_5:    \
+   case SRL_HDR_SHORT_BINARY_6:    \
+   case SRL_HDR_SHORT_BINARY_7:    \
+   case SRL_HDR_SHORT_BINARY_8:    \
+   case SRL_HDR_SHORT_BINARY_9:    \
+   case SRL_HDR_SHORT_BINARY_10:    \
+   case SRL_HDR_SHORT_BINARY_11:    \
+   case SRL_HDR_SHORT_BINARY_12:    \
+   case SRL_HDR_SHORT_BINARY_13:    \
+   case SRL_HDR_SHORT_BINARY_14:    \
+   case SRL_HDR_SHORT_BINARY_15:    \
+   case SRL_HDR_SHORT_BINARY_16:    \
+   case SRL_HDR_SHORT_BINARY_17:    \
+   case SRL_HDR_SHORT_BINARY_18:    \
+   case SRL_HDR_SHORT_BINARY_19:    \
+   case SRL_HDR_SHORT_BINARY_20:    \
+   case SRL_HDR_SHORT_BINARY_21:    \
+   case SRL_HDR_SHORT_BINARY_22:    \
+   case SRL_HDR_SHORT_BINARY_23:    \
+   case SRL_HDR_SHORT_BINARY_24:    \
+   case SRL_HDR_SHORT_BINARY_25:    \
+   case SRL_HDR_SHORT_BINARY_26:    \
+   case SRL_HDR_SHORT_BINARY_27:    \
+   case SRL_HDR_SHORT_BINARY_28:    \
+   case SRL_HDR_SHORT_BINARY_29:    \
+   case SRL_HDR_SHORT_BINARY_30:    \
+   case SRL_HDR_SHORT_BINARY_31
+
+
+
+/*
+* NOTE the above section is auto-updated by author_tools/update_from_header.pl
+
+=for autoupdater stop
+
+*/
+#endif
@@ -13,6 +13,7 @@ use Devel::Peek;
 use Encode qw(encode_utf8 is_utf8);
 use Scalar::Util qw(reftype blessed refaddr);
 use Config;
+use Carp qw(confess);
 
 # Dynamically load constants from whatever is being tested
 our ($Class, $ConstClass);
@@ -22,6 +23,12 @@ BEGIN {
     }
     elsif (-e "lib/Sereal/Decoder") {
         $Class = 'Sereal::Decoder';
+    }
+    elsif (-e "lib/Sereal/Merger") {
+        $Class = 'Sereal::Merger';
+    }
+    elsif (-e "lib/Sereal/Splitter") {
+        $Class = 'Sereal::Splitter';
     } else {
         die "Could not find an applicable Sereal constants location";
     }
@@ -115,10 +122,21 @@ sub dump_bless {
 }
 
 sub short_string {
-    die if length($_[0]) > SRL_MASK_SHORT_BINARY_LEN;
-    my $tag = SRL_HDR_SHORT_BINARY_LOW + length($_[0]);
-    $tag |= SRL_HDR_TRACK_FLAG if $_[1];
-    return pack("c a*",$tag,$_[0]);
+    my ($str, $alias)= @_;
+    $alias ||= 0;
+    my $length= length($str);
+    if ($length > SRL_MASK_SHORT_BINARY_LEN) {
+        confess "String too long for short_string(), alias=$alias length=$length";
+    }
+    my $tag = SRL_HDR_SHORT_BINARY_LOW + length($str);
+    if ($tag > SRL_HDR_SHORT_BINARY_HIGH) {
+        confess "Tag value larger than SRL_HDR_SHORT_BINARY_HIGH, tag=$tag; alias=$alias; length=$length";
+    }
+    $tag |= SRL_HDR_TRACK_FLAG if $alias;
+    if ($tag > 255) {
+        confess "Tag value over 255 in short_string(), tag=$tag; alias=$alias; length=$length; SRL_HDR_TRACK_FLAG=", SRL_HDR_TRACK_FLAG;
+    }
+    return chr($tag) . $str;
 }
 
 sub integer {
@@ -234,14 +252,13 @@ sub setup_tests {
         [[], array(), "empty array ref"],
         [[1,2,3], array(chr(0b0000_0001), chr(0b0000_0010), chr(0b0000_0011)), "array ref"],
         [1000, chr(SRL_HDR_VARINT).varint(1000), "large int"],
-        [ [1..1000],
+        [ [ map { $_, undef } 1..1000 ],
             array(
-                (map chr, (1 .. SRL_POS_MAX_SIZE)),
-                (map chr(SRL_HDR_VARINT) . varint($_), ((SRL_POS_MAX_SIZE+1) .. 1000))
+                (map { chr($_) => chr(SRL_HDR_UNDEF) } (1 .. SRL_POS_MAX_SIZE)),
+                (map { chr(SRL_HDR_VARINT) . varint($_) => chr(SRL_HDR_UNDEF) } ((SRL_POS_MAX_SIZE+1) .. 1000))
             ),
-            "array ref with pos and varints"
+            "array ref with pos and varints and undef"
         ],
-
         [{}, hash(), "empty hash ref"],
         [{foo => "baaaaar"}, hash(short_string("foo"),short_string("baaaaar")), "simple hash ref"],
         [
@@ -1,6 +1,10 @@
 # O_OBJECT	-> link an opaque C or C++ object to a blessed Perl object.
 srl_encoder_t * O_OBJECT
 srl_decoder_t * O_OBJECT
+srl_merger_t  * O_OBJECT
+
+# T_OBJECT
+Sereal::Splitter  T_PTROBJ
 
 ######################################################################
 OUTPUT
@@ -20,4 +24,3 @@ O_OBJECT
 		warn( \"${Package}::$func_name() -- $var is not a blessed SV reference\" );
 		XSRETURN_UNDEF;
 	}
-