listfuns.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  1. /* this file contains some more complicated operations on lists
  2. Copyright (C) 2006 Dennis Furey
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2, or (at your option)
  6. any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software Foundation,
  13. Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
  14. */
  15. #include <avm/common.h>
  16. #include <avm/error.h>
  17. #include <avm/chrcodes.h>
  18. #include <avm/compare.h>
  19. #include <avm/listfuns.h>
  20. /* non-zero means static variables are initialized */
  21. static int initialized = 0;
  22. /* represents (nil,nil) */
  23. static list shared_cell = NULL;
  24. /* error messages as lists of lists of character representations */
  25. static list empty_size = NULL;
  26. static list invalid_value = NULL;
  27. static list missing_value = NULL;
  28. static list memory_overflow = NULL;
  29. static list counter_overflow = NULL;
  30. static list invalid_transpose = NULL;
  31. static list invalid_membership = NULL;
  32. static list invalid_distribution = NULL;
  33. static list invalid_concatenation = NULL;
  34. void
  35. *avm_value_of_list (operand, message, fault)
  36. list operand;
  37. list *message;
  38. int *fault;
  39. /* This takes a list representing a value used by a library
  40. function and returns a pointer to the value. The value field
  41. in such a list will normally point to the block of memory
  42. holding the value, and the list itself will be a list of
  43. character representations whose binary encodings spell out the
  44. value. The redundancy is deliberate because it allows a list
  45. representing a value to be written out to a file in the usual
  46. avm format without any loss of information. */
  47. {
  48. char *temporary;
  49. void *result;
  50. int datum;
  51. counter size;
  52. list root;
  53. if (*fault = (*fault ? 1 : !!(*message)))
  54. return NULL;
  55. if (*fault = !operand)
  56. {
  57. *message = avm_copied (missing_value);
  58. return NULL;
  59. }
  60. if (operand->value)
  61. return operand->value;
  62. if (*fault = ! (result = (void *) malloc (size = avm_length (operand))))
  63. {
  64. *message = avm_copied (memory_overflow);
  65. return NULL;
  66. }
  67. operand->value = result;
  68. temporary = (char *) result;
  69. root = operand;
  70. while (*fault ? NULL : operand)
  71. if (*fault = (datum = avm_standard_character_code (operand->head)) < 0)
  72. *message = avm_copied (invalid_value);
  73. else
  74. {
  75. if (!size--)
  76. avm_internal_error(60);
  77. *temporary++ = datum;
  78. operand = operand->tail;
  79. }
  80. if (!*fault)
  81. return result;
  82. free (root->value);
  83. root->value = NULL;
  84. return NULL;
  85. }
  86. list
  87. avm_list_of_value (contents, size, fault)
  88. void *contents;
  89. size_t size;
  90. int *fault;
  91. /* inverse of value_of_list, takes the address and the size of
  92. the value to a list, making a copy of the contents rather
  93. than relying on the original */
  94. {
  95. list front,back,entry;
  96. char *temporary;
  97. void *result;
  98. if (*fault)
  99. return NULL;
  100. if(*fault = !size)
  101. return avm_copied (empty_size);
  102. if(*fault = !(result = (void *) malloc (size)))
  103. return avm_copied (memory_overflow);
  104. front = back = NULL;
  105. memcpy (result, contents, size);
  106. temporary = (char *) contents;
  107. while (*fault ? 0 : size)
  108. {
  109. entry = avm_standard_character_representation (*temporary++);
  110. avm_recoverable_enqueue (&front, &back, entry, fault);
  111. size--;
  112. }
  113. if (*fault)
  114. {
  115. avm_dispose (front);
  116. free (result);
  117. front = avm_copied (memory_overflow);
  118. }
  119. else
  120. front->value = result;
  121. return front;
  122. }
  123. list
  124. avm_reversal (operand, fault)
  125. list operand;
  126. int *fault;
  127. /* This returns a copy of the reversal of a list. */
  128. {
  129. list result;
  130. *fault = 0;
  131. if (!operand ? 1 : !(operand->tail))
  132. return avm_copied (operand);
  133. result = NULL;
  134. while (*fault ? 0 : operand)
  135. {
  136. *fault = !(result = avm_recoverable_join (avm_copied (operand->head), result));
  137. operand = operand->tail;
  138. }
  139. if (*fault)
  140. return avm_copied (memory_overflow);
  141. return result;
  142. }
  143. list
  144. avm_distribution (operand, fault)
  145. list operand;
  146. int *fault;
  147. /* This creates a list in which every item is a pair with the
  148. head of the original operand on the left and the corresponding
  149. member of the tail of the original operand on the right. */
  150. {
  151. list left, right, front, back;
  152. if (*fault = !operand)
  153. return (avm_copied (invalid_distribution));
  154. left = operand->head;
  155. right = operand->tail;
  156. front = back = (right ? avm_recoverable_join(NULL, NULL) : NULL);
  157. if (right ? !(*fault = !back) : 0)
  158. {
  159. front->known_weight = 0;
  160. *fault = !(back->head = avm_recoverable_join (avm_copied (left),avm_copied (right->head)));
  161. right = right->tail;
  162. }
  163. while (*fault ? 0 : right)
  164. {
  165. if (! (*fault = !(back = back->tail = avm_recoverable_join (NULL, NULL))))
  166. *fault = !(back->head = avm_recoverable_join (avm_copied (left),avm_copied (right->head)));
  167. right = right->tail;
  168. }
  169. if (*fault)
  170. {
  171. avm_dispose (front);
  172. return avm_copied (memory_overflow);
  173. }
  174. return front;
  175. }
  176. list
  177. avm_concatenation (operand, fault)
  178. list operand;
  179. int *fault;
  180. /* This makes a list with the head of the operand concatenated to
  181. the tail. */
  182. {
  183. list left, front, back;
  184. if (*fault = !operand)
  185. return avm_copied (invalid_concatenation);
  186. if (!(operand->tail))
  187. return avm_copied(operand->head);
  188. if (!(left = operand->head))
  189. return avm_copied(operand->tail);
  190. if (! (*fault = !(front = back = avm_recoverable_join (NULL, NULL))))
  191. {
  192. back->head = avm_copied (left->head);
  193. left = left->tail;
  194. }
  195. while (left ? !(*fault = !back) : 0)
  196. {
  197. if (back = back->tail = avm_recoverable_join (NULL, NULL))
  198. back->head = avm_copied (left->head);
  199. left = left->tail;
  200. }
  201. if (!(*fault = !back))
  202. back->tail = avm_copied (operand->tail);
  203. if (*fault)
  204. {
  205. avm_dispose (front);
  206. return avm_copied (memory_overflow);
  207. }
  208. return front;
  209. }
  210. list
  211. avm_flattened (operand, fault)
  212. list operand;
  213. int *fault;
  214. /* equivalent to reduce(cat,nil) in Ursala notation */
  215. {
  216. list front,back,item;
  217. front = back = NULL;
  218. while (*fault ? NULL : operand)
  219. {
  220. item = operand->head;
  221. while (*fault ? NULL : item)
  222. {
  223. avm_recoverable_enqueue (&front, &back, avm_copied (item->head), fault);
  224. item = item->tail;
  225. }
  226. operand = operand->tail;
  227. }
  228. return front;
  229. }
  230. list
  231. avm_transposition (operand, fault)
  232. list operand;
  233. int *fault;
  234. /* This requires the operand to represent a list of equal length
  235. lists. It returns the list of lists in which the first item is
  236. the list of all first items in the operand, the second item is
  237. the list of all second items, and so on. The operand is
  238. disposed of. */
  239. {
  240. list old, front_head, back_head, front_tail, back_tail, front, back;
  241. #define queue(f,b,x) \
  242. if(!*fault) \
  243. { \
  244. if((*fault=!(b?(b=b->tail=avm_recoverable_join(NULL,NULL)):(f=b=avm_recoverable_join(NULL,NULL))))) \
  245. { \
  246. avm_dispose(f); \
  247. f = avm_copied(memory_overflow); \
  248. } \
  249. else \
  250. b->head = avm_copied(x); \
  251. }
  252. *fault = 0;
  253. front = back = NULL;
  254. while (operand ? (!!(operand->head) ? !*fault : 0) : 0)
  255. {
  256. front_head = back_head = front_tail = back_tail = NULL;
  257. while (*fault ? 0 : operand)
  258. {
  259. queue (front_head, back_head, operand->head->head);
  260. queue (front_tail, back_tail, operand->head->tail);
  261. operand = avm_copied ((old = operand)->tail);
  262. avm_dispose (old);
  263. if (!operand ? 0 : *fault ? 0 : (*fault = !(operand->head)))
  264. {
  265. avm_dispose (front);
  266. front = avm_copied (invalid_transpose);
  267. }
  268. }
  269. queue (front, back, front_head);
  270. avm_dispose (front_head);
  271. operand = front_tail;
  272. }
  273. while (operand)
  274. {
  275. if (*fault ? 0 : (*fault = !!(operand->head)))
  276. {
  277. avm_dispose (front);
  278. front = avm_copied (invalid_transpose);
  279. }
  280. operand = avm_copied ((old = operand)->tail);
  281. avm_dispose (old);
  282. }
  283. return front;
  284. }
  285. list
  286. avm_binary_membership (operand, members, fault)
  287. list operand;
  288. list members;
  289. int *fault;
  290. /* This computes the membership predicate; returns NULL if the
  291. operand isn't anywhere in the members, but returns
  292. shared_cell if it is. */
  293. {
  294. list message;
  295. message = NULL;
  296. while (*fault ? 0 : (message ? 0 : !!members))
  297. {
  298. message = avm_binary_comparison (operand, members->head, fault);
  299. members = members->tail;
  300. }
  301. return message;
  302. }
  303. list
  304. avm_membership (operand, fault)
  305. list operand;
  306. int *fault;
  307. /* This computes the membership predicate; returns NULL if the
  308. head isn't anywhere in the tail of the operand, but returns
  309. shared_cell if it is. The operand must be non-empty or an
  310. error message is returned. */
  311. {
  312. if (*fault = !operand)
  313. return avm_copied (invalid_membership);
  314. return avm_binary_membership (operand->head, operand->tail, fault);
  315. }
  316. list
  317. avm_position (key, table, fault)
  318. list key;
  319. list table;
  320. int *fault;
  321. /* This takes a key and list whose items are possible keys, and
  322. returns position the corresponding item as a character
  323. encoding if any; otherwise returns NULL. */
  324. {
  325. int found;
  326. int position;
  327. list message;
  328. message = NULL;
  329. found = position = 0;
  330. while (*fault ? 0 : (found ? 0 : !!table))
  331. {
  332. found = (*fault ? 0 : !!(message = avm_binary_comparison (key, table->head, fault)));
  333. position++;
  334. table = table->tail;
  335. }
  336. if(found)
  337. {
  338. avm_dispose (message);
  339. message = avm_character_representation (position);
  340. }
  341. return message;
  342. }
  343. list
  344. avm_measurement (operand, fault)
  345. /* This returns the number of cells in a list as a binary number
  346. represented by a list of bits lsb first, with shared_cell for 1 and
  347. NULL for 0; also assigns the known_weight fields in all cells
  348. visited for future reference. The algorithm works without recursion
  349. by building a stack, starting out with just the operand on it. Then
  350. the following operations are perfomed until the stack has only a
  351. single item on it with a known weight, which is the answer. An
  352. unknown weight in the top item causes its head and tail to be
  353. pushed. A known weight on the top and an unknown weight on the one
  354. below causes the top and the one below to be interchanged. Known
  355. weights on both cause them to be added and popped, with the
  356. successor of the total assigned to the one below them. There could
  357. be an overflow if the weight is too big to fit in a counter type
  358. (probably 64 bits). Even though a list can't have more cells than
  359. that, it could appear to have more due to shared subtrees. In the
  360. event of overflow, an exception is thrown. */
  361. list operand;
  362. int *fault;
  363. {
  364. counter count;
  365. list temporary, stack, result;
  366. if (*fault = !(stack = avm_recoverable_join (avm_copied (operand), NULL)))
  367. return avm_copied (memory_overflow);
  368. while (stack)
  369. {
  370. if (stack->head)
  371. {
  372. if (stack->head->known_weight)
  373. {
  374. if (stack->tail)
  375. {
  376. if (stack->tail->head)
  377. {
  378. if (count = stack->tail->head->known_weight)
  379. {
  380. *fault = ((stack->tail->tail->head->known_weight = 1+count+stack->head->known_weight) <= count);
  381. if (*fault)
  382. {
  383. stack->tail->tail->head->known_weight = 0;
  384. avm_dispose (stack);
  385. return (avm_copied (counter_overflow));
  386. }
  387. else
  388. {
  389. stack = avm_copied ((temporary = stack)->tail->tail);
  390. avm_dispose (temporary);
  391. }
  392. }
  393. else
  394. {
  395. temporary = stack->tail->head;
  396. stack->tail->head = stack->head;
  397. stack->head = temporary;
  398. }
  399. }
  400. else if (*fault = !(stack->tail->tail->head->known_weight = stack->head->known_weight + 1))
  401. {
  402. stack->tail->tail->head->known_weight = 0;
  403. avm_dispose (stack);
  404. return (avm_copied (counter_overflow));
  405. }
  406. else
  407. {
  408. stack = avm_copied ((temporary = stack)->tail->tail);
  409. avm_dispose (temporary);
  410. }
  411. }
  412. else
  413. {
  414. count = stack->head->known_weight;
  415. avm_dispose (stack);
  416. stack = NULL;
  417. }
  418. }
  419. else
  420. {
  421. temporary = avm_copied(stack->head->head);
  422. stack = avm_recoverable_join(temporary, avm_recoverable_join (avm_copied(stack->head->tail),stack));
  423. if (*fault = !stack)
  424. return (avm_copied (memory_overflow));
  425. }
  426. }
  427. else if (stack->tail)
  428. {
  429. if (stack->tail->head)
  430. {
  431. if (count = stack->tail->head->known_weight)
  432. {
  433. if (*fault = ((stack->tail->tail->head->known_weight = 1 + count) <= count))
  434. {
  435. stack->tail->tail->head->known_weight = 0;
  436. avm_dispose (stack);
  437. return (avm_copied (counter_overflow));
  438. }
  439. else
  440. {
  441. stack = avm_copied ((temporary = stack)->tail->tail);
  442. avm_dispose (temporary);
  443. }
  444. }
  445. else
  446. {
  447. temporary = stack->tail->head;
  448. stack->tail->head = stack->head;
  449. stack->head = temporary;
  450. }
  451. }
  452. else
  453. {
  454. stack->tail->tail->head->known_weight = 1;
  455. stack = avm_copied ((temporary = stack)->tail->tail);
  456. avm_dispose (temporary);
  457. }
  458. }
  459. else
  460. {
  461. count = 0;
  462. avm_dispose (stack);
  463. stack = NULL;
  464. }
  465. }
  466. while (count)
  467. {
  468. if (*fault = !(stack = avm_recoverable_join ((count & 1) ? avm_copied (shared_cell) : NULL, stack)))
  469. return (avm_copied (memory_overflow));
  470. count >>= 1;
  471. }
  472. result = NULL;
  473. while (stack)
  474. {
  475. stack = (temporary = stack)->tail;
  476. temporary->tail = result;
  477. result = temporary;
  478. }
  479. return result;
  480. }
  481. void
  482. avm_initialize_listfuns ()
  483. /* This initializes some static data structures. */
  484. {
  485. if (initialized)
  486. return;
  487. initialized = 1;
  488. avm_initialize_lists ();
  489. avm_initialize_chrcodes ();
  490. avm_initialize_compare ();
  491. shared_cell = avm_join (NULL, NULL);
  492. empty_size = avm_join (avm_strung ("empty size"), NULL);
  493. missing_value = avm_join (avm_strung ("missing value"), NULL);
  494. invalid_value = avm_join (avm_strung ("invalid value"), NULL);
  495. memory_overflow = avm_join (avm_strung ("memory overflow"), NULL);
  496. counter_overflow = avm_join (avm_strung ("counter overflow"), NULL);
  497. invalid_transpose = avm_join (avm_strung ("invalid transpose"), NULL);
  498. invalid_membership = avm_join (avm_strung ("invalid membership"), NULL);
  499. invalid_distribution = avm_join (avm_strung ("invalid distribution"), NULL);
  500. invalid_concatenation = avm_join (avm_strung ("invalid concatenation"), NULL);
  501. }
  502. void
  503. avm_count_listfuns ()
  504. /* This frees some static data structures as an aid to the
  505. detection of memory leaks. */
  506. {
  507. if (!initialized)
  508. return;
  509. initialized = 0;
  510. avm_dispose (empty_size);
  511. avm_dispose (shared_cell);
  512. avm_dispose (invalid_value);
  513. avm_dispose (missing_value);
  514. avm_dispose (memory_overflow);
  515. avm_dispose (counter_overflow);
  516. avm_dispose (invalid_transpose);
  517. avm_dispose (invalid_membership);
  518. avm_dispose (invalid_distribution);
  519. avm_dispose (invalid_concatenation);
  520. empty_size = NULL;
  521. shared_cell = NULL;
  522. missing_value = NULL;
  523. invalid_value = NULL;
  524. memory_overflow = NULL;
  525. counter_overflow = NULL;
  526. invalid_transpose = NULL;
  527. invalid_membership = NULL;
  528. invalid_distribution = NULL;
  529. invalid_concatenation = NULL;
  530. }