hamster 1.0.0 → 1.0.1.pre.rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (509) hide show
  1. checksums.yaml +4 -4
  2. data/lib/hamster.rb +2 -3
  3. data/lib/hamster/core_ext.rb +1 -0
  4. data/lib/hamster/core_ext/enumerable.rb +17 -17
  5. data/lib/hamster/core_ext/enumerator.rb +16 -0
  6. data/lib/hamster/core_ext/io.rb +17 -15
  7. data/lib/hamster/enumerable.rb +107 -123
  8. data/lib/hamster/experimental/mutable_queue.rb +6 -2
  9. data/lib/hamster/experimental/mutable_set.rb +3 -1
  10. data/lib/hamster/experimental/mutable_stack.rb +30 -0
  11. data/lib/hamster/hash.rb +95 -713
  12. data/lib/hamster/immutable.rb +0 -4
  13. data/lib/hamster/list.rb +242 -1062
  14. data/lib/hamster/mutable_hash.rb +3 -1
  15. data/lib/hamster/queue.rb +87 -0
  16. data/lib/hamster/read_copy_update.rb +1 -2
  17. data/lib/hamster/set.rb +73 -478
  18. data/lib/hamster/sorter.rb +25 -0
  19. data/lib/hamster/stack.rb +75 -0
  20. data/lib/hamster/trie.rb +48 -199
  21. data/lib/hamster/tuple.rb +39 -0
  22. data/lib/hamster/undefined.rb +3 -1
  23. data/lib/hamster/vector.rb +72 -1326
  24. data/lib/hamster/version.rb +1 -1
  25. data/spec/hamster/core_ext/array_spec.rb +20 -0
  26. data/spec/{lib/hamster → hamster}/core_ext/enumerable_spec.rb +0 -5
  27. data/spec/hamster/core_ext/enumerator_spec.rb +19 -0
  28. data/spec/{lib/hamster → hamster}/core_ext/io_spec.rb +0 -0
  29. data/spec/hamster/experimental/mutable_set/add_qm_spec.rb +47 -0
  30. data/spec/hamster/experimental/mutable_set/add_spec.rb +51 -0
  31. data/spec/hamster/experimental/mutable_set/delete_qm_spec.rb +47 -0
  32. data/spec/hamster/experimental/mutable_set/delete_spec.rb +47 -0
  33. data/spec/hamster/experimental/mutable_stack/pop_spec.rb +41 -0
  34. data/spec/hamster/experimental/mutable_stack/push_spec.rb +41 -0
  35. data/spec/hamster/hash/all_spec.rb +59 -0
  36. data/spec/hamster/hash/any_spec.rb +67 -0
  37. data/spec/hamster/hash/clear_spec.rb +36 -0
  38. data/spec/hamster/hash/construction_spec.rb +35 -0
  39. data/spec/{lib/hamster → hamster}/hash/copying_spec.rb +12 -3
  40. data/spec/hamster/hash/delete_spec.rb +47 -0
  41. data/spec/hamster/hash/each_spec.rb +41 -0
  42. data/spec/hamster/hash/empty_spec.rb +27 -0
  43. data/spec/hamster/hash/eql_spec.rb +62 -0
  44. data/spec/hamster/hash/except_spec.rb +31 -0
  45. data/spec/hamster/hash/fetch_spec.rb +95 -0
  46. data/spec/hamster/hash/filter_spec.rb +63 -0
  47. data/spec/hamster/hash/find_spec.rb +58 -0
  48. data/spec/hamster/hash/get_spec.rb +55 -0
  49. data/spec/hamster/hash/has_key_spec.rb +35 -0
  50. data/spec/hamster/hash/hash_spec.rb +52 -0
  51. data/spec/{lib/hamster → hamster}/hash/immutable_spec.rb +3 -0
  52. data/spec/hamster/hash/inspect_spec.rb +32 -0
  53. data/spec/hamster/hash/keys_spec.rb +21 -0
  54. data/spec/hamster/hash/map_spec.rb +64 -0
  55. data/spec/{lib/hamster → hamster}/hash/marshal_spec.rb +3 -3
  56. data/spec/hamster/hash/merge_spec.rb +36 -0
  57. data/spec/{lib/hamster → hamster}/hash/none_spec.rb +14 -12
  58. data/spec/hamster/hash/put_spec.rb +65 -0
  59. data/spec/hamster/hash/reduce_spec.rb +60 -0
  60. data/spec/hamster/hash/remove_spec.rb +63 -0
  61. data/spec/{lib/hamster → hamster}/hash/size_spec.rb +2 -2
  62. data/spec/hamster/hash/slice_spec.rb +26 -0
  63. data/spec/hamster/hash/uniq_spec.rb +23 -0
  64. data/spec/hamster/hash/values_spec.rb +34 -0
  65. data/spec/{lib/hamster → hamster}/immutable/copying_spec.rb +8 -1
  66. data/spec/{lib/hamster → hamster}/immutable/immutable_spec.rb +14 -1
  67. data/spec/{lib/hamster → hamster}/immutable/memoize_spec.rb +3 -2
  68. data/spec/{lib/hamster → hamster}/immutable/new_spec.rb +0 -0
  69. data/spec/{lib/hamster → hamster}/immutable/transform_spec.rb +0 -0
  70. data/spec/{lib/hamster → hamster}/immutable/transform_unless_spec.rb +0 -0
  71. data/spec/hamster/list/add_spec.rb +16 -0
  72. data/spec/hamster/list/all_spec.rb +111 -0
  73. data/spec/hamster/list/any_spec.rb +79 -0
  74. data/spec/{lib/hamster → hamster}/list/append_spec.rb +22 -11
  75. data/spec/hamster/list/at_spec.rb +49 -0
  76. data/spec/hamster/list/break_spec.rb +85 -0
  77. data/spec/{lib/hamster → hamster}/list/cadr_spec.rb +17 -6
  78. data/spec/{lib/hamster → hamster}/list/chunk_spec.rb +17 -6
  79. data/spec/{lib/hamster → hamster}/list/clear_spec.rb +16 -5
  80. data/spec/hamster/list/combinations_spec.rb +51 -0
  81. data/spec/{lib/hamster → hamster}/list/compact_spec.rb +17 -6
  82. data/spec/hamster/list/cons_spec.rb +41 -0
  83. data/spec/hamster/list/construction_spec.rb +166 -0
  84. data/spec/{lib/hamster → hamster}/list/copying_spec.rb +16 -4
  85. data/spec/hamster/list/count_spec.rb +66 -0
  86. data/spec/hamster/list/cycle_spec.rb +45 -0
  87. data/spec/{lib/hamster → hamster}/list/drop_spec.rb +17 -6
  88. data/spec/hamster/list/drop_while_spec.rb +59 -0
  89. data/spec/hamster/list/each_slice_spec.rb +80 -0
  90. data/spec/hamster/list/each_spec.rb +72 -0
  91. data/spec/hamster/list/each_with_index_spec.rb +42 -0
  92. data/spec/hamster/list/elem_index_spec.rb +58 -0
  93. data/spec/hamster/list/elem_indices_spec.rb +45 -0
  94. data/spec/hamster/list/empty_spec.rb +47 -0
  95. data/spec/hamster/list/eql_spec.rb +78 -0
  96. data/spec/hamster/list/filter_spec.rb +70 -0
  97. data/spec/{lib/hamster → hamster}/list/find_all_spec.rb +2 -3
  98. data/spec/{lib/hamster → hamster}/list/find_index_spec.rb +27 -5
  99. data/spec/hamster/list/find_indices_spec.rb +45 -0
  100. data/spec/{lib/hamster → hamster}/list/find_spec.rb +33 -11
  101. data/spec/{lib/hamster → hamster}/list/flat_map_spec.rb +0 -0
  102. data/spec/{lib/hamster → hamster}/list/flatten_spec.rb +17 -6
  103. data/spec/{lib/hamster → hamster}/list/grep_spec.rb +33 -10
  104. data/spec/{lib/hamster → hamster}/list/group_by_spec.rb +44 -9
  105. data/spec/{lib/hamster → hamster}/list/hash_spec.rb +12 -4
  106. data/spec/{lib/hamster → hamster}/list/head_spec.rb +18 -3
  107. data/spec/{lib/hamster → hamster}/list/include_spec.rb +27 -6
  108. data/spec/{lib/hamster → hamster}/list/init_spec.rb +17 -6
  109. data/spec/hamster/list/inits_spec.rb +42 -0
  110. data/spec/hamster/list/inspect_spec.rb +43 -0
  111. data/spec/{lib/hamster → hamster}/list/intersperse_spec.rb +17 -6
  112. data/spec/hamster/list/join_spec.rb +81 -0
  113. data/spec/hamster/list/last_spec.rb +44 -0
  114. data/spec/{lib/hamster → hamster}/list/map_spec.rb +35 -12
  115. data/spec/hamster/list/maximum_spec.rb +77 -0
  116. data/spec/{lib/hamster → hamster}/list/merge_by_spec.rb +32 -5
  117. data/spec/{lib/hamster → hamster}/list/merge_spec.rb +20 -1
  118. data/spec/hamster/list/minimum_spec.rb +77 -0
  119. data/spec/{lib/hamster → hamster}/list/none_spec.rb +39 -12
  120. data/spec/{lib/hamster → hamster}/list/one_spec.rb +38 -13
  121. data/spec/hamster/list/partition_spec.rb +75 -0
  122. data/spec/{lib/hamster → hamster}/list/pop_spec.rb +1 -1
  123. data/spec/hamster/list/product_spec.rb +44 -0
  124. data/spec/hamster/list/reduce_spec.rb +73 -0
  125. data/spec/{lib/hamster/list/reject_spec.rb → hamster/list/remove_spec.rb} +35 -11
  126. data/spec/{lib/hamster → hamster}/list/reverse_spec.rb +25 -8
  127. data/spec/{lib/hamster → hamster}/list/select_spec.rb +2 -3
  128. data/spec/{lib/hamster → hamster}/list/size_spec.rb +26 -5
  129. data/spec/hamster/list/slice_spec.rb +50 -0
  130. data/spec/{lib/hamster → hamster}/list/sorting_spec.rb +34 -11
  131. data/spec/hamster/list/span_spec.rb +86 -0
  132. data/spec/{lib/hamster → hamster}/list/split_at_spec.rb +23 -14
  133. data/spec/hamster/list/sum_spec.rb +44 -0
  134. data/spec/hamster/list/tail_spec.rb +48 -0
  135. data/spec/hamster/list/tails_spec.rb +42 -0
  136. data/spec/{lib/hamster → hamster}/list/take_spec.rb +17 -6
  137. data/spec/{lib/hamster → hamster}/list/take_while_spec.rb +18 -11
  138. data/spec/hamster/list/to_a_spec.rb +54 -0
  139. data/spec/{lib/hamster → hamster}/list/to_ary_spec.rb +4 -1
  140. data/spec/{lib/hamster → hamster}/list/to_list_spec.rb +16 -4
  141. data/spec/hamster/list/to_set_spec.rb +33 -0
  142. data/spec/{lib/hamster → hamster}/list/union_spec.rb +23 -6
  143. data/spec/hamster/list/uniq_spec.rb +45 -0
  144. data/spec/{lib/hamster → hamster}/list/zip_spec.rb +9 -2
  145. data/spec/hamster/queue/clear_spec.rb +36 -0
  146. data/spec/hamster/queue/construction_spec.rb +43 -0
  147. data/spec/hamster/queue/dequeue_spec.rb +40 -0
  148. data/spec/hamster/queue/empty_spec.rb +47 -0
  149. data/spec/{lib/hamster/deque → hamster/queue}/enqueue_spec.rb +21 -8
  150. data/spec/hamster/queue/head_spec.rb +35 -0
  151. data/spec/hamster/queue/inspect_spec.rb +31 -0
  152. data/spec/{lib/hamster/deque → hamster/queue}/size_spec.rb +20 -5
  153. data/spec/hamster/queue/to_a_spec.rb +42 -0
  154. data/spec/{lib/hamster/deque → hamster/queue}/to_ary_spec.rb +6 -6
  155. data/spec/hamster/queue/to_list_spec.rb +44 -0
  156. data/spec/hamster/set/add_spec.rb +51 -0
  157. data/spec/hamster/set/all_spec.rb +67 -0
  158. data/spec/hamster/set/any_spec.rb +67 -0
  159. data/spec/hamster/set/clear_spec.rb +36 -0
  160. data/spec/{lib/hamster → hamster}/set/compact_spec.rb +16 -5
  161. data/spec/{lib/hamster → hamster}/set/construction_spec.rb +17 -5
  162. data/spec/{lib/hamster → hamster}/set/copying_spec.rb +12 -3
  163. data/spec/{lib/hamster → hamster}/set/count_spec.rb +28 -11
  164. data/spec/hamster/set/delete_spec.rb +47 -0
  165. data/spec/{lib/hamster/sorted_set → hamster/set}/difference_spec.rb +21 -7
  166. data/spec/{lib/hamster/set/reverse_each_spec.rb → hamster/set/each_spec.rb} +7 -8
  167. data/spec/hamster/set/empty_spec.rb +35 -0
  168. data/spec/{lib/hamster → hamster}/set/eqeq_spec.rb +0 -0
  169. data/spec/{lib/hamster → hamster}/set/eql_spec.rb +1 -7
  170. data/spec/{lib/hamster/sorted_set → hamster/set}/exclusion_spec.rb +20 -5
  171. data/spec/hamster/set/filter_spec.rb +79 -0
  172. data/spec/{lib/hamster → hamster}/set/find_spec.rb +25 -8
  173. data/spec/hamster/set/flatten_spec.rb +49 -0
  174. data/spec/hamster/set/foreach_spec.rb +39 -0
  175. data/spec/{lib/hamster → hamster}/set/grep_spec.rb +1 -1
  176. data/spec/hamster/set/group_by_spec.rb +65 -0
  177. data/spec/hamster/set/hash_spec.rb +20 -0
  178. data/spec/hamster/set/head_spec.rb +39 -0
  179. data/spec/{lib/hamster → hamster}/set/immutable_spec.rb +4 -1
  180. data/spec/hamster/set/include_spec.rb +35 -0
  181. data/spec/hamster/set/inspect_spec.rb +32 -0
  182. data/spec/hamster/set/intersection_spec.rb +46 -0
  183. data/spec/{lib/hamster/vector → hamster/set}/join_spec.rb +33 -23
  184. data/spec/hamster/set/map_spec.rb +64 -0
  185. data/spec/{lib/hamster → hamster}/set/marshal_spec.rb +9 -4
  186. data/spec/hamster/set/maximum_spec.rb +65 -0
  187. data/spec/hamster/set/minimum_spec.rb +65 -0
  188. data/spec/{lib/hamster → hamster}/set/none_spec.rb +30 -15
  189. data/spec/{lib/hamster → hamster}/set/one_spec.rb +29 -14
  190. data/spec/hamster/set/partition_spec.rb +71 -0
  191. data/spec/{lib/hamster → hamster}/set/product_spec.rb +15 -7
  192. data/spec/hamster/set/reduce_spec.rb +87 -0
  193. data/spec/hamster/set/remove_spec.rb +63 -0
  194. data/spec/{lib/hamster → hamster}/set/size_spec.rb +10 -1
  195. data/spec/{lib/hamster → hamster}/set/sorting_spec.rb +16 -18
  196. data/spec/hamster/set/subset_spec.rb +39 -0
  197. data/spec/{lib/hamster/vector → hamster/set}/sum_spec.rb +18 -4
  198. data/spec/hamster/set/superset_spec.rb +39 -0
  199. data/spec/hamster/set/to_a_spec.rb +42 -0
  200. data/spec/{lib/hamster/vector → hamster/set}/to_list_spec.rb +23 -8
  201. data/spec/{lib/hamster → hamster}/set/to_set_spec.rb +15 -3
  202. data/spec/hamster/set/union_spec.rb +45 -0
  203. data/spec/hamster/set/uniq_spec.rb +23 -0
  204. data/spec/hamster/sorter/immutable_spec.rb +12 -0
  205. data/spec/hamster/stack/clear_spec.rb +36 -0
  206. data/spec/hamster/stack/construction_spec.rb +43 -0
  207. data/spec/hamster/stack/copying_spec.rb +31 -0
  208. data/spec/hamster/stack/empty_spec.rb +31 -0
  209. data/spec/hamster/stack/eql_spec.rb +60 -0
  210. data/spec/hamster/stack/immutable_spec.rb +12 -0
  211. data/spec/hamster/stack/inspect_spec.rb +31 -0
  212. data/spec/hamster/stack/peek_spec.rb +40 -0
  213. data/spec/hamster/stack/pop_spec.rb +41 -0
  214. data/spec/hamster/stack/push_spec.rb +41 -0
  215. data/spec/hamster/stack/size_spec.rb +35 -0
  216. data/spec/hamster/stack/to_a_spec.rb +42 -0
  217. data/spec/hamster/stack/to_ary.rb +37 -0
  218. data/spec/hamster/stack/to_list_spec.rb +33 -0
  219. data/spec/hamster/trie/remove_spec.rb +117 -0
  220. data/spec/hamster/tuple/copying_spec.rb +24 -0
  221. data/spec/hamster/tuple/eql_spec.rb +61 -0
  222. data/spec/hamster/tuple/first_spec.rb +19 -0
  223. data/spec/hamster/tuple/immutable_spec.rb +12 -0
  224. data/spec/hamster/tuple/inspect_spec.rb +19 -0
  225. data/spec/hamster/tuple/last_spec.rb +19 -0
  226. data/spec/hamster/tuple/to_a_spec.rb +38 -0
  227. data/spec/hamster/tuple/to_ary_spec.rb +38 -0
  228. data/spec/hamster/undefined/erase_spec.rb +47 -0
  229. data/spec/hamster/vector/add_spec.rb +48 -0
  230. data/spec/{lib/hamster → hamster}/vector/any_spec.rb +0 -0
  231. data/spec/hamster/vector/clear_spec.rb +35 -0
  232. data/spec/{lib/hamster → hamster}/vector/copying_spec.rb +14 -4
  233. data/spec/hamster/vector/each_spec.rb +45 -0
  234. data/spec/hamster/vector/each_with_index_spec.rb +41 -0
  235. data/spec/hamster/vector/empty_spec.rb +34 -0
  236. data/spec/hamster/vector/eql_spec.rb +64 -0
  237. data/spec/hamster/vector/filter_spec.rb +62 -0
  238. data/spec/hamster/vector/first_spec.rb +35 -0
  239. data/spec/hamster/vector/get_spec.rb +80 -0
  240. data/spec/{lib/hamster → hamster}/vector/include_spec.rb +17 -4
  241. data/spec/hamster/vector/inspect_spec.rb +33 -0
  242. data/spec/{lib/hamster → hamster}/vector/last_spec.rb +3 -12
  243. data/spec/{lib/hamster → hamster}/vector/length_spec.rb +3 -12
  244. data/spec/hamster/vector/map_spec.rb +63 -0
  245. data/spec/{lib/hamster → hamster}/vector/reduce_spec.rb +47 -16
  246. data/spec/hamster/vector/set_spec.rb +113 -0
  247. data/spec/{lib/hamster → hamster}/vector/to_a_spec.rb +12 -11
  248. data/spec/{lib/hamster → hamster}/vector/to_ary_spec.rb +0 -0
  249. data/spec/lib/hamster/vector/cons_spec.rb +48 -0
  250. data/spec/lib/hamster/vector/exist_spec.rb +70 -0
  251. data/spec/lib/hamster/vector/exists_spec.rb +70 -0
  252. data/spec/lib/hamster/vector/ltlt_spec.rb +2 -20
  253. data/spec/spec_helper.rb +5 -36
  254. metadata +510 -723
  255. data/lib/hamster/deque.rb +0 -252
  256. data/lib/hamster/nested.rb +0 -36
  257. data/lib/hamster/sorted_set.rb +0 -1397
  258. data/spec/lib/hamster/core_ext/array_spec.rb +0 -14
  259. data/spec/lib/hamster/deque/clear_spec.rb +0 -34
  260. data/spec/lib/hamster/deque/construction_spec.rb +0 -30
  261. data/spec/lib/hamster/deque/copying_spec.rb +0 -20
  262. data/spec/lib/hamster/deque/dequeue_spec.rb +0 -35
  263. data/spec/lib/hamster/deque/empty_spec.rb +0 -40
  264. data/spec/lib/hamster/deque/first_spec.rb +0 -18
  265. data/spec/lib/hamster/deque/inspect_spec.rb +0 -24
  266. data/spec/lib/hamster/deque/last_spec.rb +0 -18
  267. data/spec/lib/hamster/deque/marshal_spec.rb +0 -34
  268. data/spec/lib/hamster/deque/new_spec.rb +0 -44
  269. data/spec/lib/hamster/deque/pop_spec.rb +0 -33
  270. data/spec/lib/hamster/deque/pretty_print_spec.rb +0 -24
  271. data/spec/lib/hamster/deque/random_modification_spec.rb +0 -34
  272. data/spec/lib/hamster/deque/to_a_spec.rb +0 -27
  273. data/spec/lib/hamster/deque/to_list_spec.rb +0 -26
  274. data/spec/lib/hamster/deque/unshift_spec.rb +0 -26
  275. data/spec/lib/hamster/experimental/mutable_set/add_qm_spec.rb +0 -39
  276. data/spec/lib/hamster/experimental/mutable_set/add_spec.rb +0 -37
  277. data/spec/lib/hamster/experimental/mutable_set/delete_qm_spec.rb +0 -38
  278. data/spec/lib/hamster/experimental/mutable_set/delete_spec.rb +0 -37
  279. data/spec/lib/hamster/hash/all_spec.rb +0 -54
  280. data/spec/lib/hamster/hash/any_spec.rb +0 -54
  281. data/spec/lib/hamster/hash/assoc_spec.rb +0 -52
  282. data/spec/lib/hamster/hash/clear_spec.rb +0 -43
  283. data/spec/lib/hamster/hash/construction_spec.rb +0 -39
  284. data/spec/lib/hamster/hash/default_proc_spec.rb +0 -73
  285. data/spec/lib/hamster/hash/delete_spec.rb +0 -40
  286. data/spec/lib/hamster/hash/each_spec.rb +0 -78
  287. data/spec/lib/hamster/hash/each_with_index_spec.rb +0 -30
  288. data/spec/lib/hamster/hash/empty_spec.rb +0 -44
  289. data/spec/lib/hamster/hash/eql_spec.rb +0 -70
  290. data/spec/lib/hamster/hash/except_spec.rb +0 -43
  291. data/spec/lib/hamster/hash/fetch_spec.rb +0 -58
  292. data/spec/lib/hamster/hash/find_spec.rb +0 -44
  293. data/spec/lib/hamster/hash/flat_map_spec.rb +0 -36
  294. data/spec/lib/hamster/hash/flatten_spec.rb +0 -99
  295. data/spec/lib/hamster/hash/get_spec.rb +0 -80
  296. data/spec/lib/hamster/hash/has_key_spec.rb +0 -32
  297. data/spec/lib/hamster/hash/has_value_spec.rb +0 -28
  298. data/spec/lib/hamster/hash/hash_spec.rb +0 -30
  299. data/spec/lib/hamster/hash/inspect_spec.rb +0 -31
  300. data/spec/lib/hamster/hash/invert_spec.rb +0 -31
  301. data/spec/lib/hamster/hash/key_spec.rb +0 -28
  302. data/spec/lib/hamster/hash/keys_spec.rb +0 -17
  303. data/spec/lib/hamster/hash/map_spec.rb +0 -46
  304. data/spec/lib/hamster/hash/merge_spec.rb +0 -83
  305. data/spec/lib/hamster/hash/min_max_spec.rb +0 -46
  306. data/spec/lib/hamster/hash/new_spec.rb +0 -71
  307. data/spec/lib/hamster/hash/partition_spec.rb +0 -36
  308. data/spec/lib/hamster/hash/pretty_print_spec.rb +0 -35
  309. data/spec/lib/hamster/hash/put_spec.rb +0 -103
  310. data/spec/lib/hamster/hash/reduce_spec.rb +0 -36
  311. data/spec/lib/hamster/hash/reject_spec.rb +0 -62
  312. data/spec/lib/hamster/hash/reverse_each_spec.rb +0 -28
  313. data/spec/lib/hamster/hash/sample_spec.rb +0 -14
  314. data/spec/lib/hamster/hash/select_spec.rb +0 -58
  315. data/spec/lib/hamster/hash/slice_spec.rb +0 -45
  316. data/spec/lib/hamster/hash/sort_spec.rb +0 -27
  317. data/spec/lib/hamster/hash/store_spec.rb +0 -76
  318. data/spec/lib/hamster/hash/take_spec.rb +0 -36
  319. data/spec/lib/hamster/hash/to_a_spec.rb +0 -14
  320. data/spec/lib/hamster/hash/to_hash_spec.rb +0 -22
  321. data/spec/lib/hamster/hash/update_in_spec.rb +0 -80
  322. data/spec/lib/hamster/hash/values_at_spec.rb +0 -14
  323. data/spec/lib/hamster/hash/values_spec.rb +0 -25
  324. data/spec/lib/hamster/list/add_spec.rb +0 -26
  325. data/spec/lib/hamster/list/all_spec.rb +0 -58
  326. data/spec/lib/hamster/list/any_spec.rb +0 -50
  327. data/spec/lib/hamster/list/at_spec.rb +0 -30
  328. data/spec/lib/hamster/list/break_spec.rb +0 -70
  329. data/spec/lib/hamster/list/combination_spec.rb +0 -34
  330. data/spec/lib/hamster/list/compare_spec.rb +0 -31
  331. data/spec/lib/hamster/list/cons_spec.rb +0 -26
  332. data/spec/lib/hamster/list/construction_spec.rb +0 -111
  333. data/spec/lib/hamster/list/count_spec.rb +0 -37
  334. data/spec/lib/hamster/list/cycle_spec.rb +0 -29
  335. data/spec/lib/hamster/list/delete_at_spec.rb +0 -19
  336. data/spec/lib/hamster/list/delete_spec.rb +0 -17
  337. data/spec/lib/hamster/list/drop_while_spec.rb +0 -39
  338. data/spec/lib/hamster/list/each_slice_spec.rb +0 -52
  339. data/spec/lib/hamster/list/each_spec.rb +0 -41
  340. data/spec/lib/hamster/list/each_with_index_spec.rb +0 -29
  341. data/spec/lib/hamster/list/empty_spec.rb +0 -24
  342. data/spec/lib/hamster/list/eql_spec.rb +0 -62
  343. data/spec/lib/hamster/list/fill_spec.rb +0 -50
  344. data/spec/lib/hamster/list/index_spec.rb +0 -34
  345. data/spec/lib/hamster/list/indices_spec.rb +0 -62
  346. data/spec/lib/hamster/list/inits_spec.rb +0 -29
  347. data/spec/lib/hamster/list/insert_spec.rb +0 -47
  348. data/spec/lib/hamster/list/inspect_spec.rb +0 -30
  349. data/spec/lib/hamster/list/join_spec.rb +0 -64
  350. data/spec/lib/hamster/list/last_spec.rb +0 -24
  351. data/spec/lib/hamster/list/ltlt_spec.rb +0 -20
  352. data/spec/lib/hamster/list/maximum_spec.rb +0 -40
  353. data/spec/lib/hamster/list/minimum_spec.rb +0 -40
  354. data/spec/lib/hamster/list/multithreading_spec.rb +0 -48
  355. data/spec/lib/hamster/list/partition_spec.rb +0 -116
  356. data/spec/lib/hamster/list/permutation_spec.rb +0 -56
  357. data/spec/lib/hamster/list/product_spec.rb +0 -24
  358. data/spec/lib/hamster/list/reduce_spec.rb +0 -54
  359. data/spec/lib/hamster/list/rotate_spec.rb +0 -37
  360. data/spec/lib/hamster/list/sample_spec.rb +0 -14
  361. data/spec/lib/hamster/list/slice_spec.rb +0 -230
  362. data/spec/lib/hamster/list/span_spec.rb +0 -77
  363. data/spec/lib/hamster/list/subsequences_spec.rb +0 -24
  364. data/spec/lib/hamster/list/sum_spec.rb +0 -24
  365. data/spec/lib/hamster/list/tail_spec.rb +0 -31
  366. data/spec/lib/hamster/list/tails_spec.rb +0 -29
  367. data/spec/lib/hamster/list/to_a_spec.rb +0 -40
  368. data/spec/lib/hamster/list/to_set_spec.rb +0 -19
  369. data/spec/lib/hamster/list/transpose_spec.rb +0 -20
  370. data/spec/lib/hamster/list/uniq_spec.rb +0 -30
  371. data/spec/lib/hamster/nested/construction_spec.rb +0 -44
  372. data/spec/lib/hamster/set/add_spec.rb +0 -76
  373. data/spec/lib/hamster/set/all_spec.rb +0 -52
  374. data/spec/lib/hamster/set/any_spec.rb +0 -52
  375. data/spec/lib/hamster/set/clear_spec.rb +0 -34
  376. data/spec/lib/hamster/set/delete_spec.rb +0 -72
  377. data/spec/lib/hamster/set/difference_spec.rb +0 -50
  378. data/spec/lib/hamster/set/disjoint_spec.rb +0 -26
  379. data/spec/lib/hamster/set/each_spec.rb +0 -46
  380. data/spec/lib/hamster/set/empty_spec.rb +0 -45
  381. data/spec/lib/hamster/set/exclusion_spec.rb +0 -48
  382. data/spec/lib/hamster/set/first_spec.rb +0 -29
  383. data/spec/lib/hamster/set/flatten_spec.rb +0 -47
  384. data/spec/lib/hamster/set/group_by_spec.rb +0 -60
  385. data/spec/lib/hamster/set/hash_spec.rb +0 -23
  386. data/spec/lib/hamster/set/include_spec.rb +0 -61
  387. data/spec/lib/hamster/set/inspect_spec.rb +0 -48
  388. data/spec/lib/hamster/set/intersect_spec.rb +0 -26
  389. data/spec/lib/hamster/set/intersection_spec.rb +0 -53
  390. data/spec/lib/hamster/set/join_spec.rb +0 -65
  391. data/spec/lib/hamster/set/map_spec.rb +0 -60
  392. data/spec/lib/hamster/set/maximum_spec.rb +0 -37
  393. data/spec/lib/hamster/set/minimum_spec.rb +0 -37
  394. data/spec/lib/hamster/set/new_spec.rb +0 -54
  395. data/spec/lib/hamster/set/partition_spec.rb +0 -53
  396. data/spec/lib/hamster/set/reduce_spec.rb +0 -56
  397. data/spec/lib/hamster/set/reject_spec.rb +0 -51
  398. data/spec/lib/hamster/set/sample_spec.rb +0 -14
  399. data/spec/lib/hamster/set/select_spec.rb +0 -74
  400. data/spec/lib/hamster/set/subset_spec.rb +0 -52
  401. data/spec/lib/hamster/set/sum_spec.rb +0 -24
  402. data/spec/lib/hamster/set/superset_spec.rb +0 -52
  403. data/spec/lib/hamster/set/to_a_spec.rb +0 -31
  404. data/spec/lib/hamster/set/to_list_spec.rb +0 -37
  405. data/spec/lib/hamster/set/union_spec.rb +0 -64
  406. data/spec/lib/hamster/sorted_set/above_spec.rb +0 -52
  407. data/spec/lib/hamster/sorted_set/add_spec.rb +0 -63
  408. data/spec/lib/hamster/sorted_set/at_spec.rb +0 -25
  409. data/spec/lib/hamster/sorted_set/below_spec.rb +0 -52
  410. data/spec/lib/hamster/sorted_set/between_spec.rb +0 -52
  411. data/spec/lib/hamster/sorted_set/clear_spec.rb +0 -44
  412. data/spec/lib/hamster/sorted_set/construction_spec.rb +0 -29
  413. data/spec/lib/hamster/sorted_set/delete_at_spec.rb +0 -19
  414. data/spec/lib/hamster/sorted_set/delete_spec.rb +0 -90
  415. data/spec/lib/hamster/sorted_set/disjoint_spec.rb +0 -26
  416. data/spec/lib/hamster/sorted_set/drop_spec.rb +0 -56
  417. data/spec/lib/hamster/sorted_set/drop_while_spec.rb +0 -35
  418. data/spec/lib/hamster/sorted_set/each_spec.rb +0 -29
  419. data/spec/lib/hamster/sorted_set/empty_spec.rb +0 -35
  420. data/spec/lib/hamster/sorted_set/eql_spec.rb +0 -121
  421. data/spec/lib/hamster/sorted_set/fetch_spec.rb +0 -65
  422. data/spec/lib/hamster/sorted_set/find_index_spec.rb +0 -41
  423. data/spec/lib/hamster/sorted_set/first_spec.rb +0 -19
  424. data/spec/lib/hamster/sorted_set/from_spec.rb +0 -52
  425. data/spec/lib/hamster/sorted_set/group_by_spec.rb +0 -58
  426. data/spec/lib/hamster/sorted_set/include_spec.rb +0 -24
  427. data/spec/lib/hamster/sorted_set/inspect_spec.rb +0 -38
  428. data/spec/lib/hamster/sorted_set/intersect_spec.rb +0 -26
  429. data/spec/lib/hamster/sorted_set/intersection_spec.rb +0 -29
  430. data/spec/lib/hamster/sorted_set/last_spec.rb +0 -37
  431. data/spec/lib/hamster/sorted_set/map_spec.rb +0 -36
  432. data/spec/lib/hamster/sorted_set/marshal_spec.rb +0 -37
  433. data/spec/lib/hamster/sorted_set/maximum_spec.rb +0 -37
  434. data/spec/lib/hamster/sorted_set/minimum_spec.rb +0 -20
  435. data/spec/lib/hamster/sorted_set/new_spec.rb +0 -52
  436. data/spec/lib/hamster/sorted_set/reverse_each_spec.rb +0 -29
  437. data/spec/lib/hamster/sorted_set/sample_spec.rb +0 -14
  438. data/spec/lib/hamster/sorted_set/select_spec.rb +0 -62
  439. data/spec/lib/hamster/sorted_set/size_spec.rb +0 -18
  440. data/spec/lib/hamster/sorted_set/slice_spec.rb +0 -257
  441. data/spec/lib/hamster/sorted_set/sorting_spec.rb +0 -45
  442. data/spec/lib/hamster/sorted_set/subset_spec.rb +0 -48
  443. data/spec/lib/hamster/sorted_set/superset_spec.rb +0 -48
  444. data/spec/lib/hamster/sorted_set/take_spec.rb +0 -55
  445. data/spec/lib/hamster/sorted_set/take_while_spec.rb +0 -34
  446. data/spec/lib/hamster/sorted_set/to_set_spec.rb +0 -19
  447. data/spec/lib/hamster/sorted_set/union_spec.rb +0 -28
  448. data/spec/lib/hamster/sorted_set/up_to_spec.rb +0 -52
  449. data/spec/lib/hamster/sorted_set/values_at_spec.rb +0 -34
  450. data/spec/lib/hamster/vector/add_spec.rb +0 -68
  451. data/spec/lib/hamster/vector/assoc_spec.rb +0 -36
  452. data/spec/lib/hamster/vector/bsearch_spec.rb +0 -58
  453. data/spec/lib/hamster/vector/clear_spec.rb +0 -34
  454. data/spec/lib/hamster/vector/combination_spec.rb +0 -82
  455. data/spec/lib/hamster/vector/compact_spec.rb +0 -30
  456. data/spec/lib/hamster/vector/compare_spec.rb +0 -32
  457. data/spec/lib/hamster/vector/concat_spec.rb +0 -35
  458. data/spec/lib/hamster/vector/count_spec.rb +0 -18
  459. data/spec/lib/hamster/vector/delete_at_spec.rb +0 -54
  460. data/spec/lib/hamster/vector/delete_spec.rb +0 -31
  461. data/spec/lib/hamster/vector/drop_spec.rb +0 -42
  462. data/spec/lib/hamster/vector/drop_while_spec.rb +0 -55
  463. data/spec/lib/hamster/vector/each_index_spec.rb +0 -41
  464. data/spec/lib/hamster/vector/each_spec.rb +0 -45
  465. data/spec/lib/hamster/vector/each_with_index_spec.rb +0 -40
  466. data/spec/lib/hamster/vector/empty_spec.rb +0 -42
  467. data/spec/lib/hamster/vector/eql_spec.rb +0 -77
  468. data/spec/lib/hamster/vector/fetch_spec.rb +0 -65
  469. data/spec/lib/hamster/vector/fill_spec.rb +0 -89
  470. data/spec/lib/hamster/vector/first_spec.rb +0 -19
  471. data/spec/lib/hamster/vector/flat_map_spec.rb +0 -51
  472. data/spec/lib/hamster/vector/flatten_spec.rb +0 -44
  473. data/spec/lib/hamster/vector/get_spec.rb +0 -75
  474. data/spec/lib/hamster/vector/group_by_spec.rb +0 -58
  475. data/spec/lib/hamster/vector/insert_spec.rb +0 -69
  476. data/spec/lib/hamster/vector/inspect_spec.rb +0 -50
  477. data/spec/lib/hamster/vector/map_spec.rb +0 -52
  478. data/spec/lib/hamster/vector/marshal_spec.rb +0 -32
  479. data/spec/lib/hamster/vector/maximum_spec.rb +0 -34
  480. data/spec/lib/hamster/vector/minimum_spec.rb +0 -34
  481. data/spec/lib/hamster/vector/multiply_spec.rb +0 -48
  482. data/spec/lib/hamster/vector/new_spec.rb +0 -51
  483. data/spec/lib/hamster/vector/partition_spec.rb +0 -53
  484. data/spec/lib/hamster/vector/permutation_spec.rb +0 -92
  485. data/spec/lib/hamster/vector/pop_spec.rb +0 -27
  486. data/spec/lib/hamster/vector/product_spec.rb +0 -71
  487. data/spec/lib/hamster/vector/reject_spec.rb +0 -44
  488. data/spec/lib/hamster/vector/repeated_combination_spec.rb +0 -78
  489. data/spec/lib/hamster/vector/repeated_permutation_spec.rb +0 -94
  490. data/spec/lib/hamster/vector/reverse_each_spec.rb +0 -32
  491. data/spec/lib/hamster/vector/reverse_spec.rb +0 -22
  492. data/spec/lib/hamster/vector/rindex_spec.rb +0 -37
  493. data/spec/lib/hamster/vector/rotate_spec.rb +0 -74
  494. data/spec/lib/hamster/vector/sample_spec.rb +0 -14
  495. data/spec/lib/hamster/vector/select_spec.rb +0 -64
  496. data/spec/lib/hamster/vector/set_spec.rb +0 -175
  497. data/spec/lib/hamster/vector/shift_spec.rb +0 -28
  498. data/spec/lib/hamster/vector/shuffle_spec.rb +0 -44
  499. data/spec/lib/hamster/vector/slice_spec.rb +0 -241
  500. data/spec/lib/hamster/vector/sorting_spec.rb +0 -57
  501. data/spec/lib/hamster/vector/take_spec.rb +0 -43
  502. data/spec/lib/hamster/vector/take_while_spec.rb +0 -35
  503. data/spec/lib/hamster/vector/to_set_spec.rb +0 -23
  504. data/spec/lib/hamster/vector/transpose_spec.rb +0 -49
  505. data/spec/lib/hamster/vector/uniq_spec.rb +0 -56
  506. data/spec/lib/hamster/vector/unshift_spec.rb +0 -29
  507. data/spec/lib/hamster/vector/update_in_spec.rb +0 -83
  508. data/spec/lib/hamster/vector/values_at_spec.rb +0 -34
  509. data/spec/lib/hamster/vector/zip_spec.rb +0 -58
