Memoize.cs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the Apache 2.0 License.
  3. // See the LICENSE file in the project root for more information.
  4. using System;
  5. using System.Collections;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. using Xunit;
  9. namespace Tests
  10. {
  11. public class Memoize : Tests
  12. {
  13. [Fact]
  14. public void Memoize_Arguments()
  15. {
  16. AssertThrows<ArgumentNullException>(() => EnumerableEx.Memoize<int>(null));
  17. }
  18. [Fact]
  19. public void MemoizeLimited_Arguments()
  20. {
  21. AssertThrows<ArgumentNullException>(() => EnumerableEx.Memoize<int>(null, 2));
  22. AssertThrows<ArgumentOutOfRangeException>(() => EnumerableEx.Memoize<int>(new[] { 1 }, 0));
  23. AssertThrows<ArgumentOutOfRangeException>(() => EnumerableEx.Memoize<int>(new[] { 1 }, -1));
  24. }
  25. [Fact]
  26. public void Memoize0()
  27. {
  28. var n = 0;
  29. var rng = Tick(i => n += i).Memoize();
  30. var e1 = rng.GetEnumerator();
  31. var e2 = rng.GetEnumerator();
  32. HasNext(e1, 0);
  33. Assert.Equal(0, n);
  34. HasNext(e1, 1);
  35. Assert.Equal(1, n);
  36. HasNext(e1, 2);
  37. Assert.Equal(3, n);
  38. HasNext(e2, 0);
  39. Assert.Equal(3, n);
  40. HasNext(e1, 3);
  41. Assert.Equal(6, n);
  42. HasNext(e2, 1);
  43. Assert.Equal(6, n);
  44. HasNext(e2, 2);
  45. Assert.Equal(6, n);
  46. HasNext(e2, 3);
  47. Assert.Equal(6, n);
  48. HasNext(e2, 4);
  49. Assert.Equal(10, n);
  50. HasNext(e1, 4);
  51. Assert.Equal(10, n);
  52. }
  53. [Fact]
  54. public void Publish11()
  55. {
  56. var rng = Enumerable.Range(0, 5).Publish();
  57. var e1 = rng.GetEnumerator();
  58. var e2 = rng.GetEnumerator();
  59. HasNext(e1, 0);
  60. HasNext(e1, 1);
  61. HasNext(e1, 2);
  62. e1.Dispose();
  63. HasNext(e2, 0);
  64. HasNext(e2, 1);
  65. e2.Dispose();
  66. var e3 = rng.GetEnumerator();
  67. HasNext(e3, 3);
  68. HasNext(e3, 4);
  69. NoNext(e3);
  70. }
  71. [Fact]
  72. public void Memoize1()
  73. {
  74. var rng = Enumerable.Range(0, 5).Memoize();
  75. var e1 = rng.GetEnumerator();
  76. HasNext(e1, 0);
  77. HasNext(e1, 1);
  78. HasNext(e1, 2);
  79. HasNext(e1, 3);
  80. HasNext(e1, 4);
  81. NoNext(e1);
  82. }
  83. [Fact]
  84. public void Memoize2()
  85. {
  86. var rng = Enumerable.Range(0, 5).Memoize();
  87. var e1 = rng.GetEnumerator();
  88. HasNext(e1, 0);
  89. HasNext(e1, 1);
  90. HasNext(e1, 2);
  91. HasNext(e1, 3);
  92. HasNext(e1, 4);
  93. NoNext(e1);
  94. var e2 = rng.GetEnumerator();
  95. HasNext(e2, 0);
  96. HasNext(e2, 1);
  97. HasNext(e2, 2);
  98. HasNext(e2, 3);
  99. HasNext(e2, 4);
  100. NoNext(e2);
  101. }
  102. [Fact]
  103. public void Memoize3()
  104. {
  105. var rng = Enumerable.Range(0, 5).Memoize();
  106. var e1 = rng.GetEnumerator();
  107. HasNext(e1, 0);
  108. HasNext(e1, 1);
  109. HasNext(e1, 2);
  110. var e2 = rng.GetEnumerator();
  111. HasNext(e1, 3);
  112. HasNext(e2, 0);
  113. HasNext(e2, 1);
  114. HasNext(e1, 4);
  115. HasNext(e2, 2);
  116. NoNext(e1);
  117. HasNext(e2, 3);
  118. HasNext(e2, 4);
  119. NoNext(e2);
  120. }
  121. [Fact]
  122. public void Memoize4()
  123. {
  124. var rng = Enumerable.Range(0, 5).Memoize(2);
  125. var e1 = rng.GetEnumerator();
  126. HasNext(e1, 0);
  127. HasNext(e1, 1);
  128. HasNext(e1, 2);
  129. var e2 = rng.GetEnumerator();
  130. HasNext(e2, 0);
  131. HasNext(e2, 1);
  132. HasNext(e2, 2);
  133. var e3 = rng.GetEnumerator();
  134. AssertThrows<InvalidOperationException>(() => e3.MoveNext());
  135. }
  136. [Fact]
  137. public void Memoize6()
  138. {
  139. var ex = new MyException();
  140. var rng = Enumerable.Range(0, 2).Concat(EnumerableEx.Throw<int>(ex)).Memoize();
  141. var e1 = rng.GetEnumerator();
  142. var e2 = rng.GetEnumerator();
  143. HasNext(e1, 0);
  144. HasNext(e1, 1);
  145. AssertThrows<MyException>(() => e1.MoveNext());
  146. HasNext(e2, 0);
  147. HasNext(e2, 1);
  148. AssertThrows<MyException>(() => e2.MoveNext());
  149. }
  150. [Fact]
  151. public void Memoize7()
  152. {
  153. var rng = Enumerable.Range(0, 5).Memoize();
  154. var e1 = rng.GetEnumerator();
  155. HasNext(e1, 0);
  156. HasNext(e1, 1);
  157. HasNext(e1, 2);
  158. e1.Dispose();
  159. var e2 = rng.GetEnumerator();
  160. HasNext(e2, 0);
  161. HasNext(e2, 1);
  162. e2.Dispose();
  163. var e3 = rng.GetEnumerator();
  164. HasNext(e3, 0);
  165. HasNext(e3, 1);
  166. HasNext(e3, 2);
  167. HasNext(e3, 3);
  168. HasNext(e3, 4);
  169. NoNext(e3);
  170. }
  171. [Fact]
  172. public void Memoize8()
  173. {
  174. var rng = Enumerable.Range(0, 5).Memoize();
  175. var e1 = rng.GetEnumerator();
  176. HasNext(e1, 0);
  177. HasNext(e1, 1);
  178. HasNext(e1, 2);
  179. rng.Dispose();
  180. AssertThrows<ObjectDisposedException>(() => e1.MoveNext());
  181. AssertThrows<ObjectDisposedException>(() => rng.GetEnumerator());
  182. AssertThrows<ObjectDisposedException>(() => ((IEnumerable)rng).GetEnumerator());
  183. }
  184. [Fact]
  185. public void Memoize9()
  186. {
  187. var rng = Enumerable.Range(0, 5).Memoize();
  188. var e1 = ((IEnumerable)rng).GetEnumerator();
  189. Assert.True(e1.MoveNext());
  190. Assert.Equal(0, (int)e1.Current);
  191. }
  192. [Fact]
  193. public void Memoize10()
  194. {
  195. var rnd = Rand().Take(1000).Memoize();
  196. Assert.True(rnd.Zip(rnd, (l, r) => l == r).All(x => x));
  197. }
  198. private static IEnumerable<int> Tick(Action<int> t)
  199. {
  200. var i = 0;
  201. while (true)
  202. {
  203. t(i);
  204. yield return i++;
  205. }
  206. }
  207. [Fact]
  208. public void MemoizeLambda_Arguments()
  209. {
  210. AssertThrows<ArgumentNullException>(() => EnumerableEx.Memoize<int, int>(null, xs => xs));
  211. AssertThrows<ArgumentNullException>(() => EnumerableEx.Memoize<int, int>(new[] { 1 }, null));
  212. }
  213. [Fact]
  214. public void MemoizeLambda()
  215. {
  216. var n = 0;
  217. var res = Enumerable.Range(0, 10).Do(_ => n++).Memoize(xs => xs.Zip(xs, (l, r) => l + r).Take(4)).ToList();
  218. Assert.True(res.SequenceEqual(Enumerable.Range(0, 4).Select(x => x * 2)));
  219. Assert.Equal(4, n);
  220. }
  221. [Fact]
  222. public void MemoizeLimitedLambda_Arguments()
  223. {
  224. AssertThrows<ArgumentNullException>(() => EnumerableEx.Memoize<int, int>(null, 2, xs => xs));
  225. AssertThrows<ArgumentNullException>(() => EnumerableEx.Memoize<int, int>(new[] { 1 }, 2, null));
  226. AssertThrows<ArgumentOutOfRangeException>(() => EnumerableEx.Memoize<int, int>(new[] { 1 }, 0, xs => xs));
  227. AssertThrows<ArgumentOutOfRangeException>(() => EnumerableEx.Memoize<int, int>(new[] { 1 }, -1, xs => xs));
  228. }
  229. [Fact]
  230. public void MemoizeLimitedLambda()
  231. {
  232. var n = 0;
  233. var res = Enumerable.Range(0, 10).Do(_ => n++).Memoize(2, xs => xs.Zip(xs, (l, r) => l + r).Take(4)).ToList();
  234. Assert.True(res.SequenceEqual(Enumerable.Range(0, 4).Select(x => x * 2)));
  235. Assert.Equal(4, n);
  236. }
  237. private static readonly Random s_rand = new Random();
  238. private static IEnumerable<int> Rand()
  239. {
  240. while (true)
  241. yield return s_rand.Next();
  242. }
  243. private sealed class MyException : Exception
  244. {
  245. }
  246. }
  247. }