summaryrefslogtreecommitdiffstats
path: root/MDK/Common/Func.pm
diff options
context:
space:
mode:
Diffstat (limited to 'MDK/Common/Func.pm')
-rw-r--r--MDK/Common/Func.pm117
1 files changed, 117 insertions, 0 deletions
diff --git a/MDK/Common/Func.pm b/MDK/Common/Func.pm
new file mode 100644
index 0000000..55277c9
--- /dev/null
+++ b/MDK/Common/Func.pm
@@ -0,0 +1,117 @@
+package MDK::Common::Func;
+
+use MDK::Common::Math;
+
+
+use vars qw(@ISA %EXPORT_TAGS @EXPORT_OK);
+@ISA = qw(Exporter);
+@EXPORT_OK = qw(fold_left mapn mapn_ map_index grep_index find_index map_each grep_each before_leaving catch_cdie cdie);
+%EXPORT_TAGS = (all => [ @EXPORT_OK ]);
+
+
+sub fold_left(&@) {
+ my ($f, $initial, @l) = @_;
+ local ($::a, $::b);
+ $::a = $initial;
+ foreach $::b (@_) { $::a = &$f() }
+ $::a
+}
+
+sub smapn {
+ my $f = shift;
+ my $n = shift;
+ my @r = ();
+ for (my $i = 0; $i < $n; $i++) { push @r, &$f(map { $_->[$i] } @_); }
+ @r
+}
+sub mapn(&@) {
+ my $f = shift;
+ smapn($f, MDK::Common::Math::min(map { scalar @$_ } @_), @_);
+}
+sub mapn_(&@) {
+ my $f = shift;
+ smapn($f, MDK::Common::Math::max(map { scalar @$_ } @_), @_);
+}
+
+
+sub map_index(&@) {
+ my $f = shift;
+ my @v; local $::i = 0;
+ map { @v = &$f($::i); $::i++; @v } @_;
+}
+sub grep_index(&@) {
+ my $f = shift;
+ my $v; local $::i = 0;
+ grep { $v = &$f($::i); $::i++; $v } @_;
+}
+sub find_index(&@) {
+ my $f = shift;
+ local $_;
+ for (my $i = 0; $i < @_; $i++) {
+ $_ = $_[$i];
+ &$f and return $i;
+ }
+ die "find_index failed in @_";
+}
+sub map_each(&%) {
+ my ($f, %h) = @_;
+ my @l;
+ local ($::a, $::b);
+ while (($::a, $::b) = each %h) { push @l, &$f($::a, $::b) }
+ @l;
+}
+sub grep_each(&%) {
+ my ($f, %h) = @_;
+ my %l;
+ local ($::a, $::b);
+ while (($::a, $::b) = each %h) { $l{$::a} = $::b if &$f($::a, $::b) }
+ %l;
+}
+
+
+sub add_f4before_leaving {
+ my ($f, $b, $name) = @_;
+
+ unless ($MDK::Common::Func::before_leaving::{$name}) {
+ no strict 'refs';
+ ${"MDK::Common::Func::before_leaving::$name"} = 1;
+ ${"MDK::Common::Func::before_leaving::list"} = 1;
+ }
+ local *N = *{$MDK::Common::Func::before_leaving::{$name}};
+ my $list = *MDK::Common::Func::before_leaving::list;
+ $list->{$b}{$name} = $f;
+ *N = sub {
+ my $f = $list->{$_[0]}{$name} or die '';
+ $name eq 'DESTROY' and delete $list->{$_[0]};
+ goto $f;
+ } unless defined &{*N};
+
+}
+
+#- ! the functions are not called in the order wanted, in case of multiple before_leaving :(
+sub before_leaving(&) {
+ my ($f) = @_;
+ my $b = bless {}, 'MDK::Common::Func::before_leaving';
+ add_f4before_leaving($f, $b, 'DESTROY');
+ $b;
+}
+
+sub catch_cdie(&&) {
+ my ($f, $catch) = @_;
+
+ local @MDK::Common::Func::cdie_catches;
+ unshift @MDK::Common::Func::cdie_catches, $catch;
+ &$f();
+}
+
+sub cdie {
+ my ($err, $f) = @_;
+ foreach (@MDK::Common::Func::cdie_catches) {
+ $@ = $err;
+ &{$_}(\$err) and return;
+ }
+ die $err;
+}
+
+1;
+