PageRenderTime 58ms CodeModel.GetById 6ms RepoModel.GetById 0ms app.codeStats 0ms

/src/sys/js/fan/List.js

https://bitbucket.org/bedlaczech/fan-1.0
JavaScript | 1035 lines | 849 code | 109 blank | 77 comment | 297 complexity | 21e6b710e9ce57996a6c52e859a99c50 MD5 | raw file
Possible License(s): CC-BY-SA-3.0
  1. //
  2. // Copyright (c) 2009, Brian Frank and Andy Frank
  3. // Licensed under the Academic Free License version 3.0
  4. //
  5. // History:
  6. // 12 Jan 09 Andy Frank Creation
  7. // 20 May 09 Andy Frank Refactor to new OO model
  8. // 3 Dec 09 Andy Frank Wrap Array object
  9. //
  10. /**
  11. * List
  12. */
  13. fan.sys.List = fan.sys.Obj.$extend(fan.sys.Obj);
  14. //////////////////////////////////////////////////////////////////////////
  15. // Constructors
  16. //////////////////////////////////////////////////////////////////////////
  17. fan.sys.List.make = function(of, values)
  18. {
  19. if (of == null) throw fan.sys.NullErr();
  20. if (values === undefined || typeof(values) == "number") values = [];
  21. var self = new fan.sys.List();
  22. self.m_of = of;
  23. self.m_size = values.length;
  24. self.m_values = values;
  25. self.m_readonly = false;
  26. self.m_immutable = false;
  27. return self;
  28. }
  29. fan.sys.List.makeObj = function(capacity)
  30. {
  31. return fan.sys.List.make(fan.sys.Obj.$type);
  32. }
  33. fan.sys.List.prototype.$ctor = function()
  34. {
  35. }
  36. //////////////////////////////////////////////////////////////////////////
  37. // Identity
  38. //////////////////////////////////////////////////////////////////////////
  39. fan.sys.List.prototype.$typeof = function() { return this.m_of.toListOf(); }
  40. fan.sys.List.prototype.of = function() { return this.m_of; }
  41. fan.sys.List.prototype.isEmpty = function() { return this.m_size == 0; }
  42. fan.sys.List.prototype.size = function() { return this.m_size; }
  43. fan.sys.List.prototype.size$ = function(val)
  44. {
  45. this.modify();
  46. var oldSize = this.m_size;
  47. var newSize = val;
  48. for (var i=0; this.m_size+i<newSize; i++)
  49. this.m_values.push(null);
  50. this.m_size = newSize;
  51. }
  52. fan.sys.List.prototype.capacity = function() { return this.m_values.length; }
  53. fan.sys.List.prototype.capacity$ = function(val)
  54. {
  55. this.modify();
  56. if (val < this.m_size) throw fan.sys.ArgErr.make("capacity < size");
  57. // noop
  58. }
  59. fan.sys.List.prototype.get = function(index)
  60. {
  61. if (index < 0) index = this.m_size + index;
  62. if (index >= this.m_size || index < 0) throw fan.sys.IndexErr.make(index);
  63. return this.m_values[index];
  64. }
  65. fan.sys.List.prototype.getSafe = function(index, def)
  66. {
  67. if (def === undefined) def = null;
  68. if (index < 0) index = this.m_size + index;
  69. if (index >= this.m_size || index < 0) return def;
  70. return this.m_values[index];
  71. }
  72. fan.sys.List.prototype.getRange = function(range)
  73. {
  74. var s = range.$start(this.m_size);
  75. var e = range.$end(this.m_size);
  76. if (e+1 < s || s < 0) throw fan.sys.IndexErr.make(range);
  77. return fan.sys.List.make(this.m_of, this.m_values.slice(s, e+1));
  78. }
  79. fan.sys.List.prototype.contains = function(value)
  80. {
  81. return this.index(value) != null;
  82. }
  83. fan.sys.List.prototype.containsAll = function(list)
  84. {
  85. for (var i=0; i<list.size(); ++i)
  86. if (this.index(list.get(i)) == null)
  87. return false;
  88. return true;
  89. }
  90. fan.sys.List.prototype.containsAny = function(list)
  91. {
  92. for (var i=0; i<list.size(); ++i)
  93. if (this.index(list.get(i)) != null)
  94. return true;
  95. return false;
  96. }
  97. fan.sys.List.prototype.index = function(value, off)
  98. {
  99. if (off === undefined) off = 0;
  100. var size = this.m_size;
  101. var values = this.m_values;
  102. if (size == 0) return null;
  103. var start = off;
  104. if (start < 0) start = size + start;
  105. if (start >= size || start < 0) throw fan.sys.IndexErr.make(off);
  106. if (value == null)
  107. {
  108. for (var i=start; i<size; ++i)
  109. if (values[i] == null)
  110. return i;
  111. }
  112. else
  113. {
  114. for (var i=start; i<size; ++i)
  115. {
  116. var obj = values[i];
  117. if (obj != null && fan.sys.ObjUtil.equals(obj, value))
  118. return i;
  119. }
  120. }
  121. return null;
  122. }
  123. fan.sys.List.prototype.indexr = function(value, off)
  124. {
  125. if (off === undefined) off = -1;
  126. var size = this.m_size;
  127. var values = this.m_values;
  128. if (size == 0) return null;
  129. var start = off;
  130. if (start < 0) start = size + start;
  131. if (start >= size || start < 0) throw fan.sys.IndexErr.make(off);
  132. if (value == null)
  133. {
  134. for (var i=start; i>=0; --i)
  135. if (values[i] == null)
  136. return i;
  137. }
  138. else
  139. {
  140. for (var i=start; i>=0; --i)
  141. {
  142. var obj = values[i];
  143. if (obj != null && fan.sys.ObjUtil.equals(obj, value))
  144. return i;
  145. }
  146. }
  147. return null;
  148. }
  149. fan.sys.List.prototype.indexSame = function(value, off)
  150. {
  151. if (off === undefined) off = 0;
  152. var size = this.m_size;
  153. var values = this.m_values;
  154. if (size == 0) return null;
  155. var start = off;
  156. if (start < 0) start = size + start;
  157. if (start >= size || start < 0) throw fan.sys.IndexErr.make(off);
  158. for (var i=start; i<size; i++)
  159. if (value === values[i])
  160. return i;
  161. return null;
  162. }
  163. fan.sys.List.prototype.first = function()
  164. {
  165. if (this.m_size == 0) return null;
  166. return this.m_values[0];
  167. }
  168. fan.sys.List.prototype.last = function()
  169. {
  170. if (this.m_size == 0) return null;
  171. return this.m_values[this.m_size-1];
  172. }
  173. fan.sys.List.prototype.dup = function()
  174. {
  175. return fan.sys.List.make(this.m_of, this.m_values.slice(0));
  176. }
  177. fan.sys.List.prototype.hash = function()
  178. {
  179. var hash = 33;
  180. var size = this.m_size;
  181. var vals = this.m_values;
  182. for (var i=0; i<size; ++i)
  183. {
  184. var obj = vals[i];
  185. hash = (31*hash) + (obj == null ? 0 : fan.sys.ObjUtil.hash(obj));
  186. }
  187. return hash;
  188. }
  189. fan.sys.List.prototype.equals = function(that)
  190. {
  191. if (that instanceof fan.sys.List)
  192. {
  193. if (!this.m_of.equals(that.m_of)) return false;
  194. if (this.m_size != that.m_size) return false;
  195. for (var i=0; i<this.m_size; ++i)
  196. if (!fan.sys.ObjUtil.equals(this.m_values[i], that.m_values[i]))
  197. return false;
  198. return true;
  199. }
  200. return false;
  201. }
  202. //////////////////////////////////////////////////////////////////////////
  203. // Modification
  204. //////////////////////////////////////////////////////////////////////////
  205. fan.sys.List.prototype.set = function(index, value)
  206. {
  207. this.modify();
  208. //try
  209. //{
  210. if (index < 0) index = this.m_size + index;
  211. if (index >= this.m_size || index < 0) throw fan.sys.IndexErr.make(index);
  212. this.m_values[index] = value;
  213. return this;
  214. //}
  215. //catch (ArrayIndexOutOfBoundsException e)
  216. //{
  217. // throw IndexErr.make(index).val;
  218. //}
  219. //catch (ArrayStoreException e)
  220. //{
  221. // throw CastErr.make("Setting '" + FanObj.type(value) + "' into '" + of + "[]'").val;
  222. //}
  223. }
  224. fan.sys.List.prototype.add = function(value)
  225. {
  226. // modify in insert$
  227. return this.insert$(this.m_size, value);
  228. }
  229. fan.sys.List.prototype.addAll = function(list)
  230. {
  231. // modify in insertAll$
  232. return this.insertAll$(this.m_size, list);
  233. }
  234. fan.sys.List.prototype.insert = function(index, value)
  235. {
  236. // modify in insert$
  237. if (index < 0) index = this.m_size + index;
  238. if (index > this.m_size || index < 0) throw fan.sys.IndexErr.make(index);
  239. return this.insert$(index, value);
  240. }
  241. fan.sys.List.prototype.insert$ = function(i, value)
  242. {
  243. //try
  244. //{
  245. this.modify();
  246. this.m_values.splice(i, 0, value);
  247. this.m_size++;
  248. return this;
  249. //}
  250. //catch (ArrayStoreException e)
  251. //{
  252. // throw CastErr.make("Adding '" + FanObj.type(value) + "' into '" + of + "[]'").val;
  253. //}
  254. }
  255. fan.sys.List.prototype.insertAll = function(index, list)
  256. {
  257. // modify in insertAll$
  258. if (index < 0) index = this.m_size + index;
  259. if (index > this.m_size || index < 0) throw fan.sys.IndexErr.make(index);
  260. return this.insertAll$(index, list);
  261. }
  262. fan.sys.List.prototype.insertAll$ = function(i, list)
  263. {
  264. // TODO: worth it to optimze small lists?
  265. // splice(i, 0, list[0], list[1], list[2])
  266. this.modify();
  267. if (list.m_size == 0) return this;
  268. var vals = list.m_values;
  269. if (this.m_values === vals) vals = vals.slice(0);
  270. for (var j=0; j<list.m_size; j++)
  271. this.m_values.splice(i+j, 0, vals[j]);
  272. this.m_size += list.m_size;
  273. return this;
  274. }
  275. fan.sys.List.prototype.remove = function(value)
  276. {
  277. // modify in removeAt
  278. var index = this.index(value);
  279. if (index == null) return null;
  280. return this.removeAt(index);
  281. }
  282. fan.sys.List.prototype.removeSame = function(value)
  283. {
  284. // modify in removeAt
  285. var index = this.indexSame(value);
  286. if (index == null) return null;
  287. return this.removeAt(index);
  288. }
  289. fan.sys.List.prototype.removeAt = function(index)
  290. {
  291. this.modify();
  292. if (index < 0) index = this.m_size + index;
  293. if (index >= this.m_size || index < 0) throw fan.sys.IndexErr.make(index);
  294. var old = this.m_values.splice(index, 1);
  295. this.m_size--;
  296. return old[0];
  297. }
  298. fan.sys.List.prototype.removeRange = function(r)
  299. {
  300. this.modify();
  301. var s = r.$start(this.m_size);
  302. var e = r.$end(this.m_size);
  303. var n = e - s + 1;
  304. if (n < 0) throw fan.sys.IndexErr.make(r);
  305. this.m_values.splice(s, n);
  306. this.m_size -= n;
  307. return this;
  308. }
  309. fan.sys.List.prototype.removeAll = function(toRemove)
  310. {
  311. this.modify();
  312. for (var i=0; i<toRemove.m_size; i++)
  313. this.remove(toRemove.get(i));
  314. return this;
  315. }
  316. fan.sys.List.prototype.trim = function()
  317. {
  318. this.modify();
  319. return this;
  320. }
  321. fan.sys.List.prototype.clear = function()
  322. {
  323. this.modify();
  324. this.m_values.splice(0, this.m_size);
  325. this.m_size = 0;
  326. return this;
  327. }
  328. fan.sys.List.prototype.fill = function(value, times)
  329. {
  330. this.modify();
  331. for (var i=0; i<times; i++) this.add(value);
  332. return this;
  333. }
  334. //////////////////////////////////////////////////////////////////////////
  335. // Stack
  336. //////////////////////////////////////////////////////////////////////////
  337. fan.sys.List.prototype.peek = function()
  338. {
  339. if (this.m_size == 0) return null;
  340. return this.m_values[this.m_size-1];
  341. }
  342. fan.sys.List.prototype.pop = function()
  343. {
  344. // modify in removeAt()
  345. if (this.m_size == 0) return null;
  346. return this.removeAt(-1);
  347. }
  348. fan.sys.List.prototype.push = function(obj)
  349. {
  350. // modify in add()
  351. return this.add(obj);
  352. }
  353. //////////////////////////////////////////////////////////////////////////
  354. // Iterators
  355. //////////////////////////////////////////////////////////////////////////
  356. fan.sys.List.prototype.each = function(f)
  357. {
  358. if (f.m_params.size() == 1)
  359. {
  360. for (var i=0; i<this.m_size; i++)
  361. f.call(this.m_values[i])
  362. }
  363. else
  364. {
  365. for (var i=0; i<this.m_size; i++)
  366. f.call(this.m_values[i], i)
  367. }
  368. }
  369. fan.sys.List.prototype.eachr = function(f)
  370. {
  371. if (f.m_params.size() == 1)
  372. {
  373. for (var i=this.m_size-1; i>=0; i--)
  374. f.call(this.m_values[i])
  375. }
  376. else
  377. {
  378. for (var i=this.m_size-1; i>=0; i--)
  379. f.call(this.m_values[i], i)
  380. }
  381. }
  382. fan.sys.List.prototype.eachRange = function(r, f)
  383. {
  384. var s = r.$start(this.m_size);
  385. var e = r.$end(this.m_size);
  386. var n = e - s + 1;
  387. if (n < 0) throw fan.sys.IndexErr.make(r);
  388. if (f.m_params.size() == 1)
  389. {
  390. for (var i=s; i<=e; ++i)
  391. f.call(this.m_values[i]);
  392. }
  393. else
  394. {
  395. for (var i=s; i<=e; ++i)
  396. f.call(this.m_values[i], i);
  397. }
  398. }
  399. fan.sys.List.prototype.eachWhile = function(f)
  400. {
  401. if (f.m_params.size() == 1)
  402. {
  403. for (var i=0; i<this.m_size; ++i)
  404. {
  405. var r = f.call(this.m_values[i]);
  406. if (r != null) return r;
  407. }
  408. }
  409. else
  410. {
  411. for (var i=0; i<this.m_size; ++i)
  412. {
  413. var r = f.call(this.m_values[i], i);
  414. if (r != null) return r;
  415. }
  416. }
  417. return null;
  418. }
  419. fan.sys.List.prototype.eachrWhile = function(f)
  420. {
  421. if (f.m_params.size() == 1)
  422. {
  423. for (var i=this.m_size-1; i>=0; i--)
  424. {
  425. var r = f.call(this.m_values[i]);
  426. if (r != null) return r;
  427. }
  428. }
  429. else
  430. {
  431. for (var i=this.m_size-1; i>=0; i--)
  432. {
  433. var r = f.call(this.m_values[i], i);
  434. if (r != null) return r;
  435. }
  436. }
  437. return null;
  438. }
  439. fan.sys.List.prototype.find = function(f)
  440. {
  441. if (f.m_params.size() == 1)
  442. {
  443. for (var i=0; i<this.m_size; i++)
  444. if (f.call(this.m_values[i]) == true)
  445. return this.m_values[i];
  446. }
  447. else
  448. {
  449. for (var i=0; i<this.m_size; i++)
  450. if (f.call(this.m_values[i], i) == true)
  451. return this.m_values[i];
  452. }
  453. return null;
  454. }
  455. fan.sys.List.prototype.findIndex = function(f)
  456. {
  457. if (f.m_params.size() == 1)
  458. {
  459. for (var i=0; i<this.m_size; i++)
  460. if (f.call(this.m_values[i]) == true)
  461. return i;
  462. }
  463. else
  464. {
  465. for (var i=0; i<this.m_size; i++)
  466. if (f.call(this.m_values[i], i) == true)
  467. return i;
  468. }
  469. return null;
  470. }
  471. fan.sys.List.prototype.findAll = function(f)
  472. {
  473. var acc = fan.sys.List.make(this.m_of);
  474. if (f.m_params.size() == 1)
  475. {
  476. for (var i=0; i<this.m_size; i++)
  477. if (f.call(this.m_values[i]) == true)
  478. acc.add(this.m_values[i]);
  479. }
  480. else
  481. {
  482. for (var i=0; i<this.m_size; i++)
  483. if (f.call(this.m_values[i], i) == true)
  484. acc.add(this.m_values[i]);
  485. }
  486. return acc;
  487. }
  488. fan.sys.List.prototype.findType = function(t)
  489. {
  490. var acc = fan.sys.List.make(t);
  491. for (var i=0; i<this.m_size; ++i)
  492. {
  493. var item = this.m_values[i];
  494. if (item != null && fan.sys.ObjUtil.$typeof(item).is(t))
  495. acc.add(item);
  496. }
  497. return acc;
  498. }
  499. fan.sys.List.prototype.exclude = function(f)
  500. {
  501. var acc = fan.sys.List.make(this.m_of);
  502. if (f.m_params.size() == 1)
  503. {
  504. for (var i=0; i<this.m_size; ++i)
  505. if (f.call(this.m_values[i]) != true)
  506. acc.add(this.m_values[i]);
  507. }
  508. else
  509. {
  510. for (var i=0; i<this.m_size; ++i)
  511. if (f.call(this.m_values[i], i) != true)
  512. acc.add(this.m_values[i]);
  513. }
  514. return acc;
  515. }
  516. fan.sys.List.prototype.any = function(f)
  517. {
  518. if (f.m_params.size() == 1)
  519. {
  520. for (var i=0; i<this.m_size; ++i)
  521. if (f.call(this.m_values[i]) == true)
  522. return true;
  523. }
  524. else
  525. {
  526. for (var i=0; i<this.m_size; ++i)
  527. if (f.call(this.m_values[i], i) == true)
  528. return true;
  529. }
  530. return false;
  531. }
  532. fan.sys.List.prototype.all = function(f)
  533. {
  534. if (f.m_params.size() == 1)
  535. {
  536. for (var i=0; i<this.m_size; ++i)
  537. if (f.call(this.m_values[i]) != true)
  538. return false;
  539. }
  540. else
  541. {
  542. for (var i=0; i<this.m_size; ++i)
  543. if (f.call(this.m_values[i], i) != true)
  544. return false;
  545. }
  546. return true;
  547. }
  548. fan.sys.List.prototype.reduce = function(reduction, f)
  549. {
  550. if (f.m_params.size() == 1)
  551. {
  552. for (var i=0; i<this.m_size; ++i)
  553. reduction = f.call(reduction, this.m_values[i]);
  554. }
  555. else
  556. {
  557. for (var i=0; i<this.m_size; ++i)
  558. reduction = f.call(reduction, this.m_values[i], i);
  559. }
  560. return reduction;
  561. }
  562. fan.sys.List.prototype.map = function(f)
  563. {
  564. var r = f.returns();
  565. if (r == fan.sys.Void.$type) r = fan.sys.Obj.$type.toNullable();
  566. var acc = fan.sys.List.make(r);
  567. if (f.m_params.size() == 1)
  568. {
  569. for (var i=0; i<this.m_size; ++i)
  570. acc.add(f.call(this.m_values[i]));
  571. }
  572. else
  573. {
  574. for (var i=0; i<this.m_size; ++i)
  575. acc.add(f.call(this.m_values[i], i));
  576. }
  577. return acc;
  578. }
  579. fan.sys.List.prototype.max = function(f)
  580. {
  581. if (f === undefined) f = null;
  582. if (this.m_size == 0) return null;
  583. var max = this.m_values[0];
  584. for (var i=1; i<this.m_size; ++i)
  585. {
  586. var s = this.m_values[i];
  587. if (f == null)
  588. max = (s != null && s > max) ? s : max;
  589. else
  590. max = (s != null && f.call(s, max) > 0) ? s : max;
  591. }
  592. return max;
  593. }
  594. fan.sys.List.prototype.min = function(f)
  595. {
  596. if (f === undefined) f = null;
  597. if (this.m_size == 0) return null;
  598. var min = this.m_values[0];
  599. for (var i=1; i<this.m_size; ++i)
  600. {
  601. var s = this.m_values[i];
  602. if (f == null)
  603. min = (s == null || s < min) ? s : min;
  604. else
  605. min = (s == null || f.call(s, min) < 0) ? s : min;
  606. }
  607. return min;
  608. }
  609. fan.sys.List.prototype.unique = function()
  610. {
  611. var dups = fan.sys.Map.make(fan.sys.Obj.$type, fan.sys.Obj.$type);
  612. var acc = fan.sys.List.make(this.m_of);
  613. for (var i=0; i<this.m_size; ++i)
  614. {
  615. var v = this.m_values[i];
  616. var key = v;
  617. if (key == null) key = "__null_key__";
  618. if (dups.get(key) == null)
  619. {
  620. dups.set(key, this);
  621. acc.add(v);
  622. }
  623. }
  624. return acc;
  625. }
  626. fan.sys.List.prototype.union = function(that)
  627. {
  628. var dups = fan.sys.Map.make(fan.sys.Obj.$type, fan.sys.Obj.$type);
  629. var acc = fan.sys.List.make(this.m_of);
  630. // first me
  631. for (var i=0; i<this.m_size; ++i)
  632. {
  633. var v = this.m_values[i];
  634. var key = v;
  635. if (key == null) key = "__null_key__";
  636. if (dups.get(key) == null)
  637. {
  638. dups.set(key, this);
  639. acc.add(v);
  640. }
  641. }
  642. // then him
  643. for (var i=0; i<that.m_size; ++i)
  644. {
  645. var v = that.m_values[i];
  646. var key = v;
  647. if (key == null) key = "__null_key__";
  648. if (dups.get(key) == null)
  649. {
  650. dups.set(key, this);
  651. acc.add(v);
  652. }
  653. }
  654. return acc;
  655. }
  656. fan.sys.List.prototype.intersection = function(that)
  657. {
  658. // put other list into map
  659. var dups = fan.sys.Map.make(fan.sys.Obj.$type, fan.sys.Obj.$type);
  660. for (var i=0; i<that.m_size; ++i)
  661. {
  662. var v = that.m_values[i];
  663. var key = v;
  664. if (key == null) key = "__null_key__";
  665. dups.set(key, this);
  666. }
  667. // now walk this list and accumulate
  668. // everything found in the dups map
  669. var acc = fan.sys.List.make(this.m_of);
  670. for (var i=0; i<this.m_size; ++i)
  671. {
  672. var v = this.m_values[i];
  673. var key = v;
  674. if (key == null) key = "__null_key__";
  675. if (dups.get(key) != null)
  676. {
  677. acc.add(v);
  678. dups.remove(key);
  679. }
  680. }
  681. return acc;
  682. }
  683. //////////////////////////////////////////////////////////////////////////
  684. // Utils
  685. //////////////////////////////////////////////////////////////////////////
  686. fan.sys.List.prototype.sort = function(f)
  687. {
  688. this.modify();
  689. if (f === undefined) f = null;
  690. if (f != null)
  691. this.m_values.sort(function(a,b) { return f.call(a,b) });
  692. else
  693. this.m_values.sort(function(a,b) { return fan.sys.ObjUtil.compare(a,b,false) });
  694. return this;
  695. }
  696. fan.sys.List.prototype.sortr = function(f)
  697. {
  698. this.modify();
  699. if (f === undefined) f = null;
  700. if (f != null)
  701. this.m_values.sort(function(a,b) { return f.call(b,a) });
  702. else
  703. this.m_values.sort(function(a,b) { return fan.sys.ObjUtil.compare(b,a,false) });
  704. return this;
  705. }
  706. fan.sys.List.prototype.binarySearch = function(key, f)
  707. {
  708. var c = f != null
  709. ? function(item,index) { return f.call(key,item) }
  710. : function(item,index) { return fan.sys.ObjUtil.compare(key,item,false) };
  711. return this.doBinaryFind(c);
  712. }
  713. fan.sys.List.prototype.binaryFind = function(f)
  714. {
  715. return this.doBinaryFind(f.m_func);
  716. }
  717. fan.sys.List.prototype.doBinaryFind = function(f)
  718. {
  719. var low = 0;
  720. var high = this.m_size - 1;
  721. while (low <= high)
  722. {
  723. var mid = Math.floor((low + high) / 2);
  724. var cmp = f(this.m_values[mid], mid);
  725. if (cmp > 0) low = mid + 1;
  726. else if (cmp < 0) high = mid - 1;
  727. else return mid;
  728. }
  729. return -(low + 1);
  730. }
  731. fan.sys.List.prototype.reverse = function()
  732. {
  733. this.modify();
  734. var mid = this.m_size/2;
  735. for (var i=0; i<mid; ++i)
  736. {
  737. var a = this.m_values[i];
  738. var b = this.m_values[this.m_size-i-1];
  739. this.m_values[i] = b;
  740. this.m_values[this.m_size-i-1] = a;
  741. }
  742. return this;
  743. }
  744. fan.sys.List.prototype.swap = function(a, b)
  745. {
  746. // modify in set()
  747. var temp = this.get(a);
  748. this.set(a, this.get(b));
  749. this.set(b, temp);
  750. return this;
  751. }
  752. fan.sys.List.prototype.moveTo = function(item, toIndex)
  753. {
  754. this.modify();
  755. var curIndex = this.index(item);
  756. if (curIndex == null) return this;
  757. if (curIndex == toIndex) return this;
  758. this.removeAt(curIndex);
  759. if (toIndex == -1) return this.add(item);
  760. if (toIndex < 0) ++toIndex;
  761. return this.insert(toIndex, item);
  762. }
  763. fan.sys.List.prototype.flatten = function()
  764. {
  765. var acc = fan.sys.List.make(fan.sys.Obj.$type.toNullable());
  766. this.doFlatten(acc);
  767. return acc;
  768. }
  769. fan.sys.List.prototype.doFlatten = function(acc)
  770. {
  771. for (var i=0; i<this.m_size; ++i)
  772. {
  773. var item = this.m_values[i];
  774. if (item instanceof fan.sys.List)
  775. item.doFlatten(acc);
  776. else
  777. acc.add(item);
  778. }
  779. }
  780. fan.sys.List.prototype.random = function()
  781. {
  782. if (this.m_size == 0) return null;
  783. var i = Math.floor(Math.random() * 4294967296);
  784. if (i < 0) i = -i;
  785. return this.m_values[i % this.m_size];
  786. }
  787. fan.sys.List.prototype.shuffle = function()
  788. {
  789. this.modify();
  790. for (var i=0; i<this.m_size; ++i)
  791. {
  792. var randi = Math.floor(Math.random() * (i+1));
  793. var temp = this.m_values[i];
  794. this.m_values[i] = this.m_values[randi];
  795. this.m_values[randi] = temp;
  796. }
  797. return this;
  798. }
  799. //////////////////////////////////////////////////////////////////////////
  800. // Conversion
  801. //////////////////////////////////////////////////////////////////////////
  802. fan.sys.List.prototype.join = function(sep, f)
  803. {
  804. if (sep === undefined) sep = "";
  805. if (f === undefined) f = null;
  806. if (this.m_size === 0) return "";
  807. if (this.m_size === 1)
  808. {
  809. var v = this.m_values[0];
  810. if (f != null) return f.call(v, 0);
  811. if (v == null) return "null";
  812. return fan.sys.ObjUtil.toStr(v);
  813. }
  814. var s = ""
  815. for (var i=0; i<this.m_size; ++i)
  816. {
  817. if (i > 0) s += sep;
  818. if (f == null)
  819. s += this.m_values[i];
  820. else
  821. s += f.call(this.m_values[i], i);
  822. }
  823. return s;
  824. }
  825. fan.sys.List.prototype.toStr = function()
  826. {
  827. if (this.m_size == 0) return "[,]";
  828. var s = "[";
  829. for (var i=0; i<this.m_size; i++)
  830. {
  831. if (i > 0) s += ", ";
  832. s += this.m_values[i];
  833. }
  834. s += "]";
  835. return s;
  836. }
  837. fan.sys.List.prototype.toCode = function()
  838. {
  839. var s = '';
  840. s += this.m_of.signature();
  841. s += '[';
  842. if (this.m_size == 0) s += ',';
  843. for (var i=0; i<this.m_size; ++i)
  844. {
  845. if (i > 0) s += ', ';
  846. s += fan.sys.ObjUtil.trap(this.m_values[i], "toCode", null);
  847. }
  848. s += ']';
  849. return s;
  850. }
  851. fan.sys.List.prototype.$literalEncode = function(out)
  852. {
  853. // route back to obj encoder
  854. out.writeList(this);
  855. }
  856. //////////////////////////////////////////////////////////////////////////
  857. // Readonly
  858. //////////////////////////////////////////////////////////////////////////
  859. fan.sys.List.prototype.isRW = function()
  860. {
  861. return !this.m_readonly;
  862. }
  863. fan.sys.List.prototype.isRO = function()
  864. {
  865. return this.m_readonly;
  866. }
  867. fan.sys.List.prototype.rw = function()
  868. {
  869. if (!this.m_readonly) return this;
  870. var rw = fan.sys.List.make(this.m_of, this.m_values.slice(0));
  871. rw.m_readonly = false;
  872. rw.m_readonlyList = this;
  873. return rw;
  874. }
  875. fan.sys.List.prototype.ro = function()
  876. {
  877. if (this.m_readonly) return this;
  878. if (this.m_readonlyList == null)
  879. {
  880. var ro = fan.sys.List.make(this.m_of, this.m_values.slice(0));
  881. ro.m_readonly = true;
  882. this.m_readonlyList = ro;
  883. }
  884. return this.m_readonlyList;
  885. }
  886. fan.sys.List.prototype.isImmutable = function()
  887. {
  888. return this.m_immutable;
  889. }
  890. fan.sys.List.prototype.toImmutable = function()
  891. {
  892. if (this.m_immutable) return this;
  893. // make safe copy
  894. var temp = [];
  895. for (var i=0; i<this.m_size; ++i)
  896. {
  897. var item = this.m_values[i];
  898. if (item != null)
  899. {
  900. if (item instanceof fan.sys.List) item = item.toImmutable();
  901. else if (item instanceof fan.sys.Map) item = item.toImmutable();
  902. else if (!fan.sys.ObjUtil.isImmutable(item))
  903. throw fan.sys.NotImmutableErr.make("Item [" + i + "] not immutable " +
  904. fan.sys.Type.of(item));
  905. }
  906. temp[i] = item;
  907. }
  908. // return new immutable list
  909. var ro = fan.sys.List.make(this.m_of, temp);
  910. ro.m_readonly = true;
  911. ro.m_immutable = true;
  912. return ro;
  913. }
  914. fan.sys.List.prototype.modify = function()
  915. {
  916. // if readonly then throw readonly exception
  917. if (this.m_readonly)
  918. throw fan.sys.ReadonlyErr.make("List is readonly");
  919. // if we have a cached readonlyList, then detach
  920. // it so it remains immutable
  921. if (this.m_readonlyList != null)
  922. {
  923. this.m_readonlyList.m_values = this.m_values.slice(0);
  924. this.m_readonlyList = null;
  925. }
  926. }