PageRenderTime 40ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/Languages/Ruby/Libraries/Builtins/HashOps.cs

http://github.com/IronLanguages/main
C# | 231 lines | 170 code | 37 blank | 24 comment | 23 complexity | 702b7c50bfee443cafe37cee7c515670 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * ironruby@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Collections;
  17. using System.Collections.Generic;
  18. using System.Runtime.CompilerServices;
  19. using IronRuby.Runtime;
  20. using Microsoft.Scripting.Runtime;
  21. using Microsoft.Scripting.Utils;
  22. using System.Diagnostics;
  23. using Microsoft.Scripting.Generation;
  24. using System.Threading;
  25. using IronRuby.Runtime.Calls;
  26. using IronRuby.Runtime.Conversions;
  27. namespace IronRuby.Builtins {
  28. /// <summary>
  29. /// Dictionary inherits from Object, mixes in Enumerable.
  30. /// Ruby hash is a Dictionary{object, object}, but it adds default value/proc
  31. ///
  32. /// TODO: Not all .NET types implement the right Equals, GetHashCode semantics (e.g. List{object})
  33. /// </summary>
  34. [RubyClass("Hash", Extends = typeof(Hash), Inherits = typeof(object)), Includes(typeof(IDictionary<object, object>), Copy = true)]
  35. public static class HashOps {
  36. #region Construction
  37. [RubyConstructor]
  38. public static Hash/*!*/ CreateHash(RubyClass/*!*/ self) {
  39. return new Hash(self.Context.EqualityComparer);
  40. }
  41. [RubyConstructor]
  42. public static Hash/*!*/ CreateHash(BlockParam block, RubyClass/*!*/ self, object defaultValue) {
  43. if (block != null) {
  44. throw RubyExceptions.CreateArgumentError("wrong number of arguments");
  45. }
  46. return new Hash(self.Context.EqualityComparer, null, defaultValue);
  47. }
  48. [RubyConstructor]
  49. public static Hash/*!*/ CreateHash([NotNull]BlockParam/*!*/ defaultProc, RubyClass/*!*/ self) {
  50. return new Hash(self.Context.EqualityComparer, defaultProc.Proc, null);
  51. }
  52. [RubyMethod("[]", RubyMethodAttributes.PublicSingleton)]
  53. public static Hash/*!*/ CreateSubclass(RubyClass/*!*/ self) {
  54. return Hash.CreateInstance(self);
  55. }
  56. [RubyMethod("[]", RubyMethodAttributes.PublicSingleton)]
  57. public static Hash/*!*/ CreateSubclass(ConversionStorage<IDictionary<object, object>>/*!*/ toHash, ConversionStorage<IList>/*!*/ toAry,
  58. RubyClass/*!*/ self, object listOrHash) {
  59. var toHashSite = toHash.GetSite(TryConvertToHashAction.Make(toHash.Context));
  60. var hash = toHashSite.Target(toHashSite, listOrHash);
  61. if (hash != null) {
  62. return CreateSubclass(self, hash);
  63. }
  64. var toArySite = toAry.GetSite(TryConvertToArrayAction.Make(toAry.Context));
  65. var array = toArySite.Target(toArySite, listOrHash);
  66. if (array != null) {
  67. return CreateSubclass(toAry, self, array);
  68. }
  69. throw RubyExceptions.CreateArgumentError("odd number of arguments for Hash");
  70. }
  71. [RubyMethod("[]", RubyMethodAttributes.PublicSingleton)]
  72. public static Hash/*!*/ CreateSubclass(ConversionStorage<IList>/*!*/ toAry, RubyClass/*!*/ self, [NotNull]IList/*!*/ list) {
  73. Hash result = Hash.CreateInstance(self);
  74. var toArySite = toAry.GetSite(TryConvertToArrayAction.Make(toAry.Context));
  75. foreach (object item in list) {
  76. IList pair = toArySite.Target(toArySite, item);
  77. if (pair != null && pair.Count >= 1 && pair.Count <= 2) {
  78. RubyUtils.SetHashElement(self.Context, result, pair[0], (pair.Count == 2) ? pair[1] : null);
  79. }
  80. }
  81. return result;
  82. }
  83. [RubyMethod("[]", RubyMethodAttributes.PublicSingleton)]
  84. public static Hash/*!*/ CreateSubclass(RubyClass/*!*/ self, [NotNull]IDictionary<object, object>/*!*/ hash) {
  85. // creates a new hash and copies entries of the given hash into it (no other objects associated with the has are copied):
  86. return IDictionaryOps.ReplaceData(Hash.CreateInstance(self), hash);
  87. }
  88. [RubyMethod("[]", RubyMethodAttributes.PublicSingleton)]
  89. public static Hash/*!*/ CreateSubclass(RubyClass/*!*/ self, params object[]/*!*/ items) {
  90. Debug.Assert(items.Length > 0);
  91. if (items.Length % 2 != 0) {
  92. throw RubyExceptions.CreateArgumentError("odd number of arguments for Hash");
  93. }
  94. return RubyUtils.SetHashElements(self.Context, Hash.CreateInstance(self), items);
  95. }
  96. // Reinitialization. Not called when a factory/non-default ctor is called.
  97. [RubyMethod("initialize", RubyMethodAttributes.PrivateInstance)]
  98. public static Hash/*!*/ Initialize(Hash/*!*/ self) {
  99. Assert.NotNull(self);
  100. self.RequireNotFrozen();
  101. return self;
  102. }
  103. // Reinitialization. Not called when a factory/non-default ctor is called.
  104. [RubyMethod("initialize", RubyMethodAttributes.PrivateInstance)]
  105. public static Hash/*!*/ Initialize(BlockParam block, Hash/*!*/ self, object defaultValue) {
  106. Assert.NotNull(self);
  107. if (block != null) {
  108. throw RubyExceptions.CreateArgumentError("wrong number of arguments");
  109. }
  110. self.DefaultProc = null;
  111. self.DefaultValue = defaultValue;
  112. return self;
  113. }
  114. // Reinitialization. Not called when a factory/non-default ctor is called.
  115. [RubyMethod("initialize", RubyMethodAttributes.PrivateInstance)]
  116. public static Hash/*!*/ Initialize([NotNull]BlockParam/*!*/ defaultProc, Hash/*!*/ self) {
  117. Assert.NotNull(self, defaultProc);
  118. self.DefaultProc = defaultProc.Proc;
  119. self.DefaultValue = null;
  120. return self;
  121. }
  122. [RubyMethod("initialize_copy", RubyMethodAttributes.PrivateInstance)]
  123. public static Hash/*!*/ InitializeCopy(RubyContext/*!*/ context, Hash/*!*/ self, [NotNull]Hash/*!*/ source) {
  124. self.DefaultProc = source.DefaultProc;
  125. self.DefaultValue = source.DefaultValue;
  126. IDictionaryOps.ReplaceData(self, source);
  127. return self;
  128. }
  129. #endregion
  130. [RubyMethod("try_convert", RubyMethodAttributes.PublicSingleton)]
  131. public static IDictionary<object, object> TryConvert(ConversionStorage<IDictionary<object, object>>/*!*/ toHash, RubyClass/*!*/ self, object obj) {
  132. var site = toHash.GetSite(TryConvertToHashAction.Make(toHash.Context));
  133. return site.Target(site, obj);
  134. }
  135. #region Instance Methods
  136. [RubyMethod("[]")]
  137. public static object GetElement(BinaryOpStorage/*!*/ storage, IDictionary<object, object>/*!*/ self, object key) {
  138. object result;
  139. if (!self.TryGetValue(CustomStringDictionary.NullToObj(key), out result)) {
  140. var site = storage.GetCallSite("default", 1);
  141. return site.Target(site, self, key);
  142. }
  143. return result;
  144. }
  145. [RubyMethod("default")]
  146. public static object GetDefaultValue(RubyContext/*!*/ context, Hash/*!*/ self) {
  147. return self.DefaultValue;
  148. }
  149. [RubyMethod("default")]
  150. public static object GetDefaultValue(CallSiteStorage<Func<CallSite, Proc, Hash, object, object>>/*!*/ storage, Hash/*!*/ self, object key) {
  151. if (self.DefaultProc != null) {
  152. var site = storage.GetCallSite("call", 2);
  153. return site.Target(site, self.DefaultProc, self, key);
  154. }
  155. return self.DefaultValue;
  156. }
  157. [RubyMethod("default=")]
  158. public static object SetDefaultValue(RubyContext/*!*/ context, Hash/*!*/ self, object value) {
  159. self.DefaultProc = null;
  160. return self.DefaultValue = value;
  161. }
  162. [RubyMethod("default_proc")]
  163. public static Proc GetDefaultProc(Hash/*!*/ self) {
  164. return self.DefaultProc;
  165. }
  166. [RubyMethod("replace")]
  167. public static Hash/*!*/ Replace(RubyContext/*!*/ context, Hash/*!*/ self, [DefaultProtocol, NotNull]IDictionary<object,object>/*!*/ other) {
  168. if (Object.ReferenceEquals(self, other)) {
  169. self.RequireNotFrozen();
  170. return self;
  171. }
  172. Hash otherHash = other as Hash;
  173. if (otherHash != null) {
  174. self.DefaultValue = otherHash.DefaultValue;
  175. self.DefaultProc = otherHash.DefaultProc;
  176. }
  177. return IDictionaryOps.ReplaceData(self, other);
  178. }
  179. [RubyMethod("shift")]
  180. public static object Shift(CallSiteStorage<Func<CallSite, Hash, object, object>>/*!*/ storage, Hash/*!*/ self) {
  181. self.RequireNotFrozen();
  182. if (self.Count == 0) {
  183. var site = storage.GetCallSite("default", 1);
  184. return site.Target(site, self, null);
  185. }
  186. IEnumerator<KeyValuePair<object, object>> e = self.GetEnumerator();
  187. e.MoveNext();
  188. KeyValuePair<object, object> pair = e.Current;
  189. self.Remove(pair.Key);
  190. return IDictionaryOps.MakeArray(pair);
  191. }
  192. #endregion
  193. }
  194. }