@@ -1,5 +1,4 @@
1
1
  module Hamster
2
- # @private
3
2
  module Immutable
4
3
  def self.included(klass)
5
4
  klass.extend(ClassMethods)
@@ -8,7 +7,6 @@ module Hamster
8
7
  end
9
8
  end
10
9
 
11
- # @private
12
10
  module ClassMethods
13
11
  def new(*args)
14
12
  super.immutable!
@@ -32,7 +30,6 @@ module Hamster
32
30
  end
33
31
  end
34
32
 
35
- # @private
36
33
  module MemoizeMethods
37
34
  def immutable!
38
35
  @__hamster_immutable_memory__ = Object.new
@@ -40,7 +37,6 @@ module Hamster
40
37
  end
41
38
  end
42
39
 
43
- # @private
44
40
  module InstanceMethods
45
41
  def immutable!
46
42
  freeze
@@ -1,110 +1,118 @@
1
+ require "forwardable"
1
2
  require "thread"
2
- require "atomic"
3
- require "set"
4
3
 
5
4
  require "hamster/core_ext/enumerable"
6
5
  require "hamster/undefined"
7
6
  require "hamster/enumerable"
7
+ require "hamster/tuple"
8
+ require "hamster/sorter"
8
9
  require "hamster/hash"
9
10
  require "hamster/set"
