constexp.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  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. if r>qword(high(int64)) then
  300. result.overflow:=true
  301. else
  302. result.svalue:=-int64(r);
  303. end
  304. else
  305. begin
  306. result.signed:=false;
  307. result.uvalue:=r;
  308. end;
  309. end;
  310. end;
  311. operator mod (const a,b:Tconstexprint):Tconstexprint;
  312. var aa,bb:qword;
  313. sa,sb:boolean;
  314. begin
  315. if a.overflow or b.overflow then
  316. begin
  317. result.overflow:=true;
  318. exit;
  319. end;
  320. result.overflow:=false;
  321. if a.signed then
  322. begin
  323. aa:=qword(a.svalue);
  324. sa:=a.svalue<0;
  325. end
  326. else
  327. begin
  328. aa:=a.uvalue;
  329. sa:=false;
  330. end;
  331. if b.signed then
  332. begin
  333. bb:=qword(b.svalue);
  334. sb:=b.svalue<0;
  335. end
  336. else
  337. begin
  338. bb:=b.uvalue;
  339. sb:=false;
  340. end;
  341. if bb=0 then
  342. result.overflow:=true
  343. else
  344. begin
  345. result.signed:=false;
  346. result.uvalue:=aa mod bb;
  347. end;
  348. end;
  349. operator / (const a,b:Tconstexprint):bestreal;
  350. var aa,bb:bestreal;
  351. begin
  352. if a.overflow or b.overflow then
  353. internalerror(200706096);
  354. if a.signed then
  355. aa:=a.svalue
  356. else
  357. aa:=a.uvalue;
  358. if b.signed then
  359. bb:=b.svalue
  360. else
  361. bb:=b.uvalue;
  362. result:=aa/bb;
  363. end;
  364. operator = (const a,b:Tconstexprint):boolean;
  365. begin
  366. if a.signed and (a.svalue<0) then
  367. if b.signed and (b.svalue<0) then
  368. result:=a.svalue=b.svalue
  369. else if b.uvalue>qword(high(int64)) then
  370. result:=false
  371. else
  372. result:=a.svalue=b.svalue
  373. else
  374. if not (b.signed and (b.svalue<0)) then
  375. result:=a.uvalue=b.uvalue
  376. else if a.uvalue>qword(high(int64)) then
  377. result:=false
  378. else
  379. result:=a.svalue=b.svalue
  380. end;
  381. operator > (const a,b:Tconstexprint):boolean;
  382. begin
  383. if a.signed and (a.svalue<0) then
  384. if b.signed and (b.svalue<0) then
  385. result:=a.svalue>b.svalue
  386. else if b.uvalue>qword(high(int64)) then
  387. result:=false
  388. else
  389. result:=a.svalue>b.svalue
  390. else
  391. if not (b.signed and (b.svalue<0)) then
  392. result:=a.uvalue>b.uvalue
  393. else if a.uvalue>qword(high(int64)) then
  394. result:=true
  395. else
  396. result:=a.svalue>b.svalue
  397. end;
  398. operator >= (const a,b:Tconstexprint):boolean;
  399. begin
  400. if a.signed and (a.svalue<0) then
  401. if b.signed and (b.svalue<0) then
  402. result:=a.svalue>=b.svalue
  403. else if b.uvalue>qword(high(int64)) then
  404. result:=false
  405. else
  406. result:=a.svalue>=b.svalue
  407. else
  408. if not (b.signed and (b.svalue<0)) then
  409. result:=a.uvalue>=b.uvalue
  410. else if a.uvalue>qword(high(int64)) then
  411. result:=true
  412. else
  413. result:=a.svalue>=b.svalue
  414. end;
  415. operator < (const a,b:Tconstexprint):boolean;
  416. begin
  417. if a.signed and (a.svalue<0) then
  418. if b.signed and (b.svalue<0) then
  419. result:=a.svalue<b.svalue
  420. else if b.uvalue>qword(high(int64)) then
  421. result:=true
  422. else
  423. result:=a.svalue<b.svalue
  424. else
  425. if not (b.signed and (b.svalue<0)) then
  426. result:=a.uvalue<b.uvalue
  427. else if a.uvalue>qword(high(int64)) then
  428. result:=false
  429. else
  430. result:=a.svalue<b.svalue
  431. end;
  432. operator <= (const a,b:Tconstexprint):boolean;
  433. begin
  434. if a.signed and (a.svalue<0) then
  435. if b.signed and (b.svalue<0) then
  436. result:=a.svalue<=b.svalue
  437. else if b.uvalue>qword(high(int64)) then
  438. result:=true
  439. else
  440. result:=a.svalue<=b.svalue
  441. else
  442. if not (b.signed and (b.svalue<0)) then
  443. result:=a.uvalue<=b.uvalue
  444. else if a.uvalue>qword(high(int64)) then
  445. result:=false
  446. else
  447. result:=a.svalue<=b.svalue
  448. end;
  449. operator and (const a,b:Tconstexprint):Tconstexprint;
  450. begin
  451. result.overflow:=false;
  452. result.signed:=a.signed or b.signed;
  453. result.uvalue:=a.uvalue and b.uvalue;
  454. end;
  455. operator or (const a,b:Tconstexprint):Tconstexprint;
  456. begin
  457. result.overflow:=false;
  458. result.signed:=a.signed or b.signed;
  459. result.uvalue:=a.uvalue or b.uvalue;
  460. end;
  461. operator xor (const a,b:Tconstexprint):Tconstexprint;
  462. begin
  463. result.overflow:=false;
  464. result.signed:=a.signed or b.signed;
  465. result.uvalue:=a.uvalue xor b.uvalue;
  466. end;
  467. operator shl (const a,b:Tconstexprint):Tconstexprint;
  468. begin
  469. result.overflow:=false;
  470. result.signed:=a.signed;
  471. result.uvalue:=a.uvalue shl b.uvalue;
  472. end;
  473. operator shr (const a,b:Tconstexprint):Tconstexprint;
  474. begin
  475. result.overflow:=false;
  476. result.signed:=a.signed;
  477. result.uvalue:=a.uvalue shr b.uvalue;
  478. end;
  479. function tostr(const i:Tconstexprint):shortstring;overload;
  480. begin
  481. if i.signed then
  482. str(i.svalue,result)
  483. else
  484. str(i.uvalue,result);
  485. end;
  486. end.