123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588 |
- {
- 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}
- interface
- { bootstrapping with 2.0.x }
- {$ifdef VER2_0}
- {$Q-}
- {$R-}
- {$endif}
- {$ifopt q+}
- {$define ena_q}
- {$endif}
- type Tconstexprint=record
- overflow:boolean;
- case signed:boolean of
- false:
- (uvalue:qword);
- true:
- (svalue:int64);
- end;
- Tconststring = type pchar;
- 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 internalerror: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
- {****************************************************************************}
- 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
- {$Q-}
- sspace:=qword(high(int64))+qword(-a.svalue)
- {$ifdef ena_q}{$Q+}{$endif}
- 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;
- {$Q-}
- result.svalue:=a.svalue+int64(b);
- {$ifdef ena_q}{$Q+}{$endif}
- 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;
- {$Q-}
- result.uvalue:=a.uvalue+b;
- {$ifdef ena_q}{$Q+}{$endif}
- exit;
- end;
- result.overflow:=true;
- end;
- 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
- {$Q-}
- sspace:=qword(a.svalue)+abs_low_int64
- {$ifdef ena_q}{$Q+}{$endif}
- 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;
- {$Q-}
- result.svalue:=a.svalue-int64(b);
- {$ifdef ena_q}{$Q+}{$endif}
- 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;
- {$Q-}
- result.uvalue:=a.uvalue-b;
- {$ifdef ena_q}{$Q+}{$endif}
- exit;
- end;
- ov:
- result.overflow:=true;
- 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
- {$Q-}
- result:=sub_from(a,qword(-b.svalue))
- {$ifdef ena_q}{$Q+}{$endif}
- 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
- {$Q-}
- result:=add_to(a,qword(-b.svalue))
- {$ifdef ena_q}{$Q+}{$endif}
- 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
- {$Q-}
- aa:=qword(-a.svalue)
- {$ifdef ena_q}{$Q+}{$endif}
- else
- aa:=a.uvalue;
- sb:=b.signed and (b.svalue<0);
- if sb then
- {$Q-}
- bb:=qword(-b.svalue)
- {$ifdef ena_q}{$Q+}{$endif}
- 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
- {$Q-}
- aa:=qword(-a.svalue)
- {$ifdef ena_q}{$Q+}{$endif}
- else
- aa:=a.uvalue;
- sb:=b.signed and (b.svalue<0);
- if sb then
- {$Q-}
- bb:=qword(-b.svalue)
- {$ifdef ena_q}{$Q+}{$endif}
- 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.svalue
- 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:=true
- else
- result:=a.svalue>b.svalue
- 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:=true
- else
- result:=a.svalue>=b.svalue
- 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:=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.svalue
- 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:=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.svalue
- end;
- 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.
|