10
11
 
11
12
  module Hamster
12
13
  class << self
14
+ extend Forwardable
13
15
 
14
- # Create a list containing the given items.
16
+ # Create a list containing the given items
15
17
  #
16
18
  # @example
17
19
  # list = Hamster.list(:a, :b, :c)
18
- # # => Hamster::List[:a, :b, :c]
20
+ # # => [:a, :b, :c]
19
21
  #
20
- # @return [List]
22
+ # @return [Hamster::List]
23
+ #
24
+ # @api public
21
25
  def list(*items)
22
26
  items.to_list
23
27
  end
24
28
 
25
- # Create a lazy, infinite list.
29
+ # Create a lazy, infinite list
26
30
  #
27
- # The given block is called as necessary to return successive elements of the list.
31
+ # The given block is repeatedly called to yield the elements of the list.
28
32
  #
29
33
  # @example
30
34
  # Hamster.stream { :hello }.take(3)
31
- # # => Hamster::List[:hello, :hello, :hello]
35
+ # # => [:hello, :hello, :hello]
36
+ #
37
+ # @return [Hamster::List]
32
38
  #
33
- # @return [List]
39
+ # @api public
34
40
  def stream(&block)
35
41
  return EmptyList unless block_given?
36
- LazyList.new { Cons.new(yield, stream(&block)) }
42
+ Stream.new { Sequence.new(yield, stream(&block)) }
37
43
  end
