aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad S Anwar <Mohammad.Anwar@yahoo.com>2019-08-25 18:33:50 +0100
committerGitHub <noreply@github.com>2019-08-25 18:33:50 +0100
commit6d193014b665265d0a7a2d9f5bda76d07d6e485a (patch)
tree48eecff6c1bccc2010b0c88db4fd84583705b74b
parentf62f089a449a880c427cf524014f144e2e92c198 (diff)
parentd89f97156eeb6e0b71ae806aefc24b6da1640b1d (diff)
downloadperlweeklychallenge-club-6d193014b665265d0a7a2d9f5bda76d07d6e485a.tar.gz
perlweeklychallenge-club-6d193014b665265d0a7a2d9f5bda76d07d6e485a.tar.bz2
perlweeklychallenge-club-6d193014b665265d0a7a2d9f5bda76d07d6e485a.zip
Merge pull request #553 from jmaslak/joelle-22-2-1
Joelle's solutions to 22.2 in P5 and P6
-rwxr-xr-xchallenge-022/joelle-maslak/perl5/ch-2.pl292
-rwxr-xr-xchallenge-022/joelle-maslak/perl6/ch-2.p6185
2 files changed, 477 insertions, 0 deletions
diff --git a/challenge-022/joelle-maslak/perl5/ch-2.pl b/challenge-022/joelle-maslak/perl5/ch-2.pl
new file mode 100755
index 0000000000..25e24283b0
--- /dev/null
+++ b/challenge-022/joelle-maslak/perl5/ch-2.pl
@@ -0,0 +1,292 @@
+#!/usr/bin/env perl
+use v5.26;
+use strict;
+use warnings;
+
+# Gets the name of the most recent newsletter
+
+# Turn on method signatures
+use feature 'signatures';
+no warnings 'experimental::signatures';
+
+use autodie;
+use bignum;
+use Getopt::Long;
+
+sub main() {
+ my $bits = 12;
+ my ( $infile, $outfile );
+ GetOptions(
+ "infile=s" => \$infile,
+ "outfile=s" => \$outfile,
+ "bits=i" => \$bits,
+ );
+ if ( @ARGV == 0 ) { die("Must provide command (compress/decompress)") }
+ if ( @ARGV > 1 ) { die("Invalid parameter") }
+
+ my $command = shift(@ARGV);
+ die "Must provide --infile option" unless defined($infile);
+ die "Must provide --outfile option" unless defined($outfile);
+
+ die "--infile not readable" unless -r $infile;
+ die "--outfile exists" if -e $outfile;
+
+ die "--bits must be >= 8" unless $bits >= 8;
+
+ if ( $command eq 'compress' ) {
+ compress( $infile, $outfile, $bits );
+ } elsif ( $command eq 'decompress' ) {
+ decompress( $infile, $outfile, $bits );
+ } else {
+ die "Unknown command: $command";
+ }
+}
+
+sub compress ( $infile, $outfile, $bits ) {
+ my $dict = Dictionary->new( bits => $bits );
+
+ open my $in, '<:raw', $infile;
+ my $out = BitwiseWrite->new( filename => $outfile, bits => $bits );
+
+ my $buf = '';
+ my $c;
+ while (read $in, $c, 1) {
+ $buf .= $c;
+ next if $dict->lookup($buf);
+
+ # Okay, we don't have the string - how much do we write out?
+ $dict->store($buf); # First we store this for future use.
+
+ # Now we write up what we can lookup
+ $buf = substr( $buf, 0, length($buf) - 1 );
+ $out->write( $dict->lookup($buf) );
+
+ # Now we reset the buffer
+ $buf = $c;
+ }
+ close $in;
+
+ # Flush pending buffered characters (if any)
+ $out->write( $dict->lookup($buf) ) unless $buf eq '';
+
+ $out->close;
+}
+
+sub decompress ( $infile, $outfile, $bits ) {
+ my $dict = Dictionary->new( bits => $bits );
+
+ my $in = BitwiseRead->new(filename => $infile, bits => $bits);
+ open my $out, '>:raw', $outfile;
+
+ my $prevbuf = '';
+ while (defined(my $value = $in->read())) {
+ my $buf = $dict->index($value);
+ if (!defined($buf)) {
+ $buf = $prevbuf;
+ $buf .= substr($buf, 0, 1);
+ $dict->store($buf);
+ } else {
+ if ($prevbuf ne '') {
+ $prevbuf .= substr($buf, 0, 1);
+ $dict->store($prevbuf);
+ }
+ }
+ print $out $buf;
+ $prevbuf = $buf;
+ }
+}
+
+package Dictionary {
+ use Moose;
+ use feature 'signatures';
+ no warnings 'experimental::signatures';
+
+ has dict => (
+ is => 'ro',
+ isa => 'HashRef',
+ default => sub { return {} },
+ init_arg => undef,
+ );
+
+ has idx => (
+ is => 'ro',
+ isa => 'HashRef[Str]',
+ default => sub { return {} },
+ init_arg => undef,
+ );
+
+ has next => (
+ is => 'rw',
+ default => '0',
+ init_arg => undef,
+ );
+
+ has bits => (
+ is => 'ro',
+ default => sub { 12 },
+ );
+
+ sub BUILD ( $self, $args ) {
+ for my $i ( 0 .. 255 ) {
+ $self->store( chr($i) );
+ }
+ }
+
+ sub lookup ( $self, $val ) {
+ return $self->dict->{$val} if exists $self->dict->{$val};
+ return;
+ }
+
+ sub index ( $self, $index ) {
+ return unless exists $self->idx->{$index};
+ return $self->idx->{$index};
+ }
+
+ sub store ( $self, $val ) {
+ return $self->lookup($val) if defined $self->lookup($val);
+ return if $self->next >= 2**( $self->bits );
+
+ $self->dict->{$val} = $self->next;
+ $self->idx->{ $self->next } = $val;
+
+ $self->next( $self->next + 1 );
+
+ return $self->dict->{$val};
+ }
+
+ __PACKAGE__->meta->make_immutable;
+}
+
+package BitwiseWrite {
+ use Moose;
+ use feature 'signatures';
+ no warnings 'experimental::signatures';
+
+ has filename => (
+ is => 'ro',
+ isa => 'Str',
+ required => 1,
+ );
+
+ has bits => (
+ is => 'ro',
+ required => 1,
+ );
+
+ has fh => (
+ is => 'rw',
+ init_arg => undef,
+ );
+
+ has pending => (
+ is => 'rw',
+ default => sub { 0 },
+ init_arg => undef,
+ );
+
+ has pending_bits => (
+ is => 'rw',
+ default => sub { 0 },
+ init_arg => undef,
+ );
+
+ sub BUILD ( $self, $args ) {
+ open my $fh, '>:raw', $self->filename;
+ $self->fh($fh);
+ }
+
+ sub write ( $self, $val ) {
+ my $bits = $self->bits;
+
+ $val += $self->pending << $bits;
+ $bits += $self->pending_bits;
+
+ while ( $bits >= 8 ) {
+ my $tmp = ( $val >> ( $bits - 8 ) ) % 256;
+ my $fh = $self->fh;
+ print $fh chr($tmp);
+ $bits -= 8;
+ }
+
+ $self->pending( ( ( $val << ( 8 - $bits ) ) % 256 ) >> ( 8 - $bits ) );
+ $self->pending_bits($bits);
+ }
+
+ sub close($self) {
+ if ( $self->pending_bits > 0 ) {
+ my $fh = $self->fh;
+ print $fh chr( $self->pending << ( 8 - $self->pending_bits ) );
+ }
+ close $self->fh;
+ }
+
+ __PACKAGE__->meta->make_immutable;
+}
+
+package BitwiseRead {
+ use Moose;
+ use feature 'signatures';
+ no warnings 'experimental::signatures';
+
+ has filename => (
+ is => 'ro',
+ isa => 'Str',
+ required => 1,
+ );
+
+ has bits => (
+ is => 'ro',
+ required => 1,
+ );
+
+ has fh => (
+ is => 'rw',
+ init_arg => undef,
+ );
+
+ has pending => (
+ is => 'rw',
+ default => sub { 0 },
+ init_arg => undef,
+ );
+
+ has pending_bits => (
+ is => 'rw',
+ default => sub { 0 },
+ init_arg => undef,
+ );
+
+ sub BUILD($self, $args) {
+ open my $fh, '<:raw', $self->filename;
+ $self->fh($fh);
+ }
+
+ sub read($self) {
+ my $val = $self->pending;
+ my $bits = $self->pending_bits;
+
+ while ($bits < $self->bits) {
+ my $c;
+ return unless read $self->fh, $c, 1;
+
+ $val = $val << 8;
+ $val += ord($c);
+ $bits += 8;
+ }
+
+ $self->pending_bits( $bits - $self->bits );
+ my $out = $val >> $self->pending_bits;
+ $self->pending($val - ($out << $self->pending_bits) );
+
+ return $out;
+ }
+
+ sub close($self) {
+ close $self->fh;
+ }
+
+ __PACKAGE__->meta->make_immutable;
+}
+
+main();
+
diff --git a/challenge-022/joelle-maslak/perl6/ch-2.p6 b/challenge-022/joelle-maslak/perl6/ch-2.p6
new file mode 100755
index 0000000000..6dde6c44a7
--- /dev/null
+++ b/challenge-022/joelle-maslak/perl6/ch-2.p6
@@ -0,0 +1,185 @@
+#!/usr/bin/env perl6
+use v6.d;
+
+class Dictionary {
+ has %!dict;
+ has %!index;
+ has UInt:D $!next = 0;
+ has UInt:D $.bits where * ≥ 8;
+
+ method lookup(buf8:D $val -->UInt) {
+ my $key = $val.join(":");
+ return %!dict{$key} if %!dict{$key}:exists;
+
+ return UInt;
+ }
+
+ method index(UInt:D $index -->buf8) {
+ return buf8 unless %!index{$index}:exists;
+ return %!index{$index};
+ }
+
+ method store(buf8:D $val -->UInt) {
+ my $key = $val.join(":");
+ return self.lookup($val) if self.lookup($val).defined;
+ return UInt if $!next ≥ 2**$.bits;
+
+ %!dict{$key} = $!next;
+ %!index{$!next} = $val;
+
+ $!next++;
+
+ return %!dict{$key};
+ }
+
+ method TWEAK() {
+ for ^256 -> $i {
+ my $buf = buf8.new($i);
+ self.store($buf);
+ }
+ }
+}
+
+# Write bits out in MSB first format
+class Bitwise-Write {
+ has Str $.filename is required;
+ has UInt $.bits is required;
+
+ has $!fh;
+ has UInt:D $!pending = 0;
+ has UInt:D $!pending-bits = 0;
+
+ method TWEAK() {
+ $!fh = $.filename.IO.open: :w, :bin;
+ }
+
+ method write(UInt:D $val is copy) {
+ my $bits = $.bits;
+
+ $val += $!pending +< $bits;
+ $bits += $!pending-bits;
+
+ while $bits ≥ 8 {
+ my $tmp = ( $val +> ($bits - 8) ) % 2⁸;
+ $!fh.write(buf8.new($tmp));
+ $bits -= 8;
+ }
+
+ $!pending = ( ( $val +< (8 - $bits) ) % 2⁸ ) +> (8 - $bits);
+ $!pending-bits = $bits;
+ }
+
+ method close() {
+ if $!pending-bits > 0 {
+ $!fh.write(buf8.new( $!pending +< (8 - $!pending-bits) ));
+ }
+ $!fh.close;
+ }
+}
+
+# Read UInts out in MSB first format
+class Bitwise-Read {
+ has Str $.filename is required;
+ has UInt $.bits is required;
+
+ has $!fh;
+ has UInt:D $!pending = 0;
+ has UInt:D $!pending-bits = 0;
+
+ method TWEAK() {
+ $!fh = $.filename.IO.open: :r, :bin;
+ }
+
+ method read(-->UInt) {
+ my $val = $!pending;
+ my $bits = $!pending-bits;
+
+ while $bits < $!bits {
+ my $c = $!fh.read(1);
+ return UInt unless $c.elems;
+
+ $val = $val +< 8;
+ $val += $c[0];
+ $bits += 8;
+ }
+
+ $!pending-bits = $bits - $!bits;
+ my $out = $val +> $!pending-bits;
+ $!pending = $val - ($out +< $!pending-bits);
+
+ return $out;
+ }
+
+ method close() {
+ $!fh.close;
+ }
+}
+
+multi sub MAIN(
+ "compress",
+ Str:D :$infile,
+ Str:D :$outfile,
+ UInt:D :$bits where * ≥ 8 = 12,
+) {
+ # Initialize the dictionary
+ my $dict = Dictionary.new(:$bits);
+
+ my $in = $infile.IO.open: :r, :bin;
+ my $out = Bitwise-Write.new(:filename($outfile), :$bits);
+
+ my $buf = buf8.new;
+ while $in.read(1) -> $c {
+ $buf.push: $c;
+ next if $dict.lookup($buf);
+
+ # Okay, we don't have the string - how much do we write out?
+ $dict.store: $buf; # First we store this for future use.
+
+ # Now we write up what we can lookup
+ $buf.pop;
+ $out.write: $dict.lookup($buf);
+
+ # Now we reset the buffer
+ $buf = buf8.new($c);
+ }
+
+ # Flush pending buffered characters (if any)
+ $out.write($dict.lookup($buf)) if $buf.elems;
+
+ $in.close;
+ $out.close;
+}
+
+multi sub MAIN(
+ "decompress",
+ Str:D :$infile,
+ Str:D :$outfile,
+ UInt:D :$bits where * ≥ 8 = 12,
+) {
+ # Initialize the dictionary
+ my $dict = Dictionary.new(:$bits);
+
+ my $in = Bitwise-Read.new(:filename($infile), :$bits);
+ my $out = $outfile.IO.open: :w, :bin;
+
+ my $prevbuf = buf8.new;
+ while (my $value = $in.read()).defined {
+ my $buf = $dict.index($value);
+ if ! defined($buf) {
+ $buf = $prevbuf;
+ $buf.push: $buf[0];
+ $dict.store: $buf;
+ } else {
+ if $prevbuf.elems {
+ $prevbuf.push: $buf[0];
+ $dict.store($prevbuf);
+ }
+ }
+ $out.write: $buf;
+ $prevbuf = buf8.new: $buf;
+ }
+
+ $in.close;
+ $out.close;
+}
+