PageRenderTime 80ms CodeModel.GetById 35ms RepoModel.GetById 1ms app.codeStats 0ms

/src/sys/dotnet/fan/sys/Map.cs

https://bitbucket.org/bedlaczech/fan-1.0
C# | 701 lines | 569 code | 89 blank | 43 comment | 146 complexity | 4a16bf90e65b54398e9d5664244eed04 MD5 | raw file
Possible License(s): CC-BY-SA-3.0
  1. //
  2. // Copyright (c) 2006, Brian Frank and Andy Frank
  3. // Licensed under the Academic Free License version 3.0
  4. //
  5. // History:
  6. // 28 Sep 06 Andy Frank Creation
  7. //
  8. using System;
  9. using System.Collections;
  10. using System.Diagnostics;
  11. using System.Collections.Specialized;
  12. using System.Text;
  13. using Fanx.Serial;
  14. namespace Fan.Sys
  15. {
  16. /// <summary>
  17. /// Map is a hashm_map of key value pairs.
  18. /// </summary>
  19. public sealed class Map : FanObj, Literal
  20. {
  21. //////////////////////////////////////////////////////////////////////////
  22. // Constructors
  23. //////////////////////////////////////////////////////////////////////////
  24. public static Map make(Type type)
  25. {
  26. return new Map((MapType)type, new Hashtable());
  27. }
  28. public Map(Type k, Type v) : this(new MapType(k, v), new Hashtable())
  29. {
  30. }
  31. public Map(MapType type) : this(type, new Hashtable())
  32. {
  33. }
  34. public Map(MapType type, IDictionary map)
  35. {
  36. if (type == null || map == null)
  37. {
  38. Console.WriteLine(new StackTrace(true));
  39. throw new NullErr().val;
  40. }
  41. this.m_type = type;
  42. this.m_map = map;
  43. }
  44. //////////////////////////////////////////////////////////////////////////
  45. // Identity
  46. //////////////////////////////////////////////////////////////////////////
  47. public override Type @typeof()
  48. {
  49. return m_type;
  50. }
  51. //////////////////////////////////////////////////////////////////////////
  52. // Methods
  53. //////////////////////////////////////////////////////////////////////////
  54. public bool isEmpty()
  55. {
  56. return m_map.Count == 0;
  57. }
  58. public long size()
  59. {
  60. return m_map.Count;
  61. }
  62. public object get(object key)
  63. {
  64. object val = m_map[key];
  65. if (val != null) return val;
  66. if (m_def == null) return null;
  67. return containsKey(key) ? null : m_def;
  68. }
  69. public object get(object key, object def)
  70. {
  71. object val = m_map[key];
  72. if (val != null) return val;
  73. if (def == null) return null;
  74. return containsKey(key) ? null : def;
  75. }
  76. public object getOrThrow(object key)
  77. {
  78. object val = m_map[key];
  79. if (val != null) return val;
  80. if (containsKey(key)) return null;
  81. throw UnknownKeyErr.make(key.ToString()).val;
  82. }
  83. public bool containsKey(object key)
  84. {
  85. return m_map.Contains(key);
  86. }
  87. public List keys()
  88. {
  89. return new List(m_type.m_k, m_map.Keys);
  90. }
  91. public List vals()
  92. {
  93. return new List(m_type.m_v, m_map.Values);
  94. }
  95. public Map set(object key, object val)
  96. {
  97. modify();
  98. if (key == null)
  99. throw NullErr.make("key is null").val;
  100. if (!isImmutable(key))
  101. throw NotImmutableErr.make("key is not immutable: " + @typeof(key)).val;
  102. m_map[key] = val;
  103. return this;
  104. }
  105. public Map add(object key, object val)
  106. {
  107. modify();
  108. if (key == null)
  109. throw NullErr.make("key is null").val;
  110. if (!isImmutable(key))
  111. throw NotImmutableErr.make("key is not immutable: " + @typeof(key)).val;
  112. if (containsKey(key))
  113. throw ArgErr.make("Key already mapped: " + key).val;
  114. m_map[key] = val;
  115. return this;
  116. }
  117. public object getOrAdd(object key, Func valFunc)
  118. {
  119. if (containsKey(key)) return get(key);
  120. object val = valFunc.call(key);
  121. add(key, val);
  122. return val;
  123. }
  124. public Map setAll(Map m)
  125. {
  126. modify();
  127. IDictionaryEnumerator en = m.m_map.GetEnumerator();
  128. while (en.MoveNext())
  129. {
  130. object key = en.Key;
  131. object val = en.Value;
  132. m_map[key] = val;
  133. }
  134. return this;
  135. }
  136. public Map addAll(Map m)
  137. {
  138. modify();
  139. IDictionaryEnumerator en = m.m_map.GetEnumerator();
  140. while (en.MoveNext())
  141. {
  142. object key = en.Key;
  143. object val = en.Value;
  144. add(key, val);
  145. }
  146. return this;
  147. }
  148. public Map setList(List list) { return setList(list, null); }
  149. public Map setList(List list, Func f)
  150. {
  151. modify();
  152. if (f == null)
  153. {
  154. for (int i=0; i<list.sz(); ++i)
  155. set(list.get(i), list.get(i));
  156. }
  157. else if (f.@params().sz() == 1)
  158. {
  159. for (int i=0; i<list.sz(); ++i)
  160. set(f.call(list.get(i)), list.get(i));
  161. }
  162. else
  163. {
  164. for (int i=0; i<list.sz(); ++i)
  165. set(f.call(list.get(i), i), list.get(i));
  166. }
  167. return this;
  168. }
  169. public Map addList(List list) { return addList(list, null); }
  170. public Map addList(List list, Func f)
  171. {
  172. modify();
  173. if (f == null)
  174. {
  175. for (int i=0; i<list.sz(); ++i)
  176. add(list.get(i), list.get(i));
  177. }
  178. else if (f.@params().sz() == 1)
  179. {
  180. for (int i=0; i<list.sz(); ++i)
  181. add(f.call(list.get(i)), list.get(i));
  182. }
  183. else
  184. {
  185. for (int i=0; i<list.sz(); ++i)
  186. add(f.call(list.get(i), i), list.get(i));
  187. }
  188. return this;
  189. }
  190. public object remove(object key)
  191. {
  192. modify();
  193. object val = m_map[key];
  194. m_map.Remove(key);
  195. return val;
  196. }
  197. public Map dup()
  198. {
  199. Map dup = new Map(m_type);
  200. dup.m_map = cloneMap(this.m_map);
  201. return dup;
  202. }
  203. public Map clear()
  204. {
  205. modify();
  206. m_map.Clear();
  207. return this;
  208. }
  209. public bool caseInsensitive() { return m_caseInsensitive; }
  210. public void caseInsensitive(bool v)
  211. {
  212. modify();
  213. if (m_type.m_k != Sys.StrType)
  214. throw UnsupportedErr.make("Map not keyed by string: " + m_type).val;
  215. if (m_map.Count != 0)
  216. throw UnsupportedErr.make("Map not empty").val;
  217. if (v && ordered())
  218. throw UnsupportedErr.make("Map cannot be caseInsensitive and ordered").val;
  219. if (this.m_caseInsensitive == v) return;
  220. this.m_caseInsensitive = v;
  221. if (m_caseInsensitive)
  222. m_map = new Hashtable(new CIEqualityComparer());
  223. else
  224. m_map = new Hashtable();
  225. }
  226. public bool ordered()
  227. {
  228. return m_map is OrderedDictionary;
  229. }
  230. public void ordered(bool v)
  231. {
  232. modify();
  233. if (m_map.Count != 0)
  234. throw UnsupportedErr.make("Map not empty").val;
  235. if (v && caseInsensitive())
  236. throw UnsupportedErr.make("Map cannot be caseInsensitive and ordered").val;
  237. if (ordered() == v) return;
  238. if (v)
  239. m_map = new OrderedDictionary();
  240. else
  241. m_map = new Hashtable();
  242. }
  243. public object def() { return m_def; }
  244. public void def(object v)
  245. {
  246. modify();
  247. if (v != null && !isImmutable(v))
  248. throw NotImmutableErr.make("def must be immutable: " + @typeof(v)).val;
  249. this.m_def = v;
  250. }
  251. public override bool Equals(object that)
  252. {
  253. if (that is Map)
  254. {
  255. if (!m_type.Equals(@typeof(that)))
  256. return false;
  257. IDictionary thatMap = ((Map)that).m_map;
  258. if (m_map.Count != thatMap.Count)
  259. return false;
  260. IDictionaryEnumerator en = m_map.GetEnumerator();
  261. while (en.MoveNext())
  262. {
  263. object key = en.Key;
  264. object val = en.Value;
  265. object test = thatMap[key];
  266. if (val == null)
  267. {
  268. if (test != null) return false;
  269. }
  270. else if (!val.Equals(test))
  271. {
  272. return false;
  273. }
  274. }
  275. return true;
  276. }
  277. return false;
  278. }
  279. public override int GetHashCode() { return (int)hash(); }
  280. public override long hash()
  281. {
  282. int hash = 0;
  283. IDictionaryEnumerator en = m_map.GetEnumerator();
  284. while (en.MoveNext())
  285. {
  286. object key = en.Key;
  287. object val = en.Value;
  288. hash += key.GetHashCode() ^ (val == null ? 0 : val.GetHashCode());
  289. }
  290. return hash;
  291. }
  292. public override string toStr()
  293. {
  294. if (m_map.Count == 0) return "[:]";
  295. StringBuilder s = new StringBuilder(32+m_map.Count*32);
  296. s.Append("[");
  297. bool first = true;
  298. IDictionaryEnumerator en = m_map.GetEnumerator();
  299. while (en.MoveNext())
  300. {
  301. object key = en.Key;
  302. object val = en.Value;
  303. if (!first) s.Append(", ");
  304. else first = false;
  305. s.Append(key).Append(':').Append(val);
  306. }
  307. s.Append("]");
  308. return s.ToString();
  309. }
  310. public void encode(ObjEncoder @out)
  311. {
  312. // route back to obj encoder
  313. @out.writeMap(this);
  314. }
  315. //////////////////////////////////////////////////////////////////////////
  316. // Iterators
  317. //////////////////////////////////////////////////////////////////////////
  318. public void each(Func f)
  319. {
  320. IDictionaryEnumerator en = m_map.GetEnumerator();
  321. while (en.MoveNext())
  322. {
  323. object key = en.Key;
  324. object val = en.Value;
  325. f.call(val, key);
  326. }
  327. }
  328. public object eachWhile(Func f)
  329. {
  330. IDictionaryEnumerator en = m_map.GetEnumerator();
  331. while (en.MoveNext())
  332. {
  333. object key = en.Key;
  334. object val = en.Value;
  335. object r = f.call(val, key);
  336. if (r != null) return r;
  337. }
  338. return null;
  339. }
  340. public object find(Func f)
  341. {
  342. IDictionaryEnumerator en = m_map.GetEnumerator();
  343. while (en.MoveNext())
  344. {
  345. object key = en.Key;
  346. object val = en.Value;
  347. if (f.call(val, key) == Boolean.True)
  348. return val;
  349. }
  350. return null;
  351. }
  352. public Map findAll(Func f)
  353. {
  354. Map acc = new Map(m_type);
  355. if (this.ordered()) acc.ordered(true);
  356. if (this.caseInsensitive()) acc.caseInsensitive(true);
  357. IDictionaryEnumerator en = m_map.GetEnumerator();
  358. while (en.MoveNext())
  359. {
  360. object key = en.Key;
  361. object val = en.Value;
  362. if (f.call(val, key) == Boolean.True)
  363. acc.set(key, val);
  364. }
  365. return acc;
  366. }
  367. public Map exclude(Func f)
  368. {
  369. Map acc = new Map(m_type);
  370. if (this.ordered()) acc.ordered(true);
  371. if (this.caseInsensitive()) acc.caseInsensitive(true);
  372. IDictionaryEnumerator en = m_map.GetEnumerator();
  373. while (en.MoveNext())
  374. {
  375. object key = en.Key;
  376. object val = en.Value;
  377. if (f.call(val, key) == Boolean.False)
  378. acc.set(key, val);
  379. }
  380. return acc;
  381. }
  382. public bool any(Func f)
  383. {
  384. if (m_map.Count == 0) return false;
  385. IDictionaryEnumerator en = m_map.GetEnumerator();
  386. while (en.MoveNext())
  387. {
  388. object key = en.Key;
  389. object val = en.Value;
  390. if (f.call(val, key) == Boolean.True)
  391. return true;
  392. }
  393. return false;
  394. }
  395. public bool all(Func f)
  396. {
  397. if (m_map.Count == 0) return true;
  398. IDictionaryEnumerator en = m_map.GetEnumerator();
  399. while (en.MoveNext())
  400. {
  401. object key = en.Key;
  402. object val = en.Value;
  403. if (f.call(val, key) == Boolean.False)
  404. return false;
  405. }
  406. return true;
  407. }
  408. public object reduce(object reduction, Func f)
  409. {
  410. IDictionaryEnumerator en = m_map.GetEnumerator();
  411. while (en.MoveNext())
  412. {
  413. object key = en.Key;
  414. object val = en.Value;
  415. reduction = f.call(reduction, val, key);
  416. }
  417. return reduction;
  418. }
  419. public Map map(Func f)
  420. {
  421. Type r = f.returns();
  422. if (r == Sys.VoidType) r = Sys.ObjType.toNullable();
  423. Map acc = new Map(m_type.m_k, r);
  424. if (this.ordered()) acc.ordered(true);
  425. if (this.caseInsensitive()) acc.caseInsensitive(true);
  426. IDictionaryEnumerator en = m_map.GetEnumerator();
  427. while (en.MoveNext())
  428. {
  429. object key = en.Key;
  430. object val = en.Value;
  431. acc.set(key, f.call(val, key));
  432. }
  433. return acc;
  434. }
  435. //////////////////////////////////////////////////////////////////////////
  436. // Join
  437. //////////////////////////////////////////////////////////////////////////
  438. public string join(string sep) { return join(sep, null); }
  439. public string join(string sep, Func f)
  440. {
  441. int size = (int)this.size();
  442. if (size == 0) return "";
  443. StringBuilder s = new StringBuilder(32+size*32);
  444. IDictionaryEnumerator en = m_map.GetEnumerator();
  445. while (en.MoveNext())
  446. {
  447. object key = en.Key;
  448. object val = en.Value;
  449. if (s.Length > 0) s.Append(sep);
  450. if (f == null)
  451. s.Append(key).Append(": ").Append(val);
  452. else
  453. s.Append(f.call(val, key));
  454. }
  455. return s.ToString();
  456. }
  457. public string toCode()
  458. {
  459. int size = (int)this.size();
  460. StringBuilder s = new StringBuilder(32+size*32);
  461. s.Append(@typeof().signature());
  462. s.Append('[');
  463. if (size == 0) s.Append(':');
  464. bool first = true;
  465. IDictionaryEnumerator en = m_map.GetEnumerator();
  466. while (en.MoveNext())
  467. {
  468. object key = en.Key;
  469. object val = en.Value;
  470. if (first) first = false;
  471. else s.Append(',').Append(' ');
  472. s.Append(FanObj.trap(key, "toCode", null))
  473. .Append(':')
  474. .Append(FanObj.trap(val, "toCode", null));
  475. }
  476. s.Append(']');
  477. return s.ToString();
  478. }
  479. //////////////////////////////////////////////////////////////////////////
  480. // Readonly
  481. //////////////////////////////////////////////////////////////////////////
  482. public bool isRW()
  483. {
  484. return !m_isReadonly;
  485. }
  486. public bool isRO()
  487. {
  488. return m_isReadonly;
  489. }
  490. public Map rw()
  491. {
  492. if (!m_isReadonly) return this;
  493. Map rw = new Map(m_type);
  494. rw.m_map = cloneMap(m_map);
  495. rw.m_isReadonly = false;
  496. rw.m_readonlyMap = this;
  497. rw.m_caseInsensitive = m_caseInsensitive;
  498. rw.m_def = m_def;
  499. return rw;
  500. }
  501. public Map ro()
  502. {
  503. if (m_isReadonly) return this;
  504. if (m_readonlyMap == null)
  505. {
  506. Map ro = new Map(m_type);
  507. ro.m_map = m_map;
  508. ro.m_isReadonly = true;
  509. ro.m_caseInsensitive = m_caseInsensitive;
  510. ro.m_def = m_def;
  511. m_readonlyMap = ro;
  512. }
  513. return m_readonlyMap;
  514. }
  515. public override bool isImmutable()
  516. {
  517. return m_immutable;
  518. }
  519. public override object toImmutable()
  520. {
  521. if (m_immutable) return this;
  522. // make safe copy
  523. IDictionary temp;
  524. if (caseInsensitive()) temp = new Hashtable(new CIEqualityComparer());
  525. else if (ordered()) temp = new OrderedDictionary();
  526. else temp = new Hashtable();
  527. IDictionaryEnumerator en = m_map.GetEnumerator();
  528. while (en.MoveNext())
  529. {
  530. object key = en.Key;
  531. object val = en.Value;
  532. if (val != null)
  533. {
  534. if (val is List)
  535. val = ((List)val).toImmutable();
  536. else if (val is Map)
  537. val = ((Map)val).toImmutable();
  538. else if (!isImmutable(val))
  539. throw NotImmutableErr.make("Item [" + key + "] not immutable " + @typeof(val)).val;
  540. }
  541. temp[key] = val;
  542. }
  543. // return new m_immutable m_map
  544. Map ro = new Map(m_type, temp);
  545. ro.m_isReadonly = true;
  546. ro.m_immutable = true;
  547. ro.m_caseInsensitive = m_caseInsensitive;
  548. ro.m_def = m_def;
  549. return ro;
  550. }
  551. private void modify()
  552. {
  553. // if readonly then throw readonly exception
  554. if (m_isReadonly)
  555. throw ReadonlyErr.make("Map is readonly").val;
  556. // if we have a cached m_readonlyMap, then detach
  557. // it so it remains m_immutable
  558. if (m_readonlyMap != null)
  559. {
  560. m_readonlyMap.m_map = cloneMap(m_map);
  561. m_readonlyMap = null;
  562. }
  563. }
  564. //////////////////////////////////////////////////////////////////////////
  565. // C#
  566. //////////////////////////////////////////////////////////////////////////
  567. public IDictionaryEnumerator pairsIterator()
  568. {
  569. return m_map.GetEnumerator();
  570. }
  571. public IEnumerator keysEnumerator()
  572. {
  573. return m_map.Keys.GetEnumerator();
  574. }
  575. internal IDictionary cloneMap(IDictionary dict)
  576. {
  577. if (dict is Hashtable) return (IDictionary)((Hashtable)dict).Clone();
  578. if (dict is OrderedDictionary)
  579. {
  580. OrderedDictionary dup = new OrderedDictionary();
  581. IDictionaryEnumerator en = dict.GetEnumerator();
  582. while (en.MoveNext()) dup[en.Key] = en.Value;
  583. return dup;
  584. }
  585. throw new Exception(dict.ToString());
  586. }
  587. //////////////////////////////////////////////////////////////////////////
  588. // CIEqualityComparer (Case Insensitive)
  589. //////////////////////////////////////////////////////////////////////////
  590. class CIEqualityComparer : IEqualityComparer
  591. {
  592. public new bool Equals(object x, object y)
  593. {
  594. return FanStr.equalsIgnoreCase((string)x, (string)y);
  595. }
  596. public int GetHashCode(object obj)
  597. {
  598. return FanStr.caseInsensitiveHash((string)obj);
  599. }
  600. }
  601. //////////////////////////////////////////////////////////////////////////
  602. // Fields
  603. //////////////////////////////////////////////////////////////////////////
  604. private MapType m_type;
  605. private IDictionary m_map;
  606. private Map m_readonlyMap;
  607. private bool m_isReadonly;
  608. private bool m_immutable;
  609. private bool m_caseInsensitive = false;
  610. private object m_def;
  611. }
  612. }