38
44
 
39
- # Construct a list of consecutive integers.
45
+ # Construct a list of consecutive integers
40
46
  #
41
47
  # @example
42
48
  # Hamster.interval(5,9)
43
- # # => Hamster::List[5, 6, 7, 8, 9]
49
+ # # => [5, 6, 7, 8, 9]
44
50
  #
45
51
  # @param from [Integer] Start value, inclusive
46
52
  # @param to [Integer] End value, inclusive
47
- # @return [List]
53
+ # @return [Hamster::List]
54
+ #
55
+ # @api public
48
56
  def interval(from, to)
49
57
  return EmptyList if from > to
50
58
  interval_exclusive(from, to.next)
51
59
  end
60
+ def_delegator :self, :interval, :range
52
61
 
53
62
  # Create an infinite list repeating the same item indefinitely
54
63
  #
55
64
  # @example
56
65
  # Hamster.repeat(:chunky).take(4)
57
- # => Hamster::List[:chunky, :chunky, :chunky, :chunky]
66
+ # => [:chunky, :chunky, :chunky, :chunky]
58
67
  #
59
- # @return [List]
68
+ # @api public
60
69
  def repeat(item)
61
- LazyList.new { Cons.new(item, repeat(item)) }
70
+ Stream.new { Sequence.new(item, repeat(item)) }
62
71
  end
63
72
 
64
73
  # Create a list that contains a given item a fixed number of times
65
74
  #
66
75
  # @example
67
76
  # Hamster.replicate(3).(:hamster)
68
- # #=> Hamster::List[:hamster, :hamster, :hamster]
77
+ # #=> [:hamster, :hamster, :hamster]
69
78
  #
70
- # @return [List]
79
+ # @api public
71
80
  def replicate(number, item)
72
81
  repeat(item).take(number)
73
82
  end
74
83
 
75
- # Create an infinite list where each item is derived from the previous one,
76
- # using the provided block
84
+ # Create an infinite list where each item is based on the previous one
77
85
  #
78
86
  # @example
79
- # Hamster.iterate(0) { |i| i.next }.take(5)
80
- # # => Hamster::List[0, 1, 2, 3, 4]
87
+ # Hamster.iterate(0) {|i| i.next}.take(5)
88
+ # # => [0, 1, 2, 3, 4]
81
89
  #
82
90
  # @param item [Object] Starting value
83
91
  # @yieldparam [Object] The previous value
84
92
  # @yieldreturn [Object] The next value
85
- # @return [List]
93
+ #
94
+ # @api public
86
95
  def iterate(item, &block)
87
- LazyList.new { Cons.new(item, iterate(yield(item), &block)) }
96
+ Stream.new { Sequence.new(item, iterate(yield(item), &block)) }
88
97
  end
89
98
 
90
- # Turn an Enumerator into a `Hamster::List`. The result is a lazy collection
91
- # where the values are memoized as they are generated.
99
+ # Turn an enumerator into a Hamster list
92
100
  #
93
- # If your code uses multiple threads, you need to make sure that the returned
94
- # lazy collection is realized on a single thread only. Otherwise, a `FiberError`
95
- # will be raised. After the collection is realized, it can be used from other
96
- # threads as well.
101
+ # The result is a lazy collection where the values are memoized as they are
102
+ # generated.
97
103
  #
98
104
  # @example
99
- # def rg; loop { yield rand(100) }; end
105
+ # def rg ; loop { yield rand(100) } ; end
100
106
  # Hamster.enumerate(to_enum(:rg)).take(10)
101
107
  #
102
108
  # @param enum [Enumerator] The object to iterate over
103
- # @return [List]
109
+ # @return [Stream]
110
+ #
111
+ # @api public
104
112
  def enumerate(enum)
105
- LazyList.new do
113
+ Stream.new do
106
114
  begin
107
- Cons.new(enum.next, enumerate(enum))
115
+ Sequence.new(enum.next, enumerate(enum))
108
116
  rescue StopIteration
109
117
  EmptyList
110
118
  end
@@ -115,84 +123,50 @@ module Hamster
115
123
 
116
124
  def interval_exclusive(from, to)
117
125
  return EmptyList if from == to
118
- LazyList.new { Cons.new(from, interval_exclusive(from.next, to)) }
126
+ Stream.new { Sequence.new(from, interval_exclusive(from.next, to)) }
119
127
  end
120
128
  end
121
129
 
122
- # A `List` can be constructed with {Hamster.list Hamster.list} or {List.[] List[]}.
123
- # It consists of a *head* (the first element) and a *tail* (which itself is also
124
- # a `List`, containing all the remaining elements).
130
+ # Common behavior for lists
131
+ #
132
+ # A +Hamster::List+ can be constructed with {Hamster.list Hamster.list}. It
133
+ # consists of a +head+ (the first element) and a +tail+, containing the rest
134
+ # of the list.
125
135
  #
126
136
  # This is a singly linked list. Prepending to the list with {List#cons} runs
127
137
  # in constant time. Traversing the list from front to back is efficient,
128
- # however, indexed access runs in linear time because the list needs to be
138
+ # indexed access however runs in linear time because the list needs to be
129
139
  # traversed to find the element.
130
140
  #
141
+ # In practice lists are constructed of a combination of {Sequence}, providing
142
+ # the basic blocks that are linked, {Stream} for providing laziness, and
143
+ # {EmptyList} as a terminator.
131
144
  module List
145
+ extend Forwardable
132
146
  include Enumerable
133
147
 
134
- # @private
135
148
  CADR = /^c([ad]+)r$/
136
149
 
137
- # Create a new `List` populated with the given items.
138
- #
139
- # @example
140
- # list = Hamster::List[:a, :b, :c]
141
- # # => Hamster::List[:a, :b, :c]
142
- #
143
- # @return [List]
144
- def self.[](*items)
145
- items.to_list
146
- end
150
+ def_delegator :self, :head, :first
151
+ def_delegator :self, :empty?, :null?
147
152
 
148
- # Return the number of items in this `List`.
149
- # @return [Integer]
150
153
  def size
151
- result, list = 0, self
152
- until list.empty?
153
- if list.cached_size?
154
- return result + list.size
155
- else
156
- result += 1
157
- end
158
- list = list.tail
159
- end
160
- result
154
+ reduce(0) { |memo, item| memo.next }
161
155
  end
162
- alias :length :size
156
+ def_delegator :self, :size, :length
163
157
 
164
- # Create a new `List` with `item` added at the front.
165
- #
166
- # @example
167
- # Hamster.list(:b, :c).cons(:a)
168
- # # => Hamster::List[:a, :b, :c]
169
- #
170
- # @param item [Object] The item to add
171
- # @return [List]
172
158
  def cons(item)
173
- Cons.new(item, self)
159
+ Sequence.new(item, self)
174
160
  end
175
- alias :add :cons
161
+ def_delegator :self, :cons, :>>
176
162
 
177
- # Create a new `List` with `item` added at the end. This is much less efficient
178
- # than adding items at the front.
179
- #
180
- # @example
181
- # Hamster.list(:a, :b) << :c
182
- # # => Hamster::List[:a, :b, :c]
183
- #
184
- # @param item [Object] The item to add
185
- # @return [List]
186
- def <<(item)
163
+ def add(item)
187
164
  append(Hamster.list(item))
188
165
  end
166
+ def_delegator :self, :add, :<<
189
167
 
190
- # Call the given block once for each item in the list, passing each
191
- # item from first to last successively to the block.
192
- #
193
- # @return [self]
194
168
  def each
195
- return to_enum unless block_given?
169
+ return self unless block_given?
196
170
  list = self
197
171
  until list.empty?
198
172
  yield(list.head)
@@ -200,138 +174,71 @@ module Hamster
200
174
  end
201
175
  end
202
176
 
203
- # Return a lazy list in which each element is derived from the corresponding
204
- # element in this `List`, transformed through the given block.
205
- #
206
- # @example
207
- # Hamster.list(3, 2, 1).map { |e| e * e } # => Hamster::List[9, 4, 1]
208
- #
209
- # @return [List]
210
177
  def map(&block)
