array.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. /* Definitions for the array type.
  2. This file is part of khipu.
  3. khipu is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Lesser General Public License as published by
  5. the Free Software Foundation; either version 3 of the License, or
  6. (at your option) 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 Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program. If not, see <https://www.gnu.org/licenses/>. */
  13. #include <cstdio>
  14. #include "khipu.hpp"
  15. #include "utils/raw_acc.hpp"
  16. KP_DECLS_BEGIN
  17. static array empty_array;
  18. array* array::alloc_raw (uint32_t n)
  19. {
  20. array *ret = (array *)alloch (sizeof (*ret) +
  21. n * sizeof (object), typecode::ARRAY);
  22. ret->data = (object *)&ret[1];
  23. ret->len = n;
  24. return (ret);
  25. }
  26. result<object> alloc_array (interpreter *interp, uint32_t nelems, object fill)
  27. {
  28. if (!nelems)
  29. kp_return (empty_array.as_obj ());
  30. auto eg = KP_TRY (evh_guard::make (interp));
  31. array *ret = array::alloc_raw (nelems);
  32. for (uint32_t i = 0; i < nelems; ++i)
  33. ret->data[i] = fill;
  34. interp->alval = ret->as_obj ();
  35. gc_register (interp, ret, sizeof (*ret) + nelems * sizeof (object));
  36. return (interp->alval);
  37. }
  38. result<object> add_aa (interpreter *interp, object a1, object a2)
  39. {
  40. array *p1 = as_array (a1), *p2 = as_array (a2);
  41. if (!p1->len && !p2->len)
  42. kp_return (a1);
  43. object ret = KP_TRY (alloc_array (interp, p1->len + p2->len));
  44. copy_objs (copy_objs (as_array(ret)->data,
  45. p1->data, p1->len),
  46. p2->data, p2->len);
  47. kp_return (ret);
  48. }
  49. result<object> concat_a (interpreter *interp, object *argv, int argc)
  50. {
  51. if (argc == 1)
  52. kp_return (*argv);
  53. uint32_t nlen = 0;
  54. for (int i = 0; i < argc; ++i)
  55. {
  56. if (!array_p (argv[i]))
  57. return (interp->raise ("type-error", "arguments must be arrays"));
  58. nlen += len_a (argv[i]);
  59. }
  60. object obj = KP_TRY (alloc_array (interp, nlen));
  61. object *dstp = as_array(obj)->data;
  62. for (int i = 0; i < argc; ++i)
  63. dstp = copy_objs (dstp, &xaref(argv[i], 0), len_a (argv[i]));
  64. kp_return (interp->alval);
  65. }
  66. result<object> mul_ia (interpreter *interp, object iv, object ax)
  67. {
  68. int ival = as_int (iv);
  69. const array *ap = as_array (ax);
  70. if (ival <= 0)
  71. kp_return (empty_array.as_obj ());
  72. object ret = KP_TRY (alloc_array (interp, ap->len * ival));
  73. object *ptr = as_array(ret)->data;
  74. for (int i = 0; i < ival; ++i)
  75. ptr = copy_objs (ptr, ap->data, ap->len);
  76. kp_return (ret);
  77. }
  78. static inline intptr_t
  79. get_idx (const array *ap, intptr_t ix)
  80. {
  81. return (ix < 0 ? ap->len + ix : ix);
  82. }
  83. static inline result<object*>
  84. array_ref (interpreter *interp, object ax, object iv)
  85. {
  86. int idx;
  87. if (!as<int> (iv, idx))
  88. return (interp->raise ("type-error", "index is not an integer"));
  89. array *ap = as_array (ax);
  90. idx = get_idx (ap, idx);
  91. if (kp_unlikely (idx < 0 || (uint32_t)idx >= ap->len))
  92. return (interp->raise_oob (idx, ap->len));
  93. return (&ap->data[idx]);
  94. }
  95. result<object> get_a (interpreter *interp,
  96. object ax, object iv, object dfl)
  97. {
  98. if (kp_unlikely (dfl != UNBOUND))
  99. return (interp->raise_nargs (2, 2, 3));
  100. object *p = KP_TRY (array_ref (interp, ax, iv));
  101. kp_return (*p);
  102. }
  103. result<object> nput_a (interpreter *interp,
  104. object ax, object iv, object val)
  105. {
  106. if (kp_unlikely (as_varobj(ax)->flagged_p (FLAGS_CONST)))
  107. return (interp->raise_const ());
  108. object *p = KP_TRY (array_ref (interp, ax, iv));
  109. deref (gc_wbarrier (interp, ax, *p = val));
  110. kp_return (val);
  111. }
  112. result<object> subseq_a (interpreter *interp,
  113. object ax, object ix1, object ix2)
  114. {
  115. const array *ap = as_array (ax);
  116. bool got = true;
  117. int i1, i2;
  118. if (ix2 == UNBOUND)
  119. i2 = (int)ap->len;
  120. else
  121. got = as<int> (ix2, i2);
  122. if (!got || !as<int> (ix1, i1))
  123. return (interp->raise ("type-error", "indices must be integers"));
  124. i1 = get_idx (ap, i1), i2 = get_idx (ap, i2);
  125. if ((i1 | i2) < 0 || i1 > i2 || (uint32_t)i2 > ap->len)
  126. return (interp->raise ("index-error", "indices out of bounds"));
  127. object ret = KP_TRY (alloc_array (interp, i2 - i1));
  128. copy_objs (as_array(ret)->data, ap->data + i1, i2 - i1);
  129. kp_return (ret);
  130. }
  131. result<object> copy_a (interpreter *interp, object obj, bool deep)
  132. {
  133. const array *ap = as_array (obj);
  134. if (!deep)
  135. {
  136. object ret = KP_TRY (alloc_array (interp, ap->len));
  137. copy_objs (&xaref(ret, 0), ap->data, ap->len);
  138. kp_return (ret);
  139. }
  140. raw_acc<array> rx (ap->len);
  141. array *ret = rx.get ();
  142. valref obr (interp, ret->as_obj ()), tmp (interp);
  143. for (ret->len = 0; ret->len < ap->len; ++ret->len)
  144. {
  145. *tmp = ap->data[ret->len];
  146. ret->data[ret->len] = KP_TRY (copy (interp, *tmp, true));
  147. }
  148. rx.release ();
  149. interp->retval = *obr;
  150. gc_register (interp, ret, sizeof (*ret) + ret->len * sizeof (object));
  151. return (interp->retval);
  152. }
  153. static const uint32_t ARRAY_HASH_SEED = 1634890337;
  154. result<uint32_t> hash_a (interpreter *interp, object obj)
  155. {
  156. uint32_t ret = ARRAY_HASH_SEED;
  157. for (array::iterator it { interp, obj }; it.valid (); ++it)
  158. {
  159. uint32_t tmp = KP_TRY (xhash (interp, *it));
  160. ret = mix_hash (ret, tmp);
  161. }
  162. return (ret);
  163. }
  164. result<object> nreverse_a (interpreter *interp, object obj)
  165. {
  166. array *ap = as_array (obj);
  167. if (kp_unlikely (ap->flagged_p (FLAGS_CONST)))
  168. return (interp->raise_const ());
  169. else if (ap->len == 0)
  170. kp_return (obj);
  171. for (uint32_t i = 0, j = ap->len - 1; i < j; ++i, --j)
  172. swap (ap->data[i], ap->data[j]);
  173. kp_return (obj);
  174. }
  175. result<object> reverse_a (interpreter *interp, object obj)
  176. {
  177. const array *ap = as_array (obj);
  178. if (ap->len == 0)
  179. kp_return (obj);
  180. object ret = KP_TRY (alloc_array (interp, ap->len));
  181. for (uint32_t i = 0, j = ap->len - 1 ; ; ++i, --j)
  182. {
  183. xaref(ret, i) = ap->data[j];
  184. if (i >= j)
  185. break;
  186. }
  187. kp_return (ret);
  188. }
  189. result<object> nsort_a (interpreter *interp, object obj, comparator& cmp)
  190. {
  191. array *ap = as_array (obj);
  192. if (kp_unlikely (ap->flagged_p (FLAGS_CONST)))
  193. return (interp->raise_const ());
  194. else if (ap->len <= 1)
  195. kp_return (obj);
  196. valref v1 (interp), v2 (interp);
  197. object *wp = ap->data - 1;
  198. for (uint32_t r = ap->len / 2; r > 0; --r)
  199. for (uint32_t i = r ; ; )
  200. {
  201. uint32_t j = i + i;
  202. if (j > ap->len)
  203. break;
  204. else if (j != ap->len)
  205. {
  206. bool rv = KP_TRY (cmp (*v1 = wp[j], *v2 = wp[j + 1]));
  207. if (rv)
  208. ++j;
  209. }
  210. bool rv = KP_TRY (cmp (*v1 = wp[i], *v2 = wp[j]));
  211. if (rv)
  212. swap (wp[i], wp[j]);
  213. i = j;
  214. }
  215. for (uint32_t s = ap->len - 1; s > 0; --s)
  216. {
  217. swap (*ap->data, ap->data[s]);
  218. for (uint32_t i = 1 ; ; )
  219. {
  220. uint32_t j = i + i;
  221. if (j > s)
  222. break;
  223. else if (j != s)
  224. {
  225. bool rv = KP_TRY (cmp (*v1 = wp[j], *v2 = wp[j + 1]));
  226. if (rv)
  227. ++j;
  228. }
  229. bool rv = KP_TRY (cmp (*v1 = wp[i], *v2 = wp[j]));
  230. if (rv)
  231. swap (wp[i], wp[j]);
  232. i = j;
  233. }
  234. }
  235. kp_return (obj);
  236. }
  237. result<bool> eq_aa (interpreter *interp, object a1, object a2)
  238. {
  239. if (len_a (a1) != len_a (a2))
  240. return (false);
  241. for (array::iterator i1 { interp, a1 }, i2 { interp, a2 };
  242. i1.valid (); ++i1, ++i2)
  243. {
  244. bool rv = KP_TRY (equal (interp, *i1, *i2));
  245. if (!rv)
  246. return (false);
  247. }
  248. return (true);
  249. }
  250. result<int> cmp_aa (interpreter *interp, object a1, object a2)
  251. {
  252. const array *ap1 = as_array (a1), *ap2 = as_array (a2);
  253. uint32_t rl = min (ap1->len, ap2->len);
  254. valref x (interp), y (interp);
  255. for (uint32_t i = 0; i < rl; ++i)
  256. {
  257. int c = KP_TRY (xcmp (interp, *x = ap1->data[i], *y = ap2->data[i]));
  258. if (c)
  259. return (c);
  260. }
  261. return (ap1->len < ap2->len ? -1 : ap2->len != ap1->len);
  262. }
  263. result<object> iter_a (interpreter *interp, object obj, object token, bool adv)
  264. {
  265. if (token == UNBOUND)
  266. kp_return (len_a (obj) == 0 ? NIL : fixint (0));
  267. else if (!adv)
  268. return (get_a (interp, obj, token, UNBOUND));
  269. else if (!fixint_p (token))
  270. return (interp->raise ("type-error", "token must be an int"));
  271. int ix = as_int (token) + 1;
  272. kp_return ((uint32_t)ix >= len_a (obj) ? NIL : fixint (ix));
  273. }
  274. result<object> nzap_a (interpreter *interp, object obj, object key,
  275. uint32_t flags, object fn, object *argv, int argc)
  276. {
  277. int idx;
  278. if (kp_unlikely (!as<int> (key, idx)))
  279. return (interp->raise ("type-error", "index is not an integer"));
  280. else if (kp_unlikely (flags & NZAP_DFL))
  281. return (interp->raise ("arg-error", "default argument not supported"));
  282. array *ap = as_array (obj);
  283. if (kp_unlikely (ap->flagged_p (FLAGS_CONST)))
  284. return (interp->raise_const ());
  285. idx = get_idx (ap, idx);
  286. if (kp_unlikely (idx < 0 || (uint32_t)idx >= ap->len))
  287. return (interp->raise_oob (idx, ap->len));
  288. sp_guard spg { interp };
  289. KP_VTRY (interp->growstk (argc + 1));
  290. *interp->stkend++ = fn;
  291. *interp->stkend++ = fixint (0);
  292. int stack_idx = interp->stklen () - 1;
  293. for (int i = 0; i < argc; ++i)
  294. *interp->stkend++ = argv[i];
  295. valref prev (interp);
  296. if (flags & NZAP_NOMT)
  297. {
  298. interp->stack[stack_idx] = *prev = ap->data[idx];
  299. ap->data[idx] = KP_TRY (call_n (interp, argc + 1));
  300. }
  301. else
  302. while (true)
  303. {
  304. *prev = ap->data[idx];
  305. interp->stack[stack_idx] = *prev;
  306. KP_VTRY (call_n (interp, argc + 1));
  307. if (atomic_cas_bool ((atomic_t *)&ap->data[idx],
  308. (atomic_t)*prev, (atomic_t)interp->retval))
  309. break;
  310. atomic_spin_nop ();
  311. }
  312. deref (gc_wbarrier (interp, obj, interp->retval));
  313. if (flags & NZAP_PREV)
  314. interp->retval = *prev;
  315. return (interp->retval);
  316. }
  317. result<object> last_a (interpreter *interp, object obj)
  318. {
  319. const array *ap = as_array (obj);
  320. if (!ap->len)
  321. return (interp->raise_oob (0, 0));
  322. kp_return (ap->data[ap->len - 1]);
  323. }
  324. result<object> find_a (interpreter *interp, object obj,
  325. object key, object start, object end, object test)
  326. {
  327. const array *ap = as_array (obj);
  328. int istart = start == UNBOUND ? 0 : get_idx (ap, as_int (start));
  329. int iend = end == UNBOUND ? ap->len : get_idx (ap, as_int (end));
  330. if (istart > iend)
  331. kp_return (NIL);
  332. else if ((istart | iend) < 0 || (uint32_t)iend > ap->len)
  333. return (interp->raise ("index-error", "indices out of bounds"));
  334. if (test == UNBOUND)
  335. {
  336. valref tmp (interp);
  337. for (; istart < iend; ++istart)
  338. {
  339. bool rv = KP_TRY (equal (interp, key, *tmp = ap->data[istart]));
  340. if (rv)
  341. kp_return (fixint (istart));
  342. }
  343. }
  344. else
  345. {
  346. KP_VTRY (interp->growstk (3));
  347. for (; istart < iend; ++istart)
  348. {
  349. *interp->stkend++ = test;
  350. *interp->stkend++ = key;
  351. *interp->stkend++ = ap->data[istart];
  352. KP_VTRY (call_n (interp, 2));
  353. if (interp->retval != NIL)
  354. kp_return (fixint (istart));
  355. }
  356. }
  357. kp_return (NIL);
  358. }
  359. result<int64_t> write_a (interpreter *interp, stream *strm,
  360. object obj, io_info& info)
  361. {
  362. int64_t ret = 0;
  363. ret += KP_TRY (strm->putb (interp, '['));
  364. array::iterator it { interp, obj };
  365. if (it.valid ())
  366. while (true)
  367. {
  368. ret += KP_TRY (xwrite (interp, strm, *it, info));
  369. if (!(++it).valid ())
  370. break;
  371. ret += KP_TRY (strm->putb (interp, ' '));
  372. }
  373. ret += KP_TRY (strm->putb (interp, ']'));
  374. return (ret);
  375. }
  376. result<int64_t> pack_a (interpreter *interp, stream *strm,
  377. object obj, pack_info& info)
  378. {
  379. const array *ap = as_array (obj);
  380. int64_t ret = 0;
  381. if (kp_likely (ap->len <= 0xff))
  382. { ret += KP_TRY (strm->putb (interp, (unsigned char)ap->len)); }
  383. else
  384. {
  385. ret += KP_TRY (strm->putb (interp, 0));
  386. ret += KP_TRY (strm->write (interp, &ap->len));
  387. }
  388. pack_info::eviction_guard eg { info, !ap->flagged_p (array::nonref_flag) };
  389. for (array::iterator it { interp, obj }; it.valid (); ++it)
  390. { ret += KP_TRY (xpack (interp, strm, *it, info)); }
  391. return (ret);
  392. }
  393. result<object> unpack_a (interpreter *interp, stream *strm,
  394. pack_info& info, bool save)
  395. {
  396. uint32_t len = KP_TRY (strm->getb (interp));
  397. if ((int)len < 0)
  398. return (info.error ("invalid array length"));
  399. else if (len == 0)
  400. {
  401. bool rv = KP_TRY (strm->sread (interp, &len));
  402. if (!rv)
  403. return (info.error ("invalid array length"));
  404. }
  405. raw_acc<array> ax (len);
  406. array *ret = ax.get ();
  407. valref obr (interp, ret->as_obj ());
  408. if (save)
  409. KP_VTRY (info.add_mapping (interp, *info.offset, *obr));
  410. for (ret->len = 0; ret->len < len; ++ret->len)
  411. { ret->data[ret->len] = KP_TRY (xunpack (interp, strm, info)); }
  412. ax.release ();
  413. interp->retval = *obr;
  414. gc_register (interp, ret, sizeof (*ret) + ret->len * sizeof (object));
  415. return (interp->retval);
  416. }
  417. static int
  418. do_init_array (interpreter *)
  419. {
  420. empty_array.vo_full = FLAGS_CONST;
  421. empty_array.vo_type = typecode::ARRAY;
  422. return (init_op::result_ok);
  423. }
  424. init_op init_array (do_init_array, "array");
  425. KP_DECLS_END