PageRenderTime 45ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/Languages/Ruby/Ruby/Runtime/Utils.cs

http://github.com/IronLanguages/main
C# | 1096 lines | 876 code | 171 blank | 49 comment | 190 complexity | 9910d3952898be7bfc61d3cd96525236 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. #if FEATURE_CORE_DLR
  16. using System.Linq.Expressions;
  17. #else
  18. using Microsoft.Scripting.Ast;
  19. #endif
  20. using System;
  21. using System.Globalization;
  22. using System.Diagnostics;
  23. using System.Text;
  24. using System.Reflection;
  25. using System.Collections;
  26. using System.Collections.Generic;
  27. using System.Dynamic;
  28. using Microsoft.Scripting.Utils;
  29. using IronRuby.Builtins;
  30. using Microsoft.Scripting;
  31. namespace IronRuby.Runtime {
  32. public static class Utils {
  33. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly")]
  34. public static readonly byte[] EmptyBytes = new byte[0];
  35. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly")]
  36. public static readonly char[] EmptyChars = new char[0];
  37. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly")]
  38. public static readonly MemberInfo[] EmptyMemberInfos = new MemberInfo[0];
  39. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly")]
  40. public static readonly Delegate[] EmptyDelegates = new Delegate[0];
  41. public static int IndexOf(this string[]/*!*/ array, string/*!*/ value, StringComparer/*!*/ comparer) {
  42. ContractUtils.RequiresNotNull(array, "array");
  43. ContractUtils.RequiresNotNull(value, "value");
  44. ContractUtils.RequiresNotNull(comparer, "comparer");
  45. for (int i = 0; i < array.Length; i++) {
  46. if (comparer.Equals(array[i], value)) {
  47. return i;
  48. }
  49. }
  50. return -1;
  51. }
  52. public static bool IsAscii(this string/*!*/ str) {
  53. for (int i = 0; i < str.Length; i++) {
  54. if (str[i] > 0x7f) {
  55. return false;
  56. }
  57. }
  58. return true;
  59. }
  60. public static bool IsAscii(this byte[]/*!*/ bytes, int count) {
  61. for (int i = 0; i < count; i++) {
  62. if (bytes[i] > 0x7f) {
  63. return false;
  64. }
  65. }
  66. return true;
  67. }
  68. public static bool IsAscii(this char[]/*!*/ str, int count) {
  69. for (int i = 0; i < count; i++) {
  70. if (str[i] > 0x7f) {
  71. return false;
  72. }
  73. }
  74. return true;
  75. }
  76. public static bool IsAscii(this char[]/*!*/ str, int start, int count) {
  77. for (int i = 0; i < count; i++) {
  78. if (str[start + i] > 0x7f) {
  79. return false;
  80. }
  81. }
  82. return true;
  83. }
  84. internal static bool IsBinary(this string/*!*/ str) {
  85. for (int i = 0; i < str.Length; i++) {
  86. if (str[i] > 0xff) {
  87. return false;
  88. }
  89. }
  90. return true;
  91. }
  92. internal static int GetCharacterCount(this string/*!*/ str) {
  93. int surrogateCount = 0;
  94. bool wasHighSurrogate = false;
  95. for (int i = 0; i < str.Length; i++) {
  96. char c = str[i];
  97. if (c >= '\uD800') {
  98. if (c <= '\uDBFF') {
  99. wasHighSurrogate = true;
  100. } else if (wasHighSurrogate && c <= '\uDFFF') {
  101. surrogateCount++;
  102. wasHighSurrogate = false;
  103. }
  104. }
  105. }
  106. return str.Length - surrogateCount;
  107. }
  108. /// <summary>
  109. /// Calculates the number of Unicode characters in given array.
  110. /// Assumes that the content of the array beyond count chars doesn't contain significant data and can be overwritten.
  111. /// </summary>
  112. internal static int GetCharacterCount(this char[]/*!*/ str, int count) {
  113. int surrogateCount = 0;
  114. bool wasHighSurrogate = false;
  115. if (count < str.Length) {
  116. str[count] = '\uffff';
  117. }
  118. for (int i = 0; i < str.Length; i++) {
  119. char c = str[i];
  120. if (c >= '\uD800') {
  121. if (i >= count) {
  122. break;
  123. } else if (c <= '\uDBFF') {
  124. wasHighSurrogate = true;
  125. } else if (wasHighSurrogate && c <= '\uDFFF') {
  126. surrogateCount++;
  127. wasHighSurrogate = false;
  128. }
  129. }
  130. }
  131. return str.Length - surrogateCount;
  132. }
  133. public static string/*!*/ ToAsciiString(this string/*!*/ str) {
  134. return MutableString.AppendUnicodeRepresentation(new StringBuilder(), str, MutableString.Escape.NonAscii, -1, -1).ToString();
  135. }
  136. public static int LastCharacter(this string/*!*/ str) {
  137. return str.Length == 0 ? -1 : str[str.Length - 1];
  138. }
  139. internal static IEnumerable<byte>/*!*/ EnumerateAsBytes(char[]/*!*/ data, int count) {
  140. for (int i = 0; i < count; i++) {
  141. yield return (byte)data[i];
  142. }
  143. }
  144. internal static IEnumerable<byte>/*!*/ EnumerateAsBytes(string/*!*/ data) {
  145. for (int i = 0; i < data.Length; i++) {
  146. yield return (byte)data[i];
  147. }
  148. }
  149. internal static IEnumerable<T>/*!*/ Enumerate<T>(T[]/*!*/ data, int count) {
  150. for (int i = 0; i < count; i++) {
  151. yield return data[i];
  152. }
  153. }
  154. internal const int MinListSize = 4;
  155. internal const int MinBufferSize = 16;
  156. internal static int GetExpandedSize<T>(T[]/*!*/ array, int minLength) {
  157. return Math.Max(minLength, Math.Max(1 + (array.Length << 1), typeof(T) == typeof(object) ? MinListSize : MinBufferSize));
  158. }
  159. internal static void Resize<T>(ref T[]/*!*/ array, int minLength) {
  160. if (array.Length < minLength) {
  161. Array.Resize(ref array, GetExpandedSize(array, minLength));
  162. }
  163. }
  164. internal static void TrimExcess<T>(ref T[] data, int count) {
  165. if (IsSparse(count, data.Length)) {
  166. Array.Resize(ref data, count);
  167. }
  168. }
  169. internal static bool IsSparse(int portionSize, int totalSize) {
  170. Debug.Assert(portionSize <= totalSize);
  171. return (long)portionSize * 10 < (long)totalSize * 9;
  172. }
  173. internal static void ResizeForInsertion<T>(ref T[]/*!*/ array, int itemCount, int index, int count) {
  174. int minLength = itemCount + count;
  175. T[] a;
  176. if (array.Length < minLength) {
  177. a = new T[GetExpandedSize(array, minLength)];
  178. Array.Copy(array, 0, a, 0, index);
  179. } else {
  180. a = array;
  181. }
  182. Array.Copy(array, index, a, index + count, itemCount - index);
  183. array = a;
  184. }
  185. internal static void Fill<T>(T[]/*!*/ array, int index, T item, int repeatCount) {
  186. // TODO: can be optimized for big repeatCount:
  187. for (int i = index; i < index + repeatCount; i++) {
  188. array[i] = item;
  189. }
  190. }
  191. private static void Fill(byte[]/*!*/ src, int srcStart, byte[]/*!*/ dst, int dstStart, int count, int repeatCount) {
  192. // TODO: can be optimized for big repeatCount or big count:
  193. if (count == 1) {
  194. Fill(dst, dstStart, src[srcStart], repeatCount);
  195. } else {
  196. for (int i = 0; i < repeatCount; i++) {
  197. for (int j = 0; j < count; j++) {
  198. dst[dstStart++] = src[srcStart + j];
  199. }
  200. }
  201. }
  202. }
  203. private static int GetByteCount(string/*!*/ str, int start, int count, Encoding/*!*/ encoding, out char[]/*!*/ chars) {
  204. // TODO: we can special case this for some encodings and calculate the byte count w/o copying the content:
  205. chars = new char[count];
  206. str.CopyTo(start, chars, 0, count);
  207. return encoding.GetByteCount(chars, 0, chars.Length);
  208. }
  209. internal static T[]/*!*/ Concatenate<T>(T[]/*!*/ array1, T[]/*!*/ array2) {
  210. return Concatenate(array1, array1.Length, array2, array2.Length);
  211. }
  212. internal static T[]/*!*/ Concatenate<T>(params T[][] arrays) {
  213. int length = 0;
  214. foreach (var array in arrays) {
  215. length += array.Length;
  216. }
  217. T[] result = new T[length];
  218. length = 0;
  219. foreach (var array in arrays) {
  220. Array.Copy(array, 0, result, length, array.Length);
  221. length += array.Length;
  222. }
  223. return result;
  224. }
  225. internal static T[]/*!*/ Concatenate<T>(T[]/*!*/ array1, int itemCount1, T[]/*!*/ array2, int itemCount2) {
  226. T[] result = new T[itemCount1 + itemCount2];
  227. Array.Copy(array1, 0, result, 0, itemCount1);
  228. Array.Copy(array2, 0, result, itemCount1, itemCount2);
  229. return result;
  230. }
  231. internal static int Append<T>(ref T[]/*!*/ array, int itemCount, T item, int repeatCount) {
  232. Resize(ref array, itemCount + repeatCount);
  233. Fill(array, itemCount, item, repeatCount);
  234. return itemCount + repeatCount;
  235. }
  236. internal static int Append(ref char[]/*!*/ array, int itemCount, string/*!*/ other, int start, int count) {
  237. int newCount = itemCount + count;
  238. Resize(ref array, newCount);
  239. other.CopyTo(start, array, itemCount, count);
  240. return newCount;
  241. }
  242. internal static int Append<T>(ref T[]/*!*/ array, int itemCount, T[]/*!*/ other, int start, int count) {
  243. int newCount = itemCount + count;
  244. Resize(ref array, newCount);
  245. Array.Copy(other, start, array, itemCount, count);
  246. return newCount;
  247. }
  248. internal static int Append(ref byte[]/*!*/ array, int itemCount, string/*!*/ other, int start, int count, Encoding/*!*/ encoding) {
  249. char[] appendChars;
  250. int newCount = itemCount + GetByteCount(other, start, count, encoding, out appendChars);
  251. Resize(ref array, newCount);
  252. encoding.GetBytes(appendChars, 0, appendChars.Length, array, itemCount);
  253. return newCount;
  254. }
  255. internal static int Append(ref byte[]/*!*/ array, int itemCount, char[]/*!*/ other, int start, int count, Encoding/*!*/ encoding) {
  256. int newCount = itemCount + encoding.GetByteCount(other, start, count);
  257. Resize(ref array, newCount);
  258. encoding.GetBytes(other, start, count, array, itemCount);
  259. return newCount;
  260. }
  261. internal static int Append(ref byte[]/*!*/ array, int itemCount, char other, int repeatCount, Encoding/*!*/ encoding) {
  262. if (repeatCount == 0) {
  263. return itemCount;
  264. }
  265. char[] chars = new char[] { other };
  266. int charSize = encoding.GetByteCount(chars, 0, 1);
  267. int newCount = itemCount + charSize * repeatCount;
  268. Resize(ref array, newCount);
  269. encoding.GetBytes(chars, 0, 1, array, itemCount);
  270. Fill(array, itemCount, array, itemCount + charSize, charSize, repeatCount - 1);
  271. return newCount;
  272. }
  273. internal static int InsertAt<T>(ref T[]/*!*/ array, int itemCount, int index, T other, int repeatCount) {
  274. ResizeForInsertion(ref array, itemCount, index, repeatCount);
  275. Fill(array, index, other, repeatCount);
  276. return itemCount + repeatCount;
  277. }
  278. internal static int InsertAt(ref char[]/*!*/ array, int itemCount, int index, string/*!*/ other, int start, int count) {
  279. ResizeForInsertion(ref array, itemCount, index, count);
  280. other.CopyTo(start, array, index, count);
  281. return itemCount + count;
  282. }
  283. internal static int InsertAt<T>(ref T[]/*!*/ array, int itemCount, int index, T[]/*!*/ other, int start, int count) {
  284. ResizeForInsertion(ref array, itemCount, index, count);
  285. Array.Copy(other, start, array, index, count);
  286. return itemCount + count;
  287. }
  288. internal static int InsertAt(ref byte[]/*!*/ array, int itemCount, int index, string/*!*/ other, int start, int count, Encoding/*!*/ encoding) {
  289. char[] insertChars;
  290. int insertedCount = GetByteCount(other, start, count, encoding, out insertChars);
  291. ResizeForInsertion(ref array, itemCount, index, insertedCount);
  292. encoding.GetBytes(insertChars, 0, insertChars.Length, array, itemCount);
  293. return itemCount + insertedCount;
  294. }
  295. internal static int InsertAt(ref byte[]/*!*/ array, int itemCount, int index, char[]/*!*/ other, int start, int count, Encoding/*!*/ encoding) {
  296. int insertedCount = encoding.GetByteCount(other, start, count);
  297. ResizeForInsertion(ref array, itemCount, index, insertedCount);
  298. encoding.GetBytes(other, start, count, array, itemCount);
  299. return itemCount + insertedCount;
  300. }
  301. internal static int InsertAt(ref byte[]/*!*/ array, int itemCount, int index, char other, int repeatCount, Encoding/*!*/ encoding) {
  302. if (repeatCount == 0) {
  303. return itemCount;
  304. }
  305. char[] chars = new char[] { other };
  306. int charSize = encoding.GetByteCount(chars, 0, 1);
  307. int insertedCount = charSize * repeatCount;
  308. ResizeForInsertion(ref array, itemCount, index, insertedCount);
  309. // first character:
  310. encoding.GetBytes(chars, 0, 1, array, itemCount);
  311. Fill(array, itemCount, array, itemCount + charSize, charSize, repeatCount - 1);
  312. return itemCount + insertedCount;
  313. }
  314. internal static int Remove<T>(ref T[]/*!*/ array, int itemCount, int start, int count) {
  315. T[] a;
  316. int remaining = itemCount - count;
  317. if (remaining > MinBufferSize && remaining < itemCount / 2) {
  318. a = new T[remaining];
  319. Array.Copy(array, 0, a, 0, start);
  320. } else {
  321. a = array;
  322. }
  323. Array.Copy(array, start + count, a, start, remaining - start);
  324. array = a;
  325. return remaining;
  326. }
  327. internal static T[]/*!*/ GetSlice<T>(this T[]/*!*/ array, int start, int count) {
  328. var copy = new T[count];
  329. Array.Copy(array, start, copy, 0, count);
  330. return copy;
  331. }
  332. internal static T[]/*!*/ GetSlice<T>(this T[]/*!*/ array, int arrayLength, int start, int count) {
  333. count = NormalizeCount(arrayLength, start, count);
  334. var copy = new T[count];
  335. if (count > 0) {
  336. Array.Copy(array, start, copy, 0, count);
  337. }
  338. return copy;
  339. }
  340. internal static string/*!*/ GetSlice(this string/*!*/ str, int start, int count) {
  341. count = NormalizeCount(str.Length, start, count);
  342. return count > 0 ? str.Substring(start, count) : String.Empty;
  343. }
  344. internal static string/*!*/ GetStringSlice(this char[]/*!*/ chars, int arrayLength, int start, int count) {
  345. count = NormalizeCount(arrayLength, start, count);
  346. return count > 0 ? new String(chars, start, count) : String.Empty;
  347. }
  348. internal static int NormalizeCount(int arrayLength, int start, int count) {
  349. if (count > arrayLength - start) {
  350. return start >= arrayLength ? 0 : arrayLength - start;
  351. } else {
  352. return count;
  353. }
  354. }
  355. internal static void NormalizeLastIndexOfIndices(int arrayLength, ref int start, ref int count) {
  356. if (start >= arrayLength) {
  357. count = arrayLength - (start - count + 1);
  358. start = arrayLength - 1;
  359. }
  360. }
  361. internal static int IndexOf(byte[]/*!*/ array, int arrayLength, char value, int start, int count) {
  362. int end = start + NormalizeCount(arrayLength, start, count);
  363. for (int i = start; i < end; i++) {
  364. if (array[i] == value) {
  365. return i;
  366. }
  367. }
  368. return -1;
  369. }
  370. internal static int IndexOf(char[]/*!*/ array, int arrayLength, byte value, int start, int count) {
  371. int end = start + NormalizeCount(arrayLength, start, count);
  372. for (int i = start; i < end; i++) {
  373. if (array[i] == value) {
  374. return i;
  375. }
  376. }
  377. return -1;
  378. }
  379. internal static int IndexOf(string/*!*/ str, byte value, int start, int count) {
  380. int end = start + NormalizeCount(str.Length, start, count);
  381. for (int i = start; i < end; i++) {
  382. if (str[i] == value) {
  383. return i;
  384. }
  385. }
  386. return -1;
  387. }
  388. /// <summary>
  389. /// Implements the same behavior as String.IndexOf on ASCII strings.
  390. /// </summary>
  391. internal static int IndexOf(byte[]/*!*/ array, int arrayLength, string/*!*/ str, int start, int count) {
  392. count = NormalizeCount(arrayLength, start, count);
  393. int finish = start + count - str.Length;
  394. for (int i = start; i <= finish; i++) {
  395. bool match = true;
  396. for (int j = 0; j < str.Length; j++) {
  397. if (str[j] != array[i + j]) {
  398. match = false;
  399. break;
  400. }
  401. }
  402. if (match) {
  403. return i;
  404. }
  405. }
  406. return -1;
  407. }
  408. /// <summary>
  409. /// Implements the same behavior as String.IndexOf on ASCII strings.
  410. /// </summary>
  411. internal static int IndexOf(char[]/*!*/ array, int arrayLength, string/*!*/ str, int start, int count) {
  412. count = NormalizeCount(arrayLength, start, count);
  413. int finish = start + count - str.Length;
  414. for (int i = start; i <= finish; i++) {
  415. bool match = true;
  416. for (int j = 0; j < str.Length; j++) {
  417. if (str[j] != array[i + j]) {
  418. match = false;
  419. break;
  420. }
  421. }
  422. if (match) {
  423. return i;
  424. }
  425. }
  426. return -1;
  427. }
  428. /// <summary>
  429. /// Implements the same behavior as String.IndexOf on ASCII strings.
  430. /// </summary>
  431. internal static int IndexOf(byte[]/*!*/ array, int arrayLength, byte[]/*!*/ bytes, int start, int count) {
  432. count = NormalizeCount(arrayLength, start, count);
  433. int finish = start + count - bytes.Length;
  434. for (int i = start; i <= finish; i++) {
  435. bool match = true;
  436. for (int j = 0; j < bytes.Length; j++) {
  437. if (bytes[j] != array[i + j]) {
  438. match = false;
  439. break;
  440. }
  441. }
  442. if (match) {
  443. return i;
  444. }
  445. }
  446. return -1;
  447. }
  448. /// <summary>
  449. /// Implements the same behavior as String.IndexOf on ASCII strings.
  450. /// </summary>
  451. internal static int IndexOf(char[]/*!*/ array, int arrayLength, byte[]/*!*/ bytes, int start, int count) {
  452. count = NormalizeCount(arrayLength, start, count);
  453. int finish = start + count - bytes.Length;
  454. for (int i = start; i <= finish; i++) {
  455. bool match = true;
  456. for (int j = 0; j < bytes.Length; j++) {
  457. if (bytes[j] != array[i + j]) {
  458. match = false;
  459. break;
  460. }
  461. }
  462. if (match) {
  463. return i;
  464. }
  465. }
  466. return -1;
  467. }
  468. /// <summary>
  469. /// Implements the same behavior as String.IndexOf on ASCII strings.
  470. /// </summary>
  471. internal static int IndexOf(string/*!*/ str, byte[]/*!*/ bytes, int start, int count) {
  472. count = NormalizeCount(str.Length, start, count);
  473. int finish = start + count - bytes.Length;
  474. for (int i = start; i <= finish; i++) {
  475. bool match = true;
  476. for (int j = 0; j < bytes.Length; j++) {
  477. if (bytes[j] != str[i + j]) {
  478. match = false;
  479. break;
  480. }
  481. }
  482. if (match) {
  483. return i;
  484. }
  485. }
  486. return -1;
  487. }
  488. internal static int LastIndexOf(char[]/*!*/ array, int arrayLength, byte value, int start, int count) {
  489. NormalizeLastIndexOfIndices(arrayLength, ref start, ref count);
  490. int end = start - count;
  491. for (int i = start; i > end; i--) {
  492. if (array[i] == value) {
  493. return i;
  494. }
  495. }
  496. return -1;
  497. }
  498. internal static int LastIndexOf(string/*!*/ str, byte value, int start, int count) {
  499. NormalizeLastIndexOfIndices(str.Length, ref start, ref count);
  500. int end = start - count;
  501. for (int i = start; i > end; i--) {
  502. if (str[i] == value) {
  503. return i;
  504. }
  505. }
  506. return -1;
  507. }
  508. /// <summary>
  509. /// Implements the same behavior as String.LastIndexOf on ASCII strings.
  510. /// </summary>
  511. internal static int LastIndexOf(byte[]/*!*/ array, int arrayLength, string/*!*/ value, int start, int count) {
  512. NormalizeLastIndexOfIndices(arrayLength, ref start, ref count);
  513. int finish = start - count + 1;
  514. if (value.Length == 0) {
  515. return start;
  516. }
  517. for (int i = start - value.Length + 1; i >= finish; i--) {
  518. bool match = true;
  519. for (int j = 0; j < value.Length; j++) {
  520. if (value[j] != array[i + j]) {
  521. match = false;
  522. break;
  523. }
  524. }
  525. if (match) {
  526. return i;
  527. }
  528. }
  529. return -1;
  530. }
  531. internal static int LastIndexOf(char[]/*!*/ array, int arrayLength, string/*!*/ value, int start, int count) {
  532. NormalizeLastIndexOfIndices(arrayLength, ref start, ref count);
  533. int finish = start - count + 1;
  534. if (value.Length == 0) {
  535. return start;
  536. }
  537. for (int i = start - value.Length + 1; i >= finish; i--) {
  538. bool match = true;
  539. for (int j = 0; j < value.Length; j++) {
  540. if (value[j] != array[i + j]) {
  541. match = false;
  542. break;
  543. }
  544. }
  545. if (match) {
  546. return i;
  547. }
  548. }
  549. return -1;
  550. }
  551. /// <summary>
  552. /// Implements the same behavior as String.LastIndexOf on ASCII strings.
  553. /// </summary>
  554. internal static int LastIndexOf(byte[]/*!*/ array, int arrayLength, byte[]/*!*/ value, int start, int count) {
  555. NormalizeLastIndexOfIndices(arrayLength, ref start, ref count);
  556. int finish = start - count + 1;
  557. if (value.Length == 0) {
  558. return start;
  559. }
  560. for (int i = start - value.Length + 1; i >= finish; i--) {
  561. bool match = true;
  562. for (int j = 0; j < value.Length; j++) {
  563. if (value[j] != array[i + j]) {
  564. match = false;
  565. break;
  566. }
  567. }
  568. if (match) {
  569. return i;
  570. }
  571. }
  572. return -1;
  573. }
  574. /// <summary>
  575. /// Implements the same behavior as String.LastIndexOf on ASCII strings.
  576. /// </summary>
  577. internal static int LastIndexOf(char[]/*!*/ array, int arrayLength, byte[]/*!*/ value, int start, int count) {
  578. NormalizeLastIndexOfIndices(arrayLength, ref start, ref count);
  579. int finish = start - count + 1;
  580. if (value.Length == 0) {
  581. return start;
  582. }
  583. for (int i = start - value.Length + 1; i >= finish; i--) {
  584. bool match = true;
  585. for (int j = 0; j < value.Length; j++) {
  586. if (value[j] != array[i + j]) {
  587. match = false;
  588. break;
  589. }
  590. }
  591. if (match) {
  592. return i;
  593. }
  594. }
  595. return -1;
  596. }
  597. /// <summary>
  598. /// Implements the same behavior as String.LastIndexOf on ASCII strings.
  599. /// </summary>
  600. internal static int LastIndexOf(string/*!*/ str, byte[]/*!*/ value, int start, int count) {
  601. NormalizeLastIndexOfIndices(str.Length, ref start, ref count);
  602. int finish = start - count + 1;
  603. if (value.Length == 0) {
  604. return start;
  605. }
  606. for (int i = start - value.Length + 1; i >= finish; i--) {
  607. bool match = true;
  608. for (int j = 0; j < value.Length; j++) {
  609. if (value[j] != str[i + j]) {
  610. match = false;
  611. break;
  612. }
  613. }
  614. if (match) {
  615. return i;
  616. }
  617. }
  618. return -1;
  619. }
  620. internal static int ValueCompareTo(this byte[]/*!*/ array, int itemCount, byte[]/*!*/ other) {
  621. return ValueCompareTo(array, itemCount, other, other.Length);
  622. }
  623. internal static int ValueCompareTo(this byte[]/*!*/ array, int itemCount, byte[]/*!*/ other, int otherCount) {
  624. int min = itemCount;
  625. int defaultResult;
  626. if (min < otherCount) {
  627. defaultResult = -1;
  628. } else if (min > otherCount) {
  629. min = otherCount;
  630. defaultResult = +1;
  631. } else {
  632. defaultResult = 0;
  633. }
  634. for (int i = 0; i < min; i++) {
  635. if (array[i] != other[i]) {
  636. return (int)array[i] - other[i];
  637. }
  638. }
  639. return defaultResult;
  640. }
  641. internal static int ValueCompareTo(this char[]/*!*/ array, int itemCount, char[]/*!*/ other, int otherCount) {
  642. int min = itemCount;
  643. int defaultResult;
  644. if (min < otherCount) {
  645. defaultResult = -1;
  646. } else if (min > otherCount) {
  647. min = otherCount;
  648. defaultResult = +1;
  649. } else {
  650. defaultResult = 0;
  651. }
  652. for (int i = 0; i < min; i++) {
  653. if (array[i] != other[i]) {
  654. return (int)array[i] - other[i];
  655. }
  656. }
  657. return defaultResult;
  658. }
  659. internal static int ValueCompareTo(this char[]/*!*/ array, int itemCount, string/*!*/ other) {
  660. int min = itemCount, defaultResult;
  661. if (min < other.Length) {
  662. defaultResult = -1;
  663. } else if (min > other.Length) {
  664. min = other.Length;
  665. defaultResult = +1;
  666. } else {
  667. defaultResult = 0;
  668. }
  669. for (int i = 0; i < min; i++) {
  670. if (array[i] != other[i]) {
  671. return (int)array[i] - other[i];
  672. }
  673. }
  674. return defaultResult;
  675. }
  676. internal static int ValueCompareTo(this byte[]/*!*/ array, int itemCount, string/*!*/ other) {
  677. int min = itemCount;
  678. int defaultResult;
  679. if (min < other.Length) {
  680. defaultResult = -1;
  681. } else if (min > other.Length) {
  682. min = other.Length;
  683. defaultResult = +1;
  684. } else {
  685. defaultResult = 0;
  686. }
  687. for (int i = 0; i < min; i++) {
  688. if (array[i] != other[i]) {
  689. return (int)array[i] - other[i];
  690. }
  691. }
  692. return defaultResult;
  693. }
  694. internal static int ValueCompareTo(this string/*!*/ str, string/*!*/ other) {
  695. int min = str.Length, defaultResult;
  696. if (min < other.Length) {
  697. defaultResult = -1;
  698. } else if (min > other.Length) {
  699. min = other.Length;
  700. defaultResult = +1;
  701. } else {
  702. defaultResult = 0;
  703. }
  704. for (int i = 0; i < min; i++) {
  705. if (str[i] != other[i]) {
  706. return (int)str[i] - other[i];
  707. }
  708. }
  709. return defaultResult;
  710. }
  711. internal static bool SubstringEquals(string/*!*/ name, int start, int count, string/*!*/ other) {
  712. if (count != other.Length) {
  713. return false;
  714. }
  715. for (int i = 0; i < count; i++) {
  716. if (name[start + i] != other[i]) {
  717. return false;
  718. }
  719. }
  720. return true;
  721. }
  722. internal static bool ValueEquals<T>(T[] array, int arrayCount, T[] other, int otherCount) {
  723. Debug.Assert(arrayCount <= array.Length);
  724. Debug.Assert(otherCount <= other.Length);
  725. if (arrayCount != otherCount) {
  726. return false;
  727. }
  728. for (int i = 0; i < arrayCount; i++) {
  729. if (!Object.Equals(array[i], other[i])) {
  730. return false;
  731. }
  732. }
  733. return true;
  734. }
  735. public static TOutput[]/*!*/ ConvertAll<TInput, TOutput>(this TInput[]/*!*/ array, Func<TInput, TOutput>/*!*/ converter) {
  736. var result = new TOutput[array.Length];
  737. for (int i = 0; i < array.Length; i++) {
  738. result[i] = converter(array[i]);
  739. }
  740. return result;
  741. }
  742. internal static void AddRange(IList/*!*/ list, IList/*!*/ range) {
  743. Assert.NotNull(list, range);
  744. List<object> objList;
  745. IEnumerable<object> enumerableRange;
  746. RubyArray array;
  747. if ((array = list as RubyArray) != null) {
  748. array.AddRange(range);
  749. } else if ((objList = list as List<object>) != null && (enumerableRange = range as IEnumerable<object>) != null) {
  750. objList.AddRange(enumerableRange);
  751. } else {
  752. foreach (var item in range) {
  753. list.Add(item);
  754. }
  755. }
  756. }
  757. [Conditional("DEBUG")]
  758. public static void Log(string/*!*/ message, string/*!*/ category) {
  759. #if WIN8 || ANDROID || WP75
  760. Debug.WriteLine(category + ": " + message);
  761. #elif !SILVERLIGHT
  762. Debug.WriteLine((object)message, category);
  763. #endif
  764. }
  765. public static long DateTimeTicksFromStopwatch(long elapsedStopwatchTicks) {
  766. #if !SILVERLIGHT && !WP75
  767. if (Stopwatch.IsHighResolution) {
  768. return (long)(((double)elapsedStopwatchTicks) * 10000000.0 / (double)Stopwatch.Frequency);
  769. }
  770. #endif
  771. return elapsedStopwatchTicks;
  772. }
  773. public static char ToLowerHexDigit(this int digit) {
  774. return (char)((digit < 10) ? '0' + digit : 'a' + digit - 10);
  775. }
  776. public static char ToUpperHexDigit(this int digit) {
  777. return (char)((digit < 10) ? '0' + digit : 'A' + digit - 10);
  778. }
  779. public static char ToUpperInvariant(this char c) {
  780. return Char.ToUpperInvariant(c);
  781. }
  782. public static char ToLowerInvariant(this char c) {
  783. return Char.ToLowerInvariant(c);
  784. }
  785. #if SILVERLIGHT
  786. public static string/*!*/ ToUpperInvariant(this string/*!*/ str) {
  787. return str.ToUpper(CultureInfo.InvariantCulture);
  788. }
  789. public static string/*!*/ ToLowerInvariant(this string/*!*/ str) {
  790. return str.ToLower(CultureInfo.InvariantCulture);
  791. }
  792. #endif
  793. internal static IEnumerable<Expression/*!*/>/*!*/ ToExpressions(this IEnumerable<DynamicMetaObject>/*!*/ metaObjects) {
  794. foreach (var metaObject in metaObjects) {
  795. yield return metaObject != null ? metaObject.Expression : null;
  796. }
  797. }
  798. internal static Action<RubyModule> CloneInvocationChain(Action<RubyModule> chain) {
  799. if (chain == null) {
  800. return null;
  801. }
  802. Action<RubyModule> result = _ => { };
  803. foreach (var d in chain.GetInvocationList()) {
  804. result += (Action<RubyModule>)d;
  805. }
  806. return result;
  807. }
  808. internal static void CopyTupleFields(MutableTuple/*!*/ src, MutableTuple/*!*/ dst) {
  809. Debug.Assert(src.Capacity == dst.Capacity);
  810. for (int i = 0; i < src.Capacity; i++) {
  811. dst.SetValue(i, src.GetValue(i));
  812. }
  813. }
  814. #if FEATURE_ENCODING
  815. private sealed class CheckDecoderFallback : DecoderFallback {
  816. public bool HasInvalidCharacters { get; private set; }
  817. public CheckDecoderFallback() {
  818. }
  819. public override int MaxCharCount {
  820. get { return 1; }
  821. }
  822. public override DecoderFallbackBuffer CreateFallbackBuffer() {
  823. return new Buffer(this);
  824. }
  825. internal sealed class Buffer : DecoderFallbackBuffer {
  826. private readonly CheckDecoderFallback _fallback;
  827. public Buffer(CheckDecoderFallback/*!*/ fallback) {
  828. _fallback = fallback;
  829. }
  830. public override bool Fallback(byte[]/*!*/ bytesUnknown, int index) {
  831. _fallback.HasInvalidCharacters = true;
  832. return true;
  833. }
  834. public override char GetNextChar() {
  835. return '\0';
  836. }
  837. public override bool MovePrevious() {
  838. return false;
  839. }
  840. public override int Remaining {
  841. get { return 0; }
  842. }
  843. }
  844. }
  845. private sealed class CheckEncoderFallback : EncoderFallback {
  846. public bool HasInvalidCharacters { get; private set; }
  847. public CheckEncoderFallback() {
  848. }
  849. public override int MaxCharCount {
  850. get { return 1; }
  851. }
  852. public override EncoderFallbackBuffer CreateFallbackBuffer() {
  853. return new Buffer(this);
  854. }
  855. internal sealed class Buffer : EncoderFallbackBuffer {
  856. private readonly CheckEncoderFallback _fallback;
  857. public Buffer(CheckEncoderFallback/*!*/ fallback) {
  858. _fallback = fallback;
  859. }
  860. public override bool Fallback(char charUnknown, int index) {
  861. _fallback.HasInvalidCharacters = true;
  862. return true;
  863. }
  864. public override bool Fallback(char charUnknownHigh, char charUnknownLow, int index) {
  865. _fallback.HasInvalidCharacters = true;
  866. return true;
  867. }
  868. public override char GetNextChar() {
  869. return '\0';
  870. }
  871. public override bool MovePrevious() {
  872. return false;
  873. }
  874. public override int Remaining {
  875. get { return 0; }
  876. }
  877. }
  878. }
  879. internal static bool ContainsInvalidCharacters(byte[]/*!*/ bytes, int start, int count, Encoding/*!*/ encoding) {
  880. var decoder = encoding.GetDecoder();
  881. var fallback = new CheckDecoderFallback();
  882. decoder.Fallback = fallback;
  883. decoder.GetCharCount(bytes, start, count, true);
  884. return fallback.HasInvalidCharacters;
  885. }
  886. internal static bool ContainsInvalidCharacters(char[]/*!*/ chars, int start, int count, Encoding/*!*/ encoding) {
  887. var encoder = encoding.GetEncoder();
  888. var fallback = new CheckEncoderFallback();
  889. encoder.Fallback = fallback;
  890. encoder.GetByteCount(chars, start, count, true);
  891. return fallback.HasInvalidCharacters;
  892. }
  893. #else
  894. internal static bool ContainsInvalidCharacters(byte[]/*!*/ bytes, int start, int count, Encoding/*!*/ encoding) {
  895. try {
  896. encoding.GetCharCount(bytes, start, count);
  897. return true;
  898. } catch (DecoderFallbackException){
  899. return false;
  900. }
  901. }
  902. internal static bool ContainsInvalidCharacters(char[]/*!*/ chars, int start, int count, Encoding/*!*/ encoding) {
  903. try {
  904. encoding.GetByteCount(chars, start, count);
  905. return true;
  906. } catch (EncoderFallbackException) {
  907. return false;
  908. }
  909. }
  910. #endif
  911. }
  912. }
  913. #if SILVERLIGHT
  914. namespace System.Diagnostics {
  915. internal struct Stopwatch {
  916. public void Start() {
  917. }
  918. public void Stop() {
  919. }
  920. public static long GetTimestamp() {
  921. return 0;
  922. }
  923. }
  924. }
  925. #endif