211
- return enum_for(:map) unless block_given?
212
- LazyList.new do
178
+ return self unless block_given?
179
+ Stream.new do
213
180
  next self if empty?
214
- Cons.new(yield(head), tail.map(&block))
181
+ Sequence.new(yield(head), tail.map(&block))
215
182
  end
216
183
  end
217
- alias :collect :map
184
+ def_delegator :self, :map, :collect
218
185
 
219
- # Return a lazy list which is realized by transforming each item into a `List`,
220
- # and flattening the resulting lists.
221
- #
222
- # @example
223
- # Hamster.list(1, 2, 3).flat_map { |x| Hamster.list(x, 100) }
224
- # # => Hamster::List[1, 100, 2, 100, 3, 100]
225
- #
226
- # @return [List]
227
186
  def flat_map(&block)
228
- return enum_for(:flat_map) unless block_given?
229
- LazyList.new do
187
+ return self unless block_given?
188
+ Stream.new do
230
189
  next self if empty?
231
190
  head_list = Hamster.list(*yield(head))
232
191
  next tail.flat_map(&block) if head_list.empty?
233
- Cons.new(head_list.first, head_list.drop(1).append(tail.flat_map(&block)))
192
+ Sequence.new(head_list.first, head_list.drop(1).append(tail.flat_map(&block)))
234
193
  end
235
194
  end
236
195
 
237
- # Return a lazy list which contains all the items for which the given block
238
- # returns true.
239
- #
240
- # @example
241
- # Hamster.list("Bird", "Cow", "Elephant").select { |e| e.size >= 4 }
242
- # # => Hamster::List["Bird", "Elephant"]
243
- #
244
- # @return [List]
245
- def select(&block)
246
- return enum_for(:select) unless block_given?
247
- LazyList.new do
248
- list = self
249
- while true
250
- break list if list.empty?
251
- break Cons.new(list.head, list.tail.select(&block)) if yield(list.head)
252
- list = list.tail
253
- end
196
+ def filter(&block)
197
+ return self unless block_given?
198
+ Stream.new do
199
+ next self if empty?
200
+ next Sequence.new(head, tail.filter(&block)) if yield(head)
201
+ tail.filter(&block)
254
202
  end
255
203
  end
256
- alias :find_all :select
257
- alias :keep_if :select
258
204
 
259
- # Return a lazy list which contains all elements up to, but not including, the
260
- # first element for which the block returns `nil` or `false`.
261
- #
262
- # @example
263
- # Hamster.list(1, 3, 5, 7, 6, 4, 2).take_while { |e| e < 5 }
264
- # # => Hamster::List[1, 3]
265
- #
266
- # @return [List, Enumerator]
267
205
  def take_while(&block)
268
- return enum_for(:take_while) unless block_given?
269
- LazyList.new do
206
+ return self unless block_given?
207
+ Stream.new do
270
208
  next self if empty?
271
- next Cons.new(head, tail.take_while(&block)) if yield(head)
209
+ next Sequence.new(head, tail.take_while(&block)) if yield(head)
272
210
  EmptyList
273
211
  end
274
212
  end
275
213
 
276
- # Return a lazy list which contains all elements starting from the
277
- # first element for which the block returns `nil` or `false`.
278
- #
279
- # @example
280
- # Hamster.list(1, 3, 5, 7, 6, 4, 2).drop_while { |e| e < 5 }
281
- # # => Hamster::List[5, 7, 6, 4, 2]
282
- #
283
- # @return [List, Enumerator]
284
214
  def drop_while(&block)
285
- return enum_for(:drop_while) unless block_given?
286
- LazyList.new do
215
+ return self unless block_given?
216
+ Stream.new do
287
217
  list = self
288
218
  list = list.tail while !list.empty? && yield(list.head)
289
219
  list
290
220
  end
291
221
  end
292
222
 
293
- # Return a lazy list containing the first `number` items from this `List`.
294
- #
295
- # @example
296
- # Hamster.list(1, 3, 5, 7, 6, 4, 2).take(3)
297
- # # => Hamster::List[1, 3, 5]
298
- #
299
- # @param number [Integer] The number of items to retain
300
- # @return [List]
301
223
  def take(number)
302
- LazyList.new do
224
+ Stream.new do
303
225
  next self if empty?
304
- next Cons.new(head, tail.take(number - 1)) if number > 0
226
+ next Sequence.new(head, tail.take(number - 1)) if number > 0
305
227
  EmptyList
306
228
  end
307
229
  end
308
230
 
309
- # Return a lazy list containing all but the last item from this `List`.
310
- #
311
- # @example
312
- # Hamster.list("A", "B", "C").pop # => Hamster::List["A", "B"]
313
- #
314
- # @return [List]
315
231
  def pop
316
- LazyList.new do
232
+ Stream.new do
317
233
  next self if empty?
318
234
  new_size = size - 1
319
- next Cons.new(head, tail.take(new_size - 1)) if new_size >= 1
235
+ next Sequence.new(head, tail.take(new_size - 1)) if new_size >= 1
320
236
  EmptyList
321
237
  end
322
238
  end
323
239
 
324
- # Return a lazy list containing all items after the first `number` items from
325
- # this `List`.
326
- #
327
- # @example
328
- # Hamster.list(1, 3, 5, 7, 6, 4, 2).drop(3)
329
- # # => Hamster::List[7, 6, 4, 2]
330
- #
331
- # @param number [Integer] The number of items to skip over
332
- # @return [List]
333
240
  def drop(number)
334
- LazyList.new do
241
+ Stream.new do
335
242
  list = self
336
243
  while !list.empty? && number > 0
337
244
  number -= 1
@@ -341,688 +248,224 @@ module Hamster
341
248
  end
342
249
  end
343
250
 
344
- # Return a lazy list with all items from this `List`, followed by all items from
345
- # `other`.
346
- #
347
- # @example
348
- # Hamster.list(1, 2, 3).append(Hamster.list(4, 5))
349
- # # => Hamster::List[1, 2, 3, 4, 5]
350
- #
351
- # @param other [List] The list to add onto the end of this one
352
- # @return [List]
353
251
  def append(other)
354
- LazyList.new do
252
+ Stream.new do
355
253
  next other if empty?
356
- Cons.new(head, tail.append(other))
254
+ Sequence.new(head, tail.append(other))
357
255
  end
358
256
  end
359
- alias :concat :append
360
- alias :+ :append
257
+ def_delegator :self, :append, :concat
258
+ def_delegator :self, :append, :cat
259
+ def_delegator :self, :append, :+
361
260
 
362
- # Return a `List` with the same items, but in reverse order.
363
- #
364
- # @example
365
- # Hamster.list("A", "B", "C").reverse # => Hamster::List["C", "B", "A"]
366
- #
367
- # @return [List]
368
261
  def reverse
369
- LazyList.new { reduce(EmptyList) { |list, item| list.cons(item) }}
262
+ Stream.new { reduce(EmptyList) { |list, item| list.cons(item) } }
370
263
  end
371
264
 
372
- # Gather the corresponding elements from this `List` and `others` (that is,
373
- # the elements with the same indices) into new 2-element lists. Return a
374
- # lazy list of these 2-element lists.
375
- #
376
- #
377
- # @example
378
- # Hamster.list("A", "B", "C").zip(Hamster.list(1, 2, 3))
379
- # # => Hamster::List[Hamster::List["A", 1], Hamster::List["B", 2], Hamster::List["C", 3]]
380
- #
381
- # @param others [List] The list to zip together with this one
382
- # @return [List]
383
- def zip(others)
384
- LazyList.new do
385
- next self if empty? && others.empty?
386
- Cons.new(Cons.new(head, Cons.new(others.head)), tail.zip(others.tail))
387
- end
388
- end
389
-
390
- # Gather the first element of each nested list into a new `List`, then the second
391
- # element of each nested list, then the third, and so on. In other words, if each
392
- # nested list is a "row", return a lazy list of "columns" instead.
393
- #
394
- # Although the returned list is lazy, each returned nested list (each "column")
395
- # is strict. So while each nested list in the input can be infinite, the parent
396
- # `List` must not be, or trying to realize the first element in the output will
397
- # cause an infinite loop.
398
- #
399
- # @example
400
- # # First let's create some infinite lists
401
- # list1 = Hamster.iterate(1, &:next)
402
- # list2 = Hamster.iterate(2) { |n| n * 2 }
403
- # list3 = Hamster.iterate(3) { |n| n * 3 }
404
- #
405
- # # Now we transpose our 3 infinite "rows" into an infinite series of 3-element "columns"
406
- # Hamster.list(list1, list2, list3).transpose.take(4)
407
- # # => Hamster::List[
408
- # # Hamster::List[1, 2, 3],
409
- # # Hamster::List[2, 4, 9],
410
- # # Hamster::List[3, 8, 27],
411
- # # Hamster::List[4, 16, 81]]
412
- #
413
- # @return [List]
414
- def transpose
415
- return EmptyList if empty?
416
- LazyList.new do
417
- next EmptyList if any? { |list| list.empty? }
418
- heads, tails = EmptyList, EmptyList
419
- reverse_each { |list| heads, tails = heads.cons(list.head), tails.cons(list.tail) }
420
- Cons.new(heads, tails.transpose)
265
+ def zip(other)
266
+ Stream.new do
267
+ next self if empty? && other.empty?
268
+ Sequence.new(Sequence.new(head, Sequence.new(other.head)), tail.zip(other.tail))
421
269
  end
422
270
  end
423
271
 
424
- # Concatenate an infinite series of copies of this `List` together (into a
425
- # new lazy list). Or, if empty, just return an empty list.
426
- #
427
- # @example
428
- # Hamster.list(1, 2, 3).cycle.take(10)
429
- # # => Hamster::List[1, 2, 3, 1, 2, 3, 1, 2, 3, 1]
430
- #
431
- # @return [List]
432
272
  def cycle
433
- LazyList.new do
273
+ Stream.new do
434
274
  next self if empty?
435
- Cons.new(head, tail.append(cycle))
275
+ Sequence.new(head, tail.append(cycle))
436
276
  end
437
277
  end
438
278
 
439
- # Return a new `List` with the same elements, but rotated so that the one at
440
- # index `count` is the first element of the new list. If `count` is positive,
441
- # the elements will be shifted left, and those shifted past the lowest position
442
- # will be moved to the end. If `count` is negative, the elements will be shifted
443
- # right, and those shifted past the last position will be moved to the beginning.
444
- #
445
- # @example
446
- # l = Hamster.list("A", "B", "C", "D", "E", "F")
447
- # l.rotate(2) # => Hamster::List["C", "D", "E", "F", "A", "B"]
448
- # l.rotate(-1) # => Hamster::List["F", "A", "B", "C", "D", "E"]
449
- #
450
- # @param count [Integer] The number of positions to shift items by
451
- # @return [Vector]
452
- def rotate(count = 1)
453
- raise TypeError, "expected Integer" if not count.is_a?(Integer)
454
- return self if empty? || (count % size) == 0
455
- count = (count >= 0) ? count % size : (size - (~count % size) - 1)
456
- drop(count).append(take(count))
457
- end
458
-
459
- # Return 2 `List`s, one of the first `number` items, and another of all the
460
- # remaining items.
461
- #
462
- # @example
463
- # Hamster.list("a", "b", "c", "d").split(2)
464
- # # => [Hamster::List["a", "b"], Hamster::List["c", "d"]]
465
- #
466
- # @param number [Integer] The index at which to split this list
467
- # @return [Array]
468
279
  def split_at(number)
469
- [take(number), drop(number)].freeze
280
+ Tuple.new(take(number), drop(number))
470
281
  end
471
282
 
472
- # Return 2 `List`s, one up to (but not including) the first item for which the
473
- # block returns `nil` or `false`, and another of all the remaining items.
474
- #
475
- # @example
476
- # Hamster.list(4, 3, 5, 2, 1).span { |x| x > 2 }
477
- # # => [Hamster::List[4, 3, 5], Hamster::List[2, 1]]
478
- #
479
- # @return [Array]
480
283
  def span(&block)
481
- return [self, EmptyList].freeze unless block_given?
482
- splitter = Splitter.new(self, block)
483
- mutex = Mutex.new
484
- [Splitter::Left.new(splitter, splitter.left, mutex),
485
- Splitter::Right.new(splitter, mutex)].freeze
284
+ return Tuple.new(self, EmptyList) unless block_given?
285
+ Tuple.new(take_while(&block), drop_while(&block))
486
286
  end
487
287
 
488
- # Return 2 `List`s, one up to (but not including) the first item for which the
489
- # block returns true, and another of all the remaining items.
490
- #
491
- # @example
492
- # Hamster.list(1, 3, 4, 2, 5).break { |x| x > 3 }
493
- # # => [Hamster::List[1, 3], Hamster::List[4, 2, 5]]
494
- #
495
- # @return [Array]
496
288
  def break(&block)
