| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591 | {    Copyright (c) 2007 by Daniel Mantione    This unit implements a Tconstexprint type. This type simulates an integer    type that can handle numbers from low(int64) to high(qword) calculations.    This program is free software; you can redistribute it and/or modify    it under the terms of the GNU General Public License as published by    the Free Software Foundation; either version 2 of the License, or    (at your option) any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.    You should have received a copy of the GNU General Public License    along with this program; if not, write to the Free Software    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ****************************************************************************}unit constexp;{$i fpcdefs.inc}interfacetype  Tconstexprint=record        overflow:boolean;        case signed:boolean of          false:            (uvalue:qword);          true:            (svalue:int64);      end;      errorproc=procedure (i:longint);{"Uses verbose" gives a dependency on cpuinfo through globals. This leads build trouble when compiling the directory utils, since the cpu directory isn't searched there. Therefore we use a procvar and make verbose install the errorhandler. A dependency from verbose on this unit is no problem.}var   internalerrorproc:errorproc;{Same issue, avoid dependency on cpuinfo because the cpu directory isn't searched during utils building.}{$ifdef GENERIC_CPU}type  bestreal=extended;{$else}{$ifdef x86}type  bestreal=extended;{$else}type  bestreal=double;{$endif}{$endif}operator := (const u:qword):Tconstexprint;inline;operator := (const s:int64):Tconstexprint;inline;operator := (const c:Tconstexprint):qword;operator := (const c:Tconstexprint):int64;operator := (const c:Tconstexprint):bestreal;operator + (const a,b:Tconstexprint):Tconstexprint;operator - (const a,b:Tconstexprint):Tconstexprint;operator - (const a:Tconstexprint):Tconstexprint;operator * (const a,b:Tconstexprint):Tconstexprint;operator div (const a,b:Tconstexprint):Tconstexprint;operator mod (const a,b:Tconstexprint):Tconstexprint;operator / (const a,b:Tconstexprint):bestreal;operator = (const a,b:Tconstexprint):boolean;operator > (const a,b:Tconstexprint):boolean;operator >= (const a,b:Tconstexprint):boolean;operator < (const a,b:Tconstexprint):boolean;operator <= (const a,b:Tconstexprint):boolean;operator and (const a,b:Tconstexprint):Tconstexprint;operator or (const a,b:Tconstexprint):Tconstexprint;operator xor (const a,b:Tconstexprint):Tconstexprint;operator shl (const a,b:Tconstexprint):Tconstexprint;operator shr (const a,b:Tconstexprint):Tconstexprint;function tostr(const i:Tconstexprint):shortstring;overload;{****************************************************************************}implementation{****************************************************************************}{ use a separate procedure here instead of calling internalerrorproc directly because  - procedure variables cannot have a noreturn directive  - having a procedure and a procedure variable with the same name in the interfaces of different units is confusing }procedure internalerror(i:longint);{$ifndef VER2_6}noreturn;{$endif VER2_6}begin  internalerrorproc(i);end;operator := (const u:qword):Tconstexprint;begin  result.overflow:=false;  result.signed:=false;  result.uvalue:=u;end;operator := (const s:int64):Tconstexprint;begin  result.overflow:=false;  result.signed:=true;  result.svalue:=s;end;operator := (const c:Tconstexprint):qword;begin  if c.overflow then    internalerror(200706091)  else if not c.signed then    result:=c.uvalue  else if c.svalue<0 then    internalerror(200706092)  else    result:=qword(c.svalue);end;operator := (const c:Tconstexprint):int64;begin  if c.overflow then    internalerror(200706093)  else if c.signed then    result:=c.svalue  else if c.uvalue>qword(high(int64)) then    internalerror(200706094)  else    result:=int64(c.uvalue);end;operator := (const c:Tconstexprint):bestreal;begin  if c.overflow then    internalerror(200706095)  else if c.signed then    result:=c.svalue  else    result:=c.uvalue;end;function add_to(const a:Tconstexprint;b:qword):Tconstexprint;var sspace,uspace:qword;label try_qword;begin  result.overflow:=false;  {Try if the result fits in an int64.}  if (a.signed) and (a.svalue<0) then    {$push}{$Q-}    sspace:=qword(high(int64))+qword(-a.svalue)    {$pop}  else if not a.signed and (a.uvalue>qword(high(int64))) then    goto try_qword  else    sspace:=qword(high(int64))-a.svalue;  if sspace>=b then    begin      result.signed:=true;      {$push} {$Q-}      result.svalue:=a.svalue+int64(b);      {$pop}      exit;    end;  {Try if the result fits in a qword.}try_qword:  if (a.signed) and (a.svalue<0) then    uspace:=high(qword)-qword(-a.svalue){  else if not a.signed and (a.uvalue>qword(high(int64))) then    uspace:=high(qword)-a.uvalue}  else    uspace:=high(qword)-a.uvalue;  if uspace>=b then    begin      result.signed:=false;      {$push} {$Q-}      result.uvalue:=a.uvalue+b;      {$pop}      exit;    end;  result.overflow:=true;end;{ workaround for 2.6.x bug }{$ifdef VER2_6}    {$push} {$Q-}{$endif VER2_6}function sub_from(const a:Tconstexprint;b:qword):Tconstexprint;const abs_low_int64=qword(9223372036854775808);   {abs(low(int64)) -> overflow error}var sspace:qword;label try_qword,ov;begin  result.overflow:=false;  {Try if the result fits in an int64.}  if (a.signed) and (a.svalue<0) then    {$push} {$Q-}    sspace:=qword(a.svalue)+abs_low_int64    {$pop}  else if not a.signed and (a.uvalue>qword(high(int64))) then    goto try_qword  else    sspace:=a.uvalue+qword(abs(low(int64)));  if sspace>=b then    begin      result.signed:=true;      {$push} {$Q-}      result.svalue:=a.svalue-int64(b);      {$pop}      exit;    end;  {Try if the result fits in a qword.}try_qword:  if not(a.signed and (a.svalue<0)) and (a.uvalue>=b) then    begin      result.signed:=false;      {$push} {$Q-}      result.uvalue:=a.uvalue-b;      {$pop}      exit;    end;ov:  result.overflow:=true;end;{ workaround for 2.6.x bug }{$ifdef VER2_6}    {$pop}{$endif VER2_6}operator + (const a,b:Tconstexprint):Tconstexprint;begin  if a.overflow or b.overflow then    begin      result.overflow:=true;      exit;    end;  if b.signed and (b.svalue<0) then    {$push} {$Q-}    result:=sub_from(a,qword(-b.svalue))    {$pop}  else    result:=add_to(a,b.uvalue);end;operator - (const a,b:Tconstexprint):Tconstexprint;begin  if a.overflow or b.overflow then    begin      result.overflow:=true;      exit;    end;  if b.signed and (b.svalue<0) then    {$push} {$Q-}    result:=add_to(a,qword(-b.svalue))    {$pop}  else    result:=sub_from(a,b.uvalue);end;operator - (const a:Tconstexprint):Tconstexprint;begin  if not a.signed and (a.uvalue>qword(high(int64))) then    result.overflow:=true  else    begin      result.overflow:=false;      result.signed:=true;      result.svalue:=-a.svalue;    end;end;operator * (const a,b:Tconstexprint):Tconstexprint;var aa,bb,r:qword;    sa,sb:boolean;begin  if a.overflow or b.overflow then    begin      result.overflow:=true;      exit;    end;  result.overflow:=false;  sa:=a.signed and (a.svalue<0);  if sa then     aa:=qword(-a.svalue)  else    aa:=a.uvalue;  sb:=b.signed and (b.svalue<0);  if sb then    bb:=qword(-b.svalue)  else    bb:=b.uvalue;  if (bb<>0) and (high(qword) div bb<aa) then    result.overflow:=true  else    begin      r:=aa*bb;      if sa xor sb then        begin          result.signed:=true;          if r>qword(high(int64)) then            result.overflow:=true          else            result.svalue:=-int64(r);        end      else        begin          result.signed:=false;          result.uvalue:=r;        end;    end;end;operator div (const a,b:Tconstexprint):Tconstexprint;var aa,bb,r:qword;    sa,sb:boolean;begin  if a.overflow or b.overflow then    begin      result.overflow:=true;      exit;    end;  result.overflow:=false;  sa:=a.signed and (a.svalue<0);  if sa then    {$push} {$Q-}    aa:=qword(-a.svalue)    {$pop}  else    aa:=a.uvalue;  sb:=b.signed and (b.svalue<0);  if sb then    {$push} {$Q-}    bb:=qword(-b.svalue)    {$pop}  else    bb:=b.uvalue;  if bb=0 then    result.overflow:=true  else    begin      r:=aa div bb;      if sa xor sb then        begin          result.signed:=true;          if r>qword(high(int64)) then            result.overflow:=true          else            result.svalue:=-int64(r);        end      else        begin          result.signed:=false;          result.uvalue:=r;        end;    end;end;operator mod (const a,b:Tconstexprint):Tconstexprint;var aa,bb,r:qword;    sa,sb:boolean;begin  if a.overflow or b.overflow then    begin      result.overflow:=true;      exit;    end;  result.overflow:=false;  sa:=a.signed and (a.svalue<0);  if sa then    {$push} {$Q-}    aa:=qword(-a.svalue)    {$pop}  else    aa:=a.uvalue;  sb:=b.signed and (b.svalue<0);  if sb then    {$push} {$Q-}    bb:=qword(-b.svalue)    {$pop}  else    bb:=b.uvalue;  if bb=0 then    result.overflow:=true  else    begin      { the sign of a modulo operation only depends on the sign of the        dividend }      r:=aa mod bb;      result.signed:=sa;      if not sa then        result.uvalue:=r      else        result.svalue:=-int64(r);    end;end;operator / (const a,b:Tconstexprint):bestreal;var aa,bb:bestreal;begin  if a.overflow or b.overflow then    internalerror(200706096);  if a.signed then    aa:=a.svalue  else    aa:=a.uvalue;  if b.signed then    bb:=b.svalue  else    bb:=b.uvalue;  result:=aa/bb;end;operator = (const a,b:Tconstexprint):boolean;begin  if a.signed and (a.svalue<0) then    if b.signed and (b.svalue<0) then      result:=a.svalue=b.svalue    else if b.uvalue>qword(high(int64)) then      result:=false    else      result:=a.svalue=b.svalue  else    if not (b.signed and (b.svalue<0)) then      result:=a.uvalue=b.uvalue    else if a.uvalue>qword(high(int64)) then      result:=false    else      result:=a.svalue=b.svalueend;operator > (const a,b:Tconstexprint):boolean;begin  if a.signed and (a.svalue<0) then    if b.signed and (b.svalue<0) then      result:=a.svalue>b.svalue    else if b.uvalue>qword(high(int64)) then      result:=false    else      result:=a.svalue>b.svalue  else    if not (b.signed and (b.svalue<0)) then      result:=a.uvalue>b.uvalue    else if a.uvalue>qword(high(int64)) then      result:=true    else      result:=a.svalue>b.svalueend;operator >= (const a,b:Tconstexprint):boolean;begin  if a.signed and (a.svalue<0) then    if b.signed and (b.svalue<0) then      result:=a.svalue>=b.svalue    else if b.uvalue>qword(high(int64)) then      result:=false    else      result:=a.svalue>=b.svalue  else    if not (b.signed and (b.svalue<0)) then      result:=a.uvalue>=b.uvalue    else if a.uvalue>qword(high(int64)) then      result:=true    else      result:=a.svalue>=b.svalueend;operator < (const a,b:Tconstexprint):boolean;begin  if a.signed and (a.svalue<0) then    if b.signed and (b.svalue<0) then      result:=a.svalue<b.svalue    else if b.uvalue>qword(high(int64)) then      result:=true    else      result:=a.svalue<b.svalue  else    if not (b.signed and (b.svalue<0)) then      result:=a.uvalue<b.uvalue    else if a.uvalue>qword(high(int64)) then      result:=false    else      result:=a.svalue<b.svalueend;operator <= (const a,b:Tconstexprint):boolean;begin  if a.signed and (a.svalue<0) then    if b.signed and (b.svalue<0) then      result:=a.svalue<=b.svalue    else if b.uvalue>qword(high(int64)) then      result:=true    else      result:=a.svalue<=b.svalue  else    if not (b.signed and (b.svalue<0)) then      result:=a.uvalue<=b.uvalue    else if a.uvalue>qword(high(int64)) then      result:=false    else      result:=a.svalue<=b.svalueend;operator and (const a,b:Tconstexprint):Tconstexprint;begin  result.overflow:=false;  result.signed:=a.signed or b.signed;  result.uvalue:=a.uvalue and b.uvalue;end;operator or (const a,b:Tconstexprint):Tconstexprint;begin  result.overflow:=false;  result.signed:=a.signed or b.signed;  result.uvalue:=a.uvalue or b.uvalue;end;operator xor (const a,b:Tconstexprint):Tconstexprint;begin  result.overflow:=false;  result.signed:=a.signed or b.signed;  result.uvalue:=a.uvalue xor b.uvalue;end;operator shl (const a,b:Tconstexprint):Tconstexprint;begin  result.overflow:=false;  result.signed:=a.signed;  result.uvalue:=a.uvalue shl b.uvalue;end;operator shr (const a,b:Tconstexprint):Tconstexprint;begin  result.overflow:=false;  result.signed:=a.signed;  result.uvalue:=a.uvalue shr b.uvalue;end;function tostr(const i:Tconstexprint):shortstring;overload;begin  if i.signed then    str(i.svalue,result)  else    str(i.uvalue,result);end;end.
 |