constexp.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. unit constexp;
  2. {
  3. Copyright (c) 2007 by Daniel Mantione
  4. This unit implements a Tconstexprint type. This type simulates an integer
  5. type that can handle numbers from low(int64) to high(qword) calculations.
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ****************************************************************************
  18. }
  19. {****************************************************************************}
  20. interface
  21. {****************************************************************************}
  22. {$i fpcdefs.inc}
  23. {$ifopt q+}
  24. {$define ena_q}
  25. {$endif}
  26. type Tconstexprint=record
  27. overflow:boolean;
  28. case signed:boolean of
  29. false:
  30. (uvalue:qword);
  31. true:
  32. (svalue:int64);
  33. end;
  34. errorproc=procedure (i:longint);
  35. {"Uses verbose" gives a dependency on cpuinfo through globals. This leads
  36. build trouble when compiling the directory utils, since the cpu directory
  37. isn't searched there. Therefore we use a procvar and make verbose install
  38. the errorhandler. A dependency from verbose on this unit is no problem.}
  39. var internalerror:errorproc;
  40. {Same issue, avoid dependency on cpuinfo because the cpu directory isn't
  41. searched during utils building.}
  42. {$ifdef x86}
  43. type bestreal=extended;
  44. {$else}
  45. type bestreal=double;
  46. {$endif}
  47. operator := (const u:qword):Tconstexprint;inline;
  48. operator := (const s:int64):Tconstexprint;inline;
  49. operator := (const c:Tconstexprint):qword;
  50. operator := (const c:Tconstexprint):int64;
  51. operator := (const c:Tconstexprint):bestreal;
  52. operator + (const a,b:Tconstexprint):Tconstexprint;
  53. operator - (const a,b:Tconstexprint):Tconstexprint;
  54. operator - (const a:Tconstexprint):Tconstexprint;
  55. operator * (const a,b:Tconstexprint):Tconstexprint;
  56. operator div (const a,b:Tconstexprint):Tconstexprint;
  57. operator mod (const a,b:Tconstexprint):Tconstexprint;
  58. operator / (const a,b:Tconstexprint):bestreal;
  59. operator = (const a,b:Tconstexprint):boolean;
  60. operator > (const a,b:Tconstexprint):boolean;
  61. operator >= (const a,b:Tconstexprint):boolean;
  62. operator < (const a,b:Tconstexprint):boolean;
  63. operator <= (const a,b:Tconstexprint):boolean;
  64. operator and (const a,b:Tconstexprint):Tconstexprint;
  65. operator or (const a,b:Tconstexprint):Tconstexprint;
  66. operator xor (const a,b:Tconstexprint):Tconstexprint;
  67. operator shl (const a,b:Tconstexprint):Tconstexprint;
  68. operator shr (const a,b:Tconstexprint):Tconstexprint;
  69. function tostr(const i:Tconstexprint):shortstring;overload;
  70. {****************************************************************************}
  71. implementation
  72. {****************************************************************************}
  73. operator := (const u:qword):Tconstexprint;
  74. begin
  75. result.overflow:=false;
  76. result.signed:=false;
  77. result.uvalue:=u;
  78. end;
  79. operator := (const s:int64):Tconstexprint;
  80. begin
  81. result.overflow:=false;
  82. result.signed:=true;
  83. result.svalue:=s;
  84. end;
  85. operator := (const c:Tconstexprint):qword;
  86. begin
  87. if c.overflow then
  88. internalerror(200706091)
  89. else if not c.signed then
  90. result:=c.uvalue
  91. else if c.svalue<0 then
  92. internalerror(200706092)
  93. else
  94. result:=qword(c.svalue);
  95. end;
  96. operator := (const c:Tconstexprint):int64;
  97. begin
  98. if c.overflow then
  99. internalerror(200706093)
  100. else if c.signed then
  101. result:=c.svalue
  102. else if c.uvalue>high(int64) then
  103. internalerror(200706094)
  104. else
  105. result:=int64(c.uvalue);
  106. end;
  107. operator := (const c:Tconstexprint):bestreal;
  108. begin
  109. if c.overflow then
  110. internalerror(200706095)
  111. else if c.signed then
  112. result:=c.svalue
  113. else
  114. result:=c.uvalue;
  115. end;
  116. function add_to(const a:Tconstexprint;b:qword):Tconstexprint;
  117. var sspace,uspace:qword;
  118. label try_qword;
  119. begin
  120. result.overflow:=false;
  121. {Try if the result fits in an int64.}
  122. if (a.signed) and (a.svalue<0) then
  123. {$Q-}
  124. sspace:=qword(high(int64))-qword(-a.svalue)
  125. {$ifdef ena_q}{$Q+}{$endif}
  126. else if not a.signed and (a.uvalue>qword(high(int64))) then
  127. goto try_qword
  128. else
  129. sspace:=qword(high(int64))-a.svalue;
  130. if sspace>=b then
  131. begin
  132. result.signed:=true;
  133. {$Q-}
  134. result.svalue:=a.svalue+int64(b);
  135. {$ifdef ena_q}{$Q+}{$endif}
  136. exit;
  137. end;
  138. {Try if the result fits in a qword.}
  139. try_qword:
  140. if (a.signed) and (a.svalue<0) then
  141. uspace:=high(qword)-qword(-a.svalue)
  142. { else if not a.signed and (a.uvalue>qword(high(int64))) then
  143. uspace:=high(qword)-a.uvalue}
  144. else
  145. uspace:=high(qword)-a.uvalue;
  146. if uspace>=b then
  147. begin
  148. result.signed:=false;
  149. {$Q-}
  150. result.uvalue:=a.uvalue+b;
  151. {$ifdef ena_q}{$Q+}{$endif}
  152. exit;
  153. end;
  154. result.overflow:=true;
  155. end;
  156. function sub_from(const a:Tconstexprint;b:qword):Tconstexprint;
  157. const abs_low_int64=qword(9223372036854775808); {abs(low(int64)) -> overflow error}
  158. var sspace,uspace:qword;
  159. label try_qword,ov;
  160. begin
  161. result.overflow:=false;
  162. {Try if the result fits in an int64.}
  163. if (a.signed) and (a.svalue<0) then
  164. {$Q-}
  165. sspace:=qword(a.svalue)+abs_low_int64
  166. {$ifdef ena_q}{$Q+}{$endif}
  167. else if not a.signed and (a.uvalue>qword(high(int64))) then
  168. goto try_qword
  169. else
  170. sspace:=a.uvalue+qword(abs(low(int64)));
  171. if sspace>=b then
  172. begin
  173. result.signed:=true;
  174. {$Q-}
  175. result.svalue:=a.svalue-int64(b);
  176. {$ifdef ena_q}{$Q+}{$endif}
  177. exit;
  178. end;
  179. {Try if the result fits in a qword.}
  180. try_qword:
  181. if not(a.signed and (a.svalue<0)) and (a.uvalue>=b) then
  182. begin
  183. result.signed:=false;
  184. {$Q-}
  185. result.uvalue:=a.uvalue-b;
  186. {$ifdef ena_q}{$Q+}{$endif}
  187. exit;
  188. end;
  189. ov:
  190. result.overflow:=true;
  191. end;
  192. operator + (const a,b:Tconstexprint):Tconstexprint;
  193. begin
  194. if a.overflow or b.overflow then
  195. begin
  196. result.overflow:=true;
  197. exit;
  198. end;
  199. if b.signed and (b.svalue<0) then
  200. {$Q-}
  201. result:=sub_from(a,qword(-b.svalue))
  202. {$ifdef ena_q}{$Q+}{$endif}
  203. else
  204. result:=add_to(a,b.uvalue);
  205. end;
  206. operator - (const a,b:Tconstexprint):Tconstexprint;
  207. begin
  208. if a.overflow or b.overflow then
  209. begin
  210. result.overflow:=true;
  211. exit;
  212. end;
  213. if b.signed and (b.svalue<0) then
  214. {$Q-}
  215. result:=add_to(a,qword(-b.svalue))
  216. {$ifdef ena_q}{$Q+}{$endif}
  217. else
  218. result:=sub_from(a,b.uvalue);
  219. end;
  220. operator - (const a:Tconstexprint):Tconstexprint;
  221. begin
  222. if not a.signed and (a.uvalue>qword(high(int64))) then
  223. result.overflow:=true
  224. else
  225. begin
  226. result.overflow:=false;
  227. result.signed:=true;
  228. result.svalue:=-a.svalue;
  229. end;
  230. end;
  231. operator * (const a,b:Tconstexprint):Tconstexprint;
  232. var aa,bb,r:qword;
  233. sa,sb:boolean;
  234. begin
  235. if a.overflow or b.overflow then
  236. begin
  237. result.overflow:=true;
  238. exit;
  239. end;
  240. result.overflow:=false;
  241. sa:=a.signed and (a.svalue<0);
  242. if sa then
  243. aa:=qword(-a.svalue)
  244. else
  245. aa:=a.uvalue;
  246. sb:=b.signed and (b.svalue<0);
  247. if sb then
  248. bb:=qword(-b.svalue)
  249. else
  250. bb:=b.uvalue;
  251. if (bb<>0) and (high(qword) div bb<aa) then
  252. result.overflow:=true
  253. else
  254. begin
  255. r:=aa*bb;
  256. if sa xor sb then
  257. begin
  258. result.signed:=true;
  259. if r>qword(high(int64)) then
  260. result.overflow:=true
  261. else
  262. result.svalue:=-int64(r);
  263. end
  264. else
  265. begin
  266. result.signed:=false;
  267. result.uvalue:=r;
  268. end;
  269. end;
  270. end;
  271. operator div (const a,b:Tconstexprint):Tconstexprint;
  272. var aa,bb,r:qword;
  273. sa,sb:boolean;
  274. begin
  275. if a.overflow or b.overflow then
  276. begin
  277. result.overflow:=true;
  278. exit;
  279. end;
  280. result.overflow:=false;
  281. sa:=a.signed and (a.svalue<0);
  282. if sa then
  283. aa:=qword(-a.svalue)
  284. else
  285. aa:=a.uvalue;
  286. sb:=b.signed and (b.svalue<0);
  287. if sb then
  288. bb:=qword(-b.svalue)
  289. else
  290. bb:=b.uvalue;
  291. if bb=0 then
  292. result.overflow:=true
  293. else
  294. begin
  295. r:=aa div bb;
  296. if sa xor sb then
  297. begin
  298. result.signed:=true;
  299. result.svalue:=r;
  300. end
  301. else
  302. begin
  303. result.signed:=false;
  304. result.uvalue:=r;
  305. end;
  306. end;
  307. end;
  308. operator mod (const a,b:Tconstexprint):Tconstexprint;
  309. var aa,bb:qword;
  310. sa,sb:boolean;
  311. begin
  312. if a.overflow or b.overflow then
  313. begin
  314. result.overflow:=true;
  315. exit;
  316. end;
  317. result.overflow:=false;
  318. if a.signed then
  319. begin
  320. aa:=qword(a.svalue);
  321. sa:=a.svalue<0;
  322. end
  323. else
  324. begin
  325. aa:=a.uvalue;
  326. sa:=false;
  327. end;
  328. if b.signed then
  329. begin
  330. bb:=qword(b.svalue);
  331. sb:=b.svalue<0;
  332. end
  333. else
  334. begin
  335. bb:=b.uvalue;
  336. sb:=false;
  337. end;
  338. if bb=0 then
  339. result.overflow:=true
  340. else
  341. begin
  342. result.signed:=false;
  343. result.uvalue:=aa mod bb;
  344. end;
  345. end;
  346. operator / (const a,b:Tconstexprint):bestreal;
  347. var aa,bb:bestreal;
  348. begin
  349. if a.overflow or b.overflow then
  350. internalerror(200706096);
  351. if a.signed then
  352. aa:=a.svalue
  353. else
  354. aa:=a.uvalue;
  355. if b.signed then
  356. bb:=b.svalue
  357. else
  358. bb:=b.uvalue;
  359. result:=aa/bb;
  360. end;
  361. operator = (const a,b:Tconstexprint):boolean;
  362. begin
  363. if a.signed and (a.svalue<0) then
  364. if b.signed and (b.svalue<0) then
  365. result:=a.svalue=b.svalue
  366. else if b.uvalue>qword(high(int64)) then
  367. result:=false
  368. else
  369. result:=a.svalue=b.svalue
  370. else
  371. if not (b.signed and (b.svalue<0)) then
  372. result:=a.uvalue=b.uvalue
  373. else if a.uvalue>qword(high(int64)) then
  374. result:=false
  375. else
  376. result:=a.svalue=b.svalue
  377. end;
  378. operator > (const a,b:Tconstexprint):boolean;
  379. begin
  380. if a.signed and (a.svalue<0) then
  381. if b.signed and (b.svalue<0) then
  382. result:=a.svalue>b.svalue
  383. else if b.uvalue>qword(high(int64)) then
  384. result:=false
  385. else
  386. result:=a.svalue>b.svalue
  387. else
  388. if not (b.signed and (b.svalue<0)) then
  389. result:=a.uvalue>b.uvalue
  390. else if a.uvalue>qword(high(int64)) then
  391. result:=true
  392. else
  393. result:=a.svalue>b.svalue
  394. end;
  395. operator >= (const a,b:Tconstexprint):boolean;
  396. begin
  397. if a.signed and (a.svalue<0) then
  398. if b.signed and (b.svalue<0) then
  399. result:=a.svalue>=b.svalue
  400. else if b.uvalue>qword(high(int64)) then
  401. result:=false
  402. else
  403. result:=a.svalue>=b.svalue
  404. else
  405. if not (b.signed and (b.svalue<0)) then
  406. result:=a.uvalue>=b.uvalue
  407. else if a.uvalue>qword(high(int64)) then
  408. result:=true
  409. else
  410. result:=a.svalue>=b.svalue
  411. end;
  412. operator < (const a,b:Tconstexprint):boolean;
  413. begin
  414. if a.signed and (a.svalue<0) then
  415. if b.signed and (b.svalue<0) then
  416. result:=a.svalue<b.svalue
  417. else if b.uvalue>qword(high(int64)) then
  418. result:=true
  419. else
  420. result:=a.svalue<b.svalue
  421. else
  422. if not (b.signed and (b.svalue<0)) then
  423. result:=a.uvalue<b.uvalue
  424. else if a.uvalue>qword(high(int64)) then
  425. result:=false
  426. else
  427. result:=a.svalue<b.svalue
  428. end;
  429. operator <= (const a,b:Tconstexprint):boolean;
  430. begin
  431. if a.signed and (a.svalue<0) then
  432. if b.signed and (b.svalue<0) then
  433. result:=a.svalue<=b.svalue
  434. else if b.uvalue>qword(high(int64)) then
  435. result:=true
  436. else
  437. result:=a.svalue<=b.svalue
  438. else
  439. if not (b.signed and (b.svalue<0)) then
  440. result:=a.uvalue<=b.uvalue
  441. else if a.uvalue>qword(high(int64)) then
  442. result:=false
  443. else
  444. result:=a.svalue<=b.svalue
  445. end;
  446. operator and (const a,b:Tconstexprint):Tconstexprint;
  447. begin
  448. result.overflow:=false;
  449. result.signed:=a.signed or b.signed;
  450. result.uvalue:=a.uvalue and b.uvalue;
  451. end;
  452. operator or (const a,b:Tconstexprint):Tconstexprint;
  453. begin
  454. result.overflow:=false;
  455. result.signed:=a.signed or b.signed;
  456. result.uvalue:=a.uvalue or b.uvalue;
  457. end;
  458. operator xor (const a,b:Tconstexprint):Tconstexprint;
  459. begin
  460. result.overflow:=false;
  461. result.signed:=a.signed or b.signed;
  462. result.uvalue:=a.uvalue xor b.uvalue;
  463. end;
  464. operator shl (const a,b:Tconstexprint):Tconstexprint;
  465. begin
  466. result.overflow:=false;
  467. result.signed:=a.signed;
  468. result.uvalue:=a.uvalue shl b.uvalue;
  469. end;
  470. operator shr (const a,b:Tconstexprint):Tconstexprint;
  471. begin
  472. result.overflow:=false;
  473. result.signed:=a.signed;
  474. result.uvalue:=a.uvalue shr b.uvalue;
  475. end;
  476. function tostr(const i:Tconstexprint):shortstring;overload;
  477. begin
  478. if i.signed then
  479. str(i.svalue,result)
  480. else
  481. str(i.uvalue,result);
  482. end;
  483. end.