497
289
  return span unless block_given?
498
290
  span { |item| !yield(item) }
499
291
  end
500
292
 
501
- # Return an empty `List`.
502
- # @return [List]
503
293
  def clear
504
294
  EmptyList
505
295
  end
506
296
 
507
- # Return a `List` with the same items, but sorted either in their natural order,
508
- # or using an optional comparator block. The block must take 2 parameters, and
509
- # return 0, 1, or -1 if the first one is equal, greater than, or less than the
510
- # second (respectively).
511
- #
512
- # @return [List]
513
297
  def sort(&comparator)
514
- LazyList.new { super(&comparator).to_list }
298
+ Stream.new { Sorter.new(self).sort(&comparator) }
515
299
  end
516
300
 
517
- # Return a new `List` with the same items, but sorted. The sort order will be
518
- # determined by mapping the items through the given block to obtain sort keys,
519
- # and then sorting the keys according to their natural sort order.
520
- #
521
- # @return [List]
522
301
  def sort_by(&transformer)
523
302
  return sort unless block_given?
524
- LazyList.new { super(&transformer).to_list }
303
+ Stream.new { Sorter.new(self).sort_by(&transformer) }
304
+ end
305
+
306
+ def join(sep = "")
307
+ return "" if empty?
308
+ sep = sep.to_s
309
+ tail.reduce(head.to_s.dup) { |result, item| result << sep << item.to_s }
525
310
  end
526
311
 
527
- # Return a new `List` with `sep` inserted between each of the existing elements.
528
- #
529
- # @example
530
- # Hamster.list("one", "two", "three").intersperse(" ")
531
- # # => Hamster::List["one", " ", "two", " ", "three"]
532
- #
533
- # @return [List]
534
312
  def intersperse(sep)
535
- LazyList.new do
313
+ Stream.new do
536
314
  next self if tail.empty?
537
- Cons.new(head, Cons.new(sep, tail.intersperse(sep)))
315
+ Sequence.new(head, Sequence.new(sep, tail.intersperse(sep)))
538
316
  end
539
317
  end
540
318
 
541
- # Return a lazy list with the same items, but all duplicates removed.
542
- # Use `#hash` and `#eql?` to determine which items are duplicates.
543
- #
544
- # @example
545
- # Hamster.list(:a, :b, :a, :c, :b).uniq # => Hamster::List[:a, :b, :c]
546
- #
547
- # @return [List]
548
- def uniq(items = ::Set.new)
549
- LazyList.new do
319
+ def uniq(items = EmptySet)
320
+ Stream.new do
550
321
  next self if empty?
551
322
  next tail.uniq(items) if items.include?(head)
552
- Cons.new(head, tail.uniq(items.add(head)))
323
+ Sequence.new(head, tail.uniq(items.add(head)))
553
324
  end
554
325
  end
326
+ def_delegator :self, :uniq, :nub
327
+ def_delegator :self, :uniq, :remove_duplicates
555
328
 
556
- # Return a `List` with all the elements from both this list and `other`,
557
- # with all duplicates removed.
558
- #
559
- # @example
560
- # Hamster.list(1, 2).union(Hamster.list(2, 3)) # => Hamster::List[1, 2, 3]
561
- #
562
- # @param other [List] The list to merge with
563
- # @return [List]
564
- def union(other, items = ::Set.new)
565
- LazyList.new do
566
- next other.uniq(items) if empty?
567
- next tail.union(other, items) if items.include?(head)
568
- Cons.new(head, tail.union(other, items.add(head)))
569
- end
329
+ def union(other)
330
+ append(other).uniq
570
331
  end
571
- alias :| :union
332
+ def_delegator :self, :union, :|
572
333
 
573
- # Return a lazy list with all elements except the last one.
574
- #
575
- # @example
576
- # Hamster.list("a", "b", "c").init # => Hamster::List["a", "b"]
577
- #
578
- # @return [List]
579
334
  def init
580
335
  return EmptyList if tail.empty?
581
- LazyList.new { Cons.new(head, tail.init) }
336
+ Stream.new { Sequence.new(head, tail.init) }
582
337
  end
583
338
 
584
- # Return the last item in this list.
585
- # @return [Object]
586
339
  def last
587
340
  list = self
588
341
  list = list.tail until list.tail.empty?
589
342
  list.head
590
343
  end
591
344
 
592
- # Return a lazy list of all suffixes of this list.
593
- #
594
- # @example
595
- # Hamster.list(1,2,3).tails
596
- # # => Hamster::List[
597
- # # Hamster::List[1, 2, 3],
598
- # # Hamster::List[2, 3],
599
- # # Hamster::List[3]]
600
- #
601
- # @return [List]
602
345
  def tails
603
- LazyList.new do
604
- next self if empty?
605
- Cons.new(self, tail.tails)
346
+ Stream.new do
347
+ next Sequence.new(self) if empty?
348
+ Sequence.new(self, tail.tails)
606
349
  end
607
350
  end
608
351
 
609
- # Return a lazy list of all prefixes of this list.
610
- #
611
- # @example
612
- # Hamster.list(1,2,3).inits
613
- # # => Hamster::List[
614
- # # Hamster::List[1],
615
- # # Hamster::List[1, 2],
616
- # # Hamster::List[1, 2, 3]]
617
- #
618
- # @return [List]
619
352
  def inits
620
- LazyList.new do
621
- next self if empty?
622
- Cons.new(Hamster.list(head), tail.inits.map { |list| list.cons(head) })
353
+ Stream.new do
354
+ next Sequence.new(self) if empty?
355
+ Sequence.new(EmptyList, tail.inits.map { |list| list.cons(head) })
623
356
  end
624
357
  end
625
358
 
626
- # Return a lazy list of all combinations of length `n` of items from this `List`.
627
- #
628
- # @example
629
- # Hamster.list(1,2,3).combination(2)
630
- # # => Hamster::List[
631
- # # Hamster::List[1, 2],
632
- # # Hamster::List[1, 3],
633
- # # Hamster::List[2, 3]]
634
- #
635
- # @return [List]
636
- def combination(n)
637
- return Cons.new(EmptyList) if n == 0
638
- LazyList.new do
359
+ def combinations(number)
360
+ return Sequence.new(EmptyList) if number == 0
361
+ Stream.new do
639
362
  next self if empty?
640
- tail.combination(n - 1).map { |list| list.cons(head) }.append(tail.combination(n))
363
+ tail.combinations(number - 1).map { |list| list.cons(head) }.append(tail.combinations(number))
641
364
  end
642
365
  end
366
+ def_delegator :self, :combinations, :combination
643
367
 
644
- # Split the items in this list in groups of `number`. Return a list of lists.
645
- #
646
- # @example
647
- # Hamster.list(*("a".."o")).chunk(5)
648
- # # => Hamster::List[
649
- # # Hamster::List["a", "b", "c", "d", "e"],
650
- # # Hamster::List["f", "g", "h", "i", "j"],
651
- # # Hamster::List["k", "l", "m", "n", "o"]]
652
- #
653
- # @return [List]
654
368
  def chunk(number)
655
- LazyList.new do
369
+ Stream.new do
656
370
  next self if empty?
657
371
  first, remainder = split_at(number)
658
- Cons.new(first, remainder.chunk(number))
372
+ Sequence.new(first, remainder.chunk(number))
659
373
  end
660
374
  end
661
375
 
662
- # Split the items in this list in groups of `number`, and yield each group
663
- # to the block (as a `List`).
664
- # @return [self]
665
376
  def each_chunk(number, &block)
666
- return enum_for(:each_chunk, number) unless block_given?
667
377
  chunk(number).each(&block)
668
- self
669
378
  end
670
- alias :each_slice :each_chunk
379
+ def_delegator :self, :each_chunk, :each_slice
671
380
 
672
- # Return a new `List` with all nested lists recursively "flattened out",
673
- # that is, their elements inserted into the new `List` in the place where
674
- # the nested list originally was.
675
- #
676
- # @example
677
- # Hamster.list(Hamster.list(1, 2), Hamster.list(3, 4)).flatten
678
- # # => Hamster::List[1, 2, 3, 4]
679
- #
680
- # @return [List]
681
381
  def flatten
682
- LazyList.new do
382
+ Stream.new do
683
383
  next self if empty?
684
384
  next head.append(tail.flatten) if head.is_a?(List)
685
- Cons.new(head, tail.flatten)
385
+ Sequence.new(head, tail.flatten)
686
386
  end
687
387
  end
688
388
 
689
- # Passes each item to the block, and gathers them into a {Hash} where the
690
- # keys are return values from the block, and the values are `List`s of items
691
- # for which the block returned that value.
692
- #
693
- # @return [Hash]
694
389
  def group_by(&block)
695
- group_by_with(EmptyList, &block)
696
- end
697
- alias :group :group_by
698
-
699
- # Retrieve the item at `index`. Negative indices count back from the end of
700
- # the list (-1 is the last item). If `index` is invalid (either too high or
701
- # too low), return `nil`.
702
- #
703
- # @param index [Integer] The index to retrieve
704
- # @return [Object]
705
- def at(index)
706
- index += size if index < 0
707
- return nil if index < 0
708
- node = self
709
- while index > 0
710
- node = node.tail
711
- index -= 1
390
+ return group_by { |item| item } unless block_given?
391
+ reduce(EmptyHash) do |hash, item|
392
+ key = yield(item)
393
+ hash.put(key, (hash.get(key) || EmptyList).cons(item))
712
394
  end
713
- node.head
714
395
  end
396
+ def_delegator :self, :group_by, :group
715
397
 
716
- # Element reference. Return the item at a specific index, or a specified,
717
- # contiguous range of items (as a new list).
718
- #
719
- # @overload list[index]
720
- # Return the item at `index`.
721
- # @param index [Integer] The index to retrieve.
722
- # @overload list[start, length]
723
- # Return a sublist starting at index `start` and continuing for `length` elements.
724
- # @param start [Integer] The index to start retrieving items from.
725
- # @param length [Integer] The number of items to retrieve.
726
- # @overload list[range]
727
- # Return a sublist specified by the given `range` of indices.
728
- # @param range [Range] The range of indices to retrieve.
729
- #
730
- # @return [Object]
731
- def [](arg, length = (missing_length = true))
732
- if missing_length
733
- if arg.is_a?(Range)
734
- from, to = arg.begin, arg.end
735
- from += size if from < 0
736
- return nil if from < 0
737
- to += size if to < 0
738
- to += 1 if !arg.exclude_end?
739
- length = to - from
740
- length = 0 if length < 0
741
- list = self
742
- while from > 0
743
- return nil if list.empty?
744
- list = list.tail
745
- from -= 1
746
- end
747
- list.take(length)
748
- else
749
- at(arg)
750
- end
751
- else
752
- return nil if length < 0
753
- arg += size if arg < 0
754
- return nil if arg < 0
755
- list = self
756
- while arg > 0
757
- return nil if list.empty?
758
- list = list.tail
759
- arg -= 1
760
- end
761
- list.take(length)
762
- end
398
+ def at(index)
399
+ drop(index).head
763
400
  end
764
- alias :slice :[]
765
401
 
766
- # Return a `List` of indices where the given object is found, or where the given
767
- # block returns true.
768
- #
769
- # @overload indices(obj)
770
- # Return a `List` of indices where `obj` is found. Use `#==` for testing equality.
771
- # @overload indices { |item| ... }
772
- # Pass each item successively to the block. Return a list of indices where the
773
- # block returns true.
774
- #
775
- # @return [List]
776
- def indices(object = Undefined, i = 0, &block)
777
- return indices { |item| item == object } if not block_given?
778
- return EmptyList if empty?
779
- LazyList.new do
780
- node = self
781
- while true
782
- break Cons.new(i, node.tail.indices(Undefined, i + 1, &block)) if yield(node.head)
783
- node = node.tail
784
- break EmptyList if node.empty?
785
- i += 1
786
- end
787
- end
402
+ def slice(from, length = Undefined)
403
+ return at(from) if length.equal?(Undefined)
404
+ drop(from).take(length)
788
405
  end
406
+ def_delegator :self, :slice, :[]
789
407
 
