package Math::AnyInt; #use 5.006; use v5.36; use strict; use warnings; our $VERSION = '0.01'; use Exporter qw(import); our @EXPORT = qw( calcop VERBOSE_AnyInt ); # caller can set this to 0 or 1 our $VERBOSE_AnyInt = 0; # overload basic arithmetic operators use overload '+' => sub { # we get 3 params: 1+2 are objects of this class, swap is ... well # get the value of the objects, do the operation # and then convert to 32bit my ($self, $other, $swap) = @_; if( $VERBOSE_AnyInt > 0 ){ print STDOUT "+ : operating on ".(defined($self)&&defined($$self)?$$self:'')." and ".(defined($other)?$other:'')." (swap is ".(defined($swap)?($swap?'yes':'no'):'').")\n" } Math::AnyInt->new( calc_32bit_signed($self->value() + $other->value()) ); }, '-' => sub { my ($self, $other, $swap) = @_; if( $VERBOSE_AnyInt > 0 ){ print STDOUT "- : operating on ".(defined($self)&&defined($$self)?$$self:'')." and ".(defined($other)?$other:'')." (swap is ".(defined($swap)?($swap?'yes':'no'):'').")\n" } return $swap ? Math::AnyInt->new( calc_32bit_signed($self->value() - $other->value()) ) : Math::AnyInt->new( calc_32bit_signed($other->value() - $self->value()) ) ; }, '*' => sub { my ($self, $other, $swap) = @_; if( $VERBOSE_AnyInt > 0 ){ print STDOUT "* : operating on ".(defined($self)&&defined($$self)?$$self:'')." and ".(defined($other)?$other:'')." (swap is ".(defined($swap)?($swap?'yes':'no'):'').")\n" } Math::AnyInt->new( calc_32bit_signed($self->value() + $other->value()) ); }, '/' => sub { my ($self, $other, $swap) = @_; if( $VERBOSE_AnyInt > 0 ){ print STDOUT "/ : operating on ".(defined($self)&&defined($$self)?$$self:'')." and ".(defined($other)?$other:'')." (swap is ".(defined($swap)?($swap?'yes':'no'):'').")\n" } return $swap ? Math::AnyInt->new( calc_32bit_signed($self->value() / $other->value()) ) : Math::AnyInt->new( calc_32bit_signed($other->value() / $self->value()) ) ; }, '<<' => sub { my ($self, $other, $swap) = @_; if( $VERBOSE_AnyInt > 0 ){ print STDOUT "<< : operating on ".(defined($self)&&defined($$self)?$$self:'')." and ".(defined($other)?$other:'')." (swap is ".(defined($swap)?($swap?'yes':'no'):'').")\n" } # if operands were swapped, it does matter in this case if( $swap ){ die "<< : order is important why is swap on?" } Math::AnyInt->new( calc_32bit_signed($self->value() << $other->value()) ); }, '>>' => sub { my ($self, $other, $swap) = @_; if( $VERBOSE_AnyInt > 0 ){ print STDOUT ">> : operating on ".(defined($self)&&defined($$self)?$$self:'')." and ".(defined($other)?$other:'')." (swap is ".(defined($swap)?($swap?'yes':'no'):'').")\n" } if( $swap ){ die "<< : order is important why is swap on?" } Math::AnyInt->new( calc_32bit_signed($self->value() >> $other->value()) ); }, '**' => sub { my ($self, $other, $swap) = @_; if( $VERBOSE_AnyInt > 0 ){ print STDOUT "** : operating on ".(defined($self)&&defined($$self)?$$self:'')." and ".(defined($other)?$other:'')." (swap is ".(defined($swap)?($swap?'yes':'no'):'').")\n" } if( $swap ){ die "<< : order is important why is swap on?" } Math::AnyInt->new( calc_32bit_signed($self->value() ** $other->value()) ); }, '""' => sub { ${$_[0]} } ; sub new { my ($class, $val) = @_; return bless \$val } # Corion's converting to 32bit signed int sub calc_32bit_signed { return unpack("l", pack("L", $_[0])) } ##sub calc_32bit_signed { unpack( "l", pack "L", ($_[0] & 0xffffffff)) } # NERDVANA's converting to 32bit signed int #sub calc_32bit_signed { return calc_32bit_signed_in_C($_[0]) } use Inline 'C', <<~'END'; #include long calc_32bit_signed_in_C(long input) { return (int32_t)((int32_t)input); } long test_addition_in_C(long l, long r) { return (int32_t)((int32_t)l + (int32_t)r); } END # return the integer value contain in this object # which is just a ref to the value (see new()) sub value { return ${ $_[0] } } # this does the arithmetic when the operator is in string format, useful for testing sub calcop { my ($lop, $op, $rop) = @_; if( ref($lop) ne __PACKAGE__ ){ die 'calcop()'." : left-operant must be a ".__PACKAGE__." object but it is just '".ref($lop)."'."; } if( ref($rop) ne __PACKAGE__ ){ die 'calcop()'." : right-operant must be a ".__PACKAGE__." object but it is just '".ref($rop)."'."; } if( $VERBOSE_AnyInt > 0 ){ print STDOUT 'calcop()'." : called for '$$lop' '$op' '$$rop' ...\n" } if( $op eq '+' ){ return $lop + $rop; } elsif( $op eq '-' ){ return $lop - $rop } elsif( $op eq '*' ){ return $lop * $rop } elsif( $op eq '/' ){ return $lop / $rop } elsif( $op eq '<<' ){ return $lop << $rop } elsif( $op eq '>>' ){ return $lop >> $rop } elsif( $op eq '**' ){ return $lop ** $rop } die 'calcop()'." : unknown operator '$op'."; } 1;