790
- # Merge all the nested lists into a single list, using the given comparator
791
- # block to determine the order which items should be shifted out of the nested
792
- # lists and into the output list. The comparator should take 2 parameters and
793
- # return 0, 1, or -1 if the first parameter is (respectively) equal to, greater
794
- # than, or less than the second parameter. Whichever nested list's `#head` is
795
- # determined to be "lowest" according to the comparator will be the first in
796
- # the merged `List`.
797
- #
798
- # @example
799
- # list_1 = Hamster::List[1, -3, -5]
800
- # list_2 = Hamster::List[-2, 4, 6]
801
- # Hamster::List[list_1, list_2].merge { |a,b| a.abs <=> b.abs }
802
- # # => Hamster::List[1, -2, -3, 4, -5, 6]
803
- #
804
- # @return [List]
805
- def merge(&comparator)
806
- return merge_by unless block_given?
807
- LazyList.new do
808
- sorted = reject(&:empty?).sort do |a, b|
809
- yield(a.head, b.head)
810
- end
811
- next EmptyList if sorted.empty?
812
- Cons.new(sorted.head.head, sorted.tail.cons(sorted.head.tail).merge(&comparator))
408
+ def find_index
409
+ return nil unless block_given?
410
+ i = 0
411
+ list = self
412
+ loop do
413
+ return nil if list.empty?
414
+ return i if yield(list.head)
415
+ i += 1
416
+ list = list.tail
813
417
  end
814
418
  end
815
419
 
816
- # Merge all the nested lists into a single list, using sort keys generated
817
- # by mapping the items in the nested lists through the given block to determine the
818
- # order which items should be shifted out of the nested lists and into the output
819
- # list. Whichever nested list's `#head` has the "lowest" sort key (according to
820
- # their natural order) will be the first in the merged `List`.
821
- #
822
- # @example
823
- # list_1 = Hamster::List[1, -3, -5]
824
- # list_2 = Hamster::List[-2, 4, 6]
825
- # Hamster::List[list_1, list_2].merge_by { |x| x.abs }
826
- # # => Hamster::List[1, -2, -3, 4, -5, 6]
827
- #
828
- # @return [List]
829
- def merge_by(&transformer)
830
- return merge_by { |item| item } unless block_given?
831
- LazyList.new do
832
- sorted = reject(&:empty?).sort_by do |list|
833
- yield(list.head)
834
- end
835
- next EmptyList if sorted.empty?
836
- Cons.new(sorted.head.head, sorted.tail.cons(sorted.head.tail).merge_by(&transformer))
837
- end
420
+ def elem_index(object)
421
+ find_index { |item| item == object }
838
422
  end
839
423
 
840
- # Return a randomly chosen element from this list.
841
- # @return [Object]
842
- def sample
843
- at(rand(size))
424
+ def index(object = Undefined, &block)
425
+ return elem_index(object) unless object.equal?(Undefined)
426
+ find_index(&block)
844
427
  end
845
428
 
846
- # Return a new `List` with the given items inserted before the item at `index`.
847
- #
848
- # @example
849
- # Hamster.list("A", "D", "E").insert(1, "B", "C") # => Hamster::List["A", "B", "C", "D", "E"]
850
- #
851
- # @param index [Integer] The index where the new items should go
852
- # @param items [Array] The items to add
853
- # @return [List]
854
- def insert(index, *items)
855
- if index == 0
856
- return items.to_list.append(self)
857
- elsif index > 0
858
- LazyList.new do
859
- Cons.new(head, tail.insert(index-1, *items))
860
- end
861
- else
862
- raise IndexError if index < -size
863
- insert(index + size, *items)
429
+ def find_indices(i = 0, &block)
430
+ return EmptyList unless block_given?
431
+ Stream.new do
432
+ next EmptyList if empty?
433
+ next Sequence.new(i, tail.find_indices(i + 1, &block)) if yield(head)
434
+ tail.find_indices(i + 1, &block)
864
435
  end
865
436
  end
866
437
 
867
- # Return a lazy list with all elements equal to `obj` removed. `#==` is used
868
- # for testing equality.
869
- #
870
- # @example
871
- # Hamster.list(:a, :b, :a, :a, :c).delete(:a) # => Hamster::List[:b, :c]
872
- #
873
- # @param obj [Object] The object to remove.
874
- # @return [List]
875
- def delete(obj)
876
- list = self
877
- list = list.tail while list.head == obj && !list.empty?
878
- return EmptyList if list.empty?
879
- LazyList.new { Cons.new(list.head, list.tail.delete(obj)) }
880
- end
881
-
882
- # Return a lazy list containing the same items, minus the one at `index`.
883
- # If `index` is negative, it counts back from the end of the list.
884
- #
885
- # @example
886
- # Hamster.list(1, 2, 3).delete_at(1) # => Hamster::List[1, 3]
887
- # Hamster.list(1, 2, 3).delete_at(-1) # => Hamster::List[1, 2]
888
- #
889
- # @param index [Integer] The index of the item to remove
890
- # @return [List]
891
- def delete_at(index)
892
- if index == 0
893
- tail
894
- elsif index < 0
895
- index += size if index < 0
896
- return self if index < 0
897
- delete_at(index)
898
- else
899
- LazyList.new { Cons.new(head, tail.delete_at(index - 1)) }
900
- end
438
+ def elem_indices(object)
439
+ find_indices { |item| item == object }
901
440
  end
902
441
 
903
- # Replace a range of indexes with the given object.
904
- #
905
- # @overload fill(obj)
906
- # Return a new `List` of the same size, with every item set to `obj`.
907
- # @overload fill(obj, start)
908
- # Return a new `List` with all indexes from `start` to the end of the
909
- # list set to `obj`.
910
- # @overload fill(obj, start, length)
911
- # Return a new `List` with `length` indexes, beginning from `start`,
912
- # set to `obj`.
913
- #
914
- # @example
915
- # list = Hamster.list("a", "b", "c", "d")
916
- # list.fill("x") # => Hamster::List["x", "x", "x", "x"]
917
- # list.fill("z", 2) # => Hamster::List["a", "b", "z", "z"]
918
- # list.fill("y", 0, 2) # => Hamster::List["y", "y", "c", "d"]
919
- #
920
- # @return [List]
921
- def fill(obj, index = 0, length = nil)
922
- if index == 0
923
- length ||= size
924
- if length > 0
925
- LazyList.new do
926
- Cons.new(obj, tail.fill(obj, 0, length-1))
927
- end
928
- else
929
- self
930
- end
931
- elsif index > 0
932
- LazyList.new do
933
- Cons.new(head, tail.fill(obj, index-1, length))
934
- end
935
- else
936
- raise IndexError if index < -size
937
- fill(obj, index + size, length)
938
- end
442
+ def indices(object = Undefined, &block)
443
+ return elem_indices(object) unless object.equal?(Undefined)
444
+ find_indices(&block)
939
445
  end
940
446
 
941
- # Yields all permutations of length `n` of the items in the list, and then
942
- # returns `self`. If no length `n` is specified, permutations of the entire
943
- # list will be yielded.
944
- #
945
- # There is no guarantee about which order the permutations will be yielded in.
946
- #
947
- # If no block is given, an `Enumerator` is returned instead.
948
- #
949
- # @example
950
- # Hamster.list(1, 2, 3).permutation.to_a
951
- # # => [Hamster::List[1, 2, 3],
952
- # # Hamster::List[2, 1, 3],
953
- # # Hamster::List[2, 3, 1],
954
- # # Hamster::List[1, 3, 2],
955
- # # Hamster::List[3, 1, 2],
956
- # # Hamster::List[3, 2, 1]]
957
- #
958
- # @return [self, Enumerator]
959
- def permutation(length = size, &block)
960
- return enum_for(:permutation, length) if not block_given?
961
- if length == 0
962
- yield EmptyList
963
- elsif length == 1
964
- each { |obj| yield Cons.new(obj, EmptyList) }
965
- elsif not empty?
966
- if length < size
967
- tail.permutation(length, &block)
968
- end
969
-
970
- tail.permutation(length-1) do |p|
971
- 0.upto(length-1) do |i|
972
- left,right = p.split_at(i)
973
- yield left.append(right.cons(head))
974
- end
447
+ def merge(&comparator)
448
+ return merge_by unless block_given?
449
+ Stream.new do
450
+ sorted = remove(&:empty?).sort do |a, b|
451
+ yield(a.head, b.head)
975
452
  end
453
+ next EmptyList if sorted.empty?
454
+ Sequence.new(sorted.head.head, sorted.tail.cons(sorted.head.tail).merge(&comparator))
976
455
  end
977
- self
978
456
  end
979
457
 
980
- # Yield every non-empty sublist to the given block. (The entire `List` also
981
- # counts as one sublist.)
982
- #
983
- # @example
984
- # Hamster.list(1, 2, 3).subsequences { |list| p list }
985
- # # prints:
986
- # # Hamster::List[1]
987
- # # Hamster::List[1, 2]
988
- # # Hamster::List[1, 2, 3]
989
- # # Hamster::List[2]
990
- # # Hamster::List[2, 3]
991
- # # Hamster::List[3]
992
- #
993
- # @yield [sublist] One or more contiguous elements from this list
994
- # @return [self]
995
- def subsequences(&block)
996
- return enum_for(:subsequences) if not block_given?
997
- if not empty?
998
- 1.upto(size) do |n|
999
- yield take(n)
458
+ def merge_by(&transformer)
459
+ return merge_by { |item| item } unless block_given?
460
+ Stream.new do
461
+ sorted = remove(&:empty?).sort_by do |list|
462
+ yield(list.head)
1000
463
  end
1001
- tail.subsequences(&block)
464
+ next EmptyList if sorted.empty?
465
+ Sequence.new(sorted.head.head, sorted.tail.cons(sorted.head.tail).merge_by(&transformer))
1002
466
  end
1003
- self
1004
467
  end
1005
468
 
1006
- # Return 2 `List`s, the first containing all the elements for which the block
1007
- # evaluates to true, the second containing the rest.
1008
- #
1009
- # @example
1010
- # Hamster.list(1, 2, 3, 4, 5, 6).partition { |x| x.even? }
1011
- # # => [Hamster::List[2, 4, 6], Hamster::List[1, 3, 5]]
1012
- #
1013
- # @return [List]
1014
- def partition(&block)
1015
- return enum_for(:partition) if not block_given?
1016
- partitioner = Partitioner.new(self, block)
1017
- mutex = Mutex.new
1018
- [Partitioned.new(partitioner, partitioner.left, mutex),
1019
- Partitioned.new(partitioner, partitioner.right, mutex)].freeze
1020
- end
1021
-
1022
- # Return true if `other` has the same type and contents as this `Hash`.
1023
- #
1024
- # @param other [Object] The collection to compare with
1025
- # @return [Boolean]
1026
469
  def eql?(other)
1027
470
  list = self
1028
471
  loop do
@@ -1035,96 +478,65 @@ module Hamster
1035
478
  other = other.tail
1036
479
  end
1037
480
  end
481
+ def_delegator :self, :eql?, :==
1038
482
 
1039
- # See `Object#hash`
1040
- # @return [Integer]
1041
483
  def hash
1042
484
  reduce(0) { |hash, item| (hash << 5) - hash + item.hash }
1043
485
  end
1044
486
 
1045
- # Return `self`.
1046
- # @return [List]
1047
487
  def dup
1048
488
  self
1049
489
  end
1050
- alias :clone :dup
490
+ def_delegator :self, :dup, :clone
1051
491
 
1052
- # Return `self`.
1053
- # @return [List]
1054
492
  def to_list
1055
493
  self
1056
494
  end
1057
495
 
1058
- # Return the contents of this `List` as a programmer-readable `String`. If all the
1059
- # items in the list are serializable as Ruby literal strings, the returned string can
1060
- # be passed to `eval` to reconstitute an equivalent `List`.
1061
- #
1062
- # @return [String]
1063
- def inspect
1064
- result = "Hamster::List["
1065
- each_with_index { |obj, i| result << ', ' if i > 0; result << obj.inspect }
1066
- result << "]"
496
+ def to_set
497
+ reduce(EmptySet) { |set, item| set.add(item) }
1067
498
  end
1068
499
 
1069
- # Allows this `List` to be printed at the `pry` console, or using `pp` (from the
1070
- # Ruby standard library), in a way which takes the amount of horizontal space on
1071
- # the screen into account, and which indents nested structures to make them easier
1072
- # to read.
1073
- #
1074
- # @private
1075
- def pretty_print(pp)
1076
- pp.group(1, "Hamster::List[", "]") do
1077
- pp.breakable ''
1078
- pp.seplist(self) { |obj| obj.pretty_print(pp) }
1079
- end
500
+ def inspect
501
+ to_a.inspect
1080
502
  end
1081
503
 
1082
- # @private
1083
504
  def respond_to?(name, include_private = false)
1084
505
  super || !!name.to_s.match(CADR)
1085
506
  end
1086
507
 
1087
- # Return `true` if the size of this list can be obtained in constant time (without
1088
- # traversing the list).
1089
- # @return [Integer]
1090
- def cached_size?
1091
- false
1092
- end
1093
-
1094
508
  private
1095
509
 
1096
510
  def method_missing(name, *args, &block)
1097
- if name.to_s.match(CADR)
1098
- # Perform compositions of car and cdr operations. Their names consist of a 'c',
1099
- # followed by at least one 'a' or 'd', and finally an 'r'. The series of 'a's and
1100
- # 'd's in the method name identify the series of car and cdr operations performed.
1101
- # The order in which the 'a's and 'd's appear is the inverse of the order in which
1102
- # the corresponding operations are performed.
1103
- code = "def #{name}; self."
1104
- code << Regexp.last_match[1].reverse.chars.map do |char|
1105
- {'a' => 'head', 'd' => 'tail'}[char]
1106
- end.join('.')
1107
- code << '; end'
1108
- List.class_eval(code)
1109
- send(name, *args, &block)
1110
- else
1111
- super
511
+ return accessor(Regexp.last_match[1]) if name.to_s.match(CADR)
512
+ super
513
+ end
514
+
515
+ # Perform compositions of <tt>car</tt> and <tt>cdr</tt> operations. Their names consist of a 'c', followed by at
516
+ # least one 'a' or 'd', and finally an 'r'. The series of 'a's and 'd's in each function's name is chosen to
517
+ # identify the series of car and cdr operations that is performed by the function. The order in which the 'a's and
518
+ # 'd's appear is the inverse of the order in which the corresponding operations are performed.
519
+ def accessor(sequence)
520
+ sequence.reverse.each_char.reduce(self) do |memo, char|
521
+ case char
522
+ when "a" then memo.head
523
+ when "d" then memo.tail
524
+ end
1112
525
  end
1113
526
  end
1114
527
  end
1115
528
 
1116
529
  # The basic building block for constructing lists
1117
530
  #
1118
- # A Cons, also known as a "cons cell", has a "head" and a "tail", where
1119
- # the head is an element in the list, and the tail is a reference to the
531
+ # A Sequence, also known as a "cons cell", has a +head+ and a +tail+, where
532
+ # the +head+ is an element in the list, and the +tail+ is a reference to the
1120
533
  # rest of the list. This way a singly linked list can be constructed, with
1121
- # each `Cons` holding a single element and a pointer to the next
1122
- # `Cons`.
534
+ # each +Sequence+ holding a single element and a pointer to the next
535
+ # +Sequence+.
1123
536
  #
1124
- # The last `Cons` instance in the chain has the {EmptyList} as its tail.
537
+ # The last +Sequence+ instance in the chain has the {EmptyList} as its tail.
1125
538
  #
1126
- # @private
1127
- class Cons
539
+ class Sequence
1128
540
  include List
1129
541
 
1130
542
  attr_reader :head, :tail
@@ -1132,292 +544,71 @@ module Hamster
1132
544
  def initialize(head, tail = EmptyList)
1133
545
  @head = head
1134
546
  @tail = tail
1135
- @size = tail.cached_size? ? tail.size + 1 : nil
1136
547
  end
1137
548
 
1138
549
  def empty?
1139
550
  false
1140
551
  end
1141
-
1142
- def size
1143
- @size ||= super
1144
- end
1145
- alias :length :size
1146
-
1147
- def cached_size?
1148
- @size != nil
1149
- end
1150
552
  end
1151
553
 
1152
- # A `LazyList` takes a block that returns a `List`, i.e. an object that responds
1153
- # to `#head`, `#tail` and `#empty?`. The list is only realized (i.e. the block is
1154
- # only called) when one of these operations is performed.
554
+ # Lazy list stream
555
+ #
556
+ # A +Stream+ takes a block that returns a +List+, i.e. an object that responds
557
+ # to +head+, +tail+ and +empty?+. The list is only realized when one of these
558
+ # operations is performed.
1155
559
  #
1156
- # By returning a `Cons` that in turn has a {LazyList} as its tail, one can
560
+ # By returning a +Sequence+ that in turn has a {Stream} as its +tail+, one can
1157
561
  # construct infinite lazy lists.
1158
562
  #
1159
- # @private
1160
- class LazyList
1161
- include List
1162
-
1163
- def initialize(&block)
1164
- @head = block # doubles as storage for block while yet unrealized
1165
- @tail = nil
1166
- @atomic = Atomic.new(0) # haven't yet run block
1167
- @size = nil
1168
- end
1169
-
1170
- def head
1171
- realize if @atomic.get != 2
1172
- @head
1173
- end
1174
- alias :first :head
1175
-
1176
- def tail
1177
- realize if @atomic.get != 2
1178
- @tail
1179
- end
1180
-
1181
- def empty?
1182
- realize if @atomic.get != 2
1183
- @size == 0
1184
- end
1185
-
1186
- def size
1187
- @size ||= super
1188
- end
1189
- alias :length :size
1190
-
1191
- def cached_size?
1192
- @size != nil
1193
- end
1194
-
1195
- private
1196
-
1197
- QUEUE = ConditionVariable.new
1198
- MUTEX = Mutex.new
1199
-
1200
- def realize
1201
- while true
1202
- # try to "claim" the right to run the block which realizes target
1203
- if @atomic.compare_and_swap(0,1) # full memory barrier here
1204
- begin
1205
- list = @head.call
1206
- if list.empty?
1207
- @head, @tail, @size = nil, self, 0
1208
- else
1209
- @head, @tail = list.head, list.tail
1210
- end
1211
- rescue
1212
- @atomic.set(0)
1213
- MUTEX.synchronize { QUEUE.broadcast }
1214
- raise
1215
- end
1216
- @atomic.set(2)
1217
- MUTEX.synchronize { QUEUE.broadcast }
1218
- return
1219
- end
1220
- # we failed to "claim" it, another thread must be running it
1221
- if @atomic.get == 1 # another thread is running the block
1222
- MUTEX.synchronize do
1223
- # check value of @atomic again, in case another thread already changed it
1224
- # *and* went past the call to QUEUE.broadcast before we got here
1225
- QUEUE.wait(MUTEX) if @atomic.get == 1
1226
- end
1227
- elsif @atomic.get == 2 # another thread finished the block
1228
- return
1229
- end
1230
- end
1231
- end
1232
- end
1233
-
1234
- # Common behavior for other classes which implement various kinds of lazy lists
1235
- # @private
1236
- class Realizable
1237
- include List
1238
-
1239
- def initialize
1240
- @head, @tail, @size = Undefined, Undefined, nil
1241
- end
1242
-
1243
- def head
1244
- realize if @head == Undefined
1245
- @head
1246
- end
1247
- alias :first :head
1248
-
1249
- def tail
1250
- realize if @tail == Undefined
1251
- @tail
1252
- end
1253
-
1254
- def empty?
1255
- realize if @head == Undefined
1256
- @size == 0
1257
- end
1258
-
1259
- def size
1260
- @size ||= super
1261
- end
1262
- alias :length :size
1263
-
1264
- def cached_size?
1265
- @size != nil
1266
- end
1267
-
1268
- def realized?
1269
- @head != Undefined
1270
- end
1271
- end
1272
-
1273
- # This class can divide a collection into 2 lazy lists, one of items
1274
- # for which the block returns true, and another for false
1275
- # At the same time, it guarantees the block will only be called ONCE for each item
563
+ # The recommended interface for using this is through {Hamster.stream Hamster.stream}
1276
564
  #
1277
- # @private
1278
- class Partitioner
1279
- attr_reader :left, :right
1280
- def initialize(list, block)
1281
- @list, @block, @left, @right = list, block, [], []
1282
- end
1283
-
1284
- def next_item
1285
- unless @list.empty?
1286
- item = @list.head
1287
- (@block.call(item) ? @left : @right) << item
1288
- @list = @list.tail
1289
- end
1290
- end
565
+ class Stream
566
+ extend Forwardable
1291
567
 
1292
- def done?
1293
- @list.empty?
1294
- end
1295
- end
1296
-
1297
- # One of the lazy lists which gets its items from a Partitioner
1298
- # @private
1299
- class Partitioned < Realizable
1300
- def initialize(partitioner, buffer, mutex)
1301
- super()
1302
- @partitioner, @buffer, @mutex = partitioner, buffer, mutex
1303
- end
1304
-
1305
- def realize
1306
- @mutex.synchronize do
1307
- return if @head != Undefined # another thread got ahead of us
1308
- while true
1309
- if !@buffer.empty?
1310
- @head = @buffer.shift
1311
- @tail = Partitioned.new(@partitioner, @buffer, @mutex)
1312
- # don't hold onto references
1313
- # tail will keep references alive until end of list is reached
1314
- @partitioner, @buffer, @mutex = nil, nil, nil
1315
- return
1316
- elsif @partitioner.done?
1317
- @head, @size, @tail = nil, 0, self
1318
- @partitioner, @buffer, @mutex = nil, nil, nil # allow them to be GC'd
1319
- return
1320
- else
1321
- @partitioner.next_item
1322
- end
1323
- end
1324
- end
1325
- end
1326
- end
568
+ include List
1327
569
 
1328
- # This class can divide a list up into 2 lazy lists, one for the prefix of elements
1329
- # for which the block returns true, and another for all the elements after that
1330
- # It guarantees that the block will only be called ONCE for each item
1331
- #
1332
- # @private
1333
- class Splitter
1334
- attr_reader :left, :right
1335
- def initialize(list, block)
1336
- @list, @block, @left, @right = list, block, [], EmptyList
1337
- end
1338
-
1339
- def next_item
1340
- unless @list.empty?
1341
- item = @list.head
1342
- if @block.call(item)
1343
- @left << item
1344
- @list = @list.tail
1345
- else
1346
- @right = @list
1347
- @list = EmptyList
1348
- end
1349
- end
570
+ def initialize(&block)
571
+ @block = block
572
+ @lock = Mutex.new
1350
573
  end
1351
574
 
1352
- def done?
1353
- @list.empty?
1354
- end
575
+ def_delegator :target, :head
576
+ def_delegator :target, :tail
577
+ def_delegator :target, :empty?
1355
578
 
1356
- # @private
1357
- class Left < Realizable
1358
- def initialize(splitter, buffer, mutex)
1359
- super()
1360
- @splitter, @buffer, @mutex = splitter, buffer, mutex
1361
- end
579
+ protected
1362
580
 
1363
- def realize
1364
- @mutex.synchronize do
1365
- return if @head != Undefined # another thread got ahead of us
1366
- while true
1367
- if !@buffer.empty?
1368
- @head = @buffer.shift
1369
- @tail = Left.new(@splitter, @buffer, @mutex)
1370
- @splitter, @buffer, @mutex = nil, nil, nil
1371
- return
1372
- elsif @splitter.done?
1373
- @head, @size, @tail = nil, 0, self
1374
- @splitter, @buffer, @mutex = nil, nil, nil
1375
- return
1376
- else
1377
- @splitter.next_item
1378
- end
1379
- end
581
+ def vivify
582
+ @lock.synchronize do
583
+ unless @block.nil?
584
+ @target = @block.call
585
+ @block = nil
1380
586
  end
1381
587
  end
588
+ @target
1382
589
  end
1383
590
 
1384
- # @private
1385
- class Right < Realizable
1386
- def initialize(splitter, mutex)
1387
- super()
1388
- @splitter, @mutex = splitter, mutex
1389
- end
591
+ private
1390
592
 
1391
- def realize
1392
- @mutex.synchronize do
1393
- return if @head != Undefined
1394
- @splitter.next_item until @splitter.done?
1395
- if @splitter.right.empty?
1396
- @head, @size, @tail = nil, 0, self
1397
- else
1398
- @head, @tail = @splitter.right.head, @splitter.right.tail
1399
- end
1400
- @splitter, @mutex = nil, nil
1401
- end
1402
- end
593
+ def target
594
+ list = vivify
595
+ list = list.vivify while list.is_a?(Stream)
596
+ list
1403
597
  end
1404
598
  end
1405
599
 
1406
- # A list without any elements. This is a singleton, since all empty lists are equivalent.
600
+ # A list without any elements
1407
601
  #
602
+ # This is a singleton, since all empty lists are equivalent. It is used
603
+ # as a terminating element in a chain of +Sequence+ instances.
1408
604
  module EmptyList
1409
605
  class << self
1410
606
  include List
1411
607
 
1412
- # There is no first item in an empty list, so return `nil`.
1413
- # @return [nil]
1414
608
  def head
1415
609
  nil
1416
610
  end
1417
- alias :first :head
1418
611
 
1419
- # There are no subsequent elements, so return an empty list.
1420
- # @return [self]
1421
612
  def tail
1422
613
  self
1423
614
  end
@@ -1425,17 +616,6 @@ module Hamster
1425
616
  def empty?
1426
617
  true
1427
618
  end
1428
-
1429
- # Return the number of items in this `List`.
1430
- # @return [Integer]
1431
- def size
1432
- 0
1433
- end
1434
- alias :length :size
1435
-
1436
- def cached_size?
1437
- true
1438
- end
1439
619
  end
1440
620
  end
1441
621
  end