hamster 1.0.1.pre.rc3 → 2.0.0

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 (358) hide show
  1. checksums.yaml +4 -4
  2. data/lib/hamster.rb +2 -0
  3. data/lib/hamster/associable.rb +49 -0
  4. data/lib/hamster/core_ext/enumerable.rb +3 -13
  5. data/lib/hamster/core_ext/io.rb +1 -1
  6. data/lib/hamster/core_ext/struct.rb +9 -0
  7. data/lib/hamster/deque.rb +57 -38
  8. data/lib/hamster/enumerable.rb +14 -41
  9. data/lib/hamster/experimental/mutable_queue.rb +5 -8
  10. data/lib/hamster/experimental/mutable_set.rb +6 -7
  11. data/lib/hamster/hash.rb +301 -110
  12. data/lib/hamster/immutable.rb +1 -1
  13. data/lib/hamster/list.rb +479 -194
  14. data/lib/hamster/mutable_hash.rb +6 -7
  15. data/lib/hamster/nested.rb +78 -0
  16. data/lib/hamster/read_copy_update.rb +1 -1
  17. data/lib/hamster/set.rb +198 -88
  18. data/lib/hamster/sorted_set.rb +706 -261
  19. data/lib/hamster/trie.rb +134 -15
  20. data/lib/hamster/vector.rb +571 -140
  21. data/lib/hamster/version.rb +3 -1
  22. data/spec/lib/hamster/associable/associable_spec.rb +150 -0
  23. data/spec/lib/hamster/core_ext/array_spec.rb +1 -1
  24. data/spec/lib/hamster/core_ext/enumerable_spec.rb +2 -2
  25. data/spec/lib/hamster/core_ext/io_spec.rb +1 -1
  26. data/spec/lib/hamster/deque/clear_spec.rb +3 -3
  27. data/spec/lib/hamster/deque/construction_spec.rb +8 -8
  28. data/spec/lib/hamster/deque/copying_spec.rb +1 -1
  29. data/spec/lib/hamster/deque/dequeue_spec.rb +12 -4
  30. data/spec/lib/hamster/deque/empty_spec.rb +14 -16
  31. data/spec/lib/hamster/deque/enqueue_spec.rb +4 -4
  32. data/spec/lib/hamster/deque/first_spec.rb +18 -0
  33. data/spec/lib/hamster/deque/inspect_spec.rb +1 -1
  34. data/spec/lib/hamster/deque/last_spec.rb +9 -11
  35. data/spec/lib/hamster/deque/marshal_spec.rb +6 -6
  36. data/spec/lib/hamster/deque/new_spec.rb +5 -5
  37. data/spec/lib/hamster/deque/pop_spec.rb +15 -3
  38. data/spec/lib/hamster/deque/pretty_print_spec.rb +24 -0
  39. data/spec/lib/hamster/deque/push_spec.rb +37 -0
  40. data/spec/lib/hamster/deque/shift_spec.rb +30 -0
  41. data/spec/lib/hamster/deque/size_spec.rb +1 -1
  42. data/spec/lib/hamster/deque/to_a_spec.rb +2 -2
  43. data/spec/lib/hamster/deque/to_ary_spec.rb +1 -1
  44. data/spec/lib/hamster/deque/to_list_spec.rb +3 -3
  45. data/spec/lib/hamster/deque/unshift_spec.rb +8 -3
  46. data/spec/lib/hamster/experimental/mutable_set/add_qm_spec.rb +3 -3
  47. data/spec/lib/hamster/experimental/mutable_set/add_spec.rb +3 -3
  48. data/spec/lib/hamster/experimental/mutable_set/delete_qm_spec.rb +3 -3
  49. data/spec/lib/hamster/experimental/mutable_set/delete_spec.rb +3 -3
  50. data/spec/lib/hamster/hash/all_spec.rb +32 -34
  51. data/spec/lib/hamster/hash/any_spec.rb +34 -36
  52. data/spec/lib/hamster/hash/assoc_spec.rb +3 -3
  53. data/spec/lib/hamster/hash/clear_spec.rb +4 -4
  54. data/spec/lib/hamster/hash/construction_spec.rb +8 -8
  55. data/spec/lib/hamster/hash/copying_spec.rb +1 -1
  56. data/spec/lib/hamster/hash/default_proc_spec.rb +3 -3
  57. data/spec/lib/hamster/hash/delete_spec.rb +4 -4
  58. data/spec/lib/hamster/hash/each_spec.rb +3 -3
  59. data/spec/lib/hamster/hash/each_with_index_spec.rb +1 -1
  60. data/spec/lib/hamster/hash/empty_spec.rb +13 -15
  61. data/spec/lib/hamster/hash/eql_spec.rb +4 -4
  62. data/spec/lib/hamster/hash/except_spec.rb +7 -7
  63. data/spec/lib/hamster/hash/fetch_spec.rb +10 -10
  64. data/spec/lib/hamster/hash/find_spec.rb +2 -2
  65. data/spec/lib/hamster/hash/flat_map_spec.rb +4 -4
  66. data/spec/lib/hamster/hash/flatten_spec.rb +13 -13
  67. data/spec/lib/hamster/hash/get_spec.rb +7 -7
  68. data/spec/lib/hamster/hash/has_key_spec.rb +3 -3
  69. data/spec/lib/hamster/hash/has_value_spec.rb +4 -4
  70. data/spec/lib/hamster/hash/hash_spec.rb +5 -5
  71. data/spec/lib/hamster/hash/inspect_spec.rb +2 -2
  72. data/spec/lib/hamster/hash/invert_spec.rb +6 -6
  73. data/spec/lib/hamster/hash/key_spec.rb +2 -2
  74. data/spec/lib/hamster/hash/keys_spec.rb +2 -2
  75. data/spec/lib/hamster/hash/map_spec.rb +4 -4
  76. data/spec/lib/hamster/hash/marshal_spec.rb +2 -2
  77. data/spec/lib/hamster/hash/merge_spec.rb +62 -56
  78. data/spec/lib/hamster/hash/min_max_spec.rb +9 -13
  79. data/spec/lib/hamster/hash/new_spec.rb +6 -6
  80. data/spec/lib/hamster/hash/none_spec.rb +3 -3
  81. data/spec/lib/hamster/hash/partition_spec.rb +2 -2
  82. data/spec/lib/hamster/hash/put_spec.rb +29 -7
  83. data/spec/lib/hamster/hash/reduce_spec.rb +4 -4
  84. data/spec/lib/hamster/hash/{remove_spec.rb → reject_spec.rb} +7 -7
  85. data/spec/lib/hamster/hash/reverse_each_spec.rb +1 -1
  86. data/spec/lib/hamster/hash/{filter_spec.rb → select_spec.rb} +6 -6
  87. data/spec/lib/hamster/hash/size_spec.rb +3 -3
  88. data/spec/lib/hamster/hash/slice_spec.rb +4 -4
  89. data/spec/lib/hamster/hash/sort_spec.rb +2 -2
  90. data/spec/lib/hamster/hash/store_spec.rb +29 -7
  91. data/spec/lib/hamster/hash/take_spec.rb +2 -2
  92. data/spec/lib/hamster/hash/to_a_spec.rb +1 -1
  93. data/spec/lib/hamster/hash/to_hash_spec.rb +4 -4
  94. data/spec/lib/hamster/hash/values_at_spec.rb +3 -3
  95. data/spec/lib/hamster/hash/values_spec.rb +2 -2
  96. data/spec/lib/hamster/immutable/new_spec.rb +14 -0
  97. data/spec/lib/hamster/list/add_spec.rb +16 -10
  98. data/spec/lib/hamster/list/all_spec.rb +33 -35
  99. data/spec/lib/hamster/list/any_spec.rb +29 -31
  100. data/spec/lib/hamster/list/append_spec.rb +6 -6
  101. data/spec/lib/hamster/list/at_spec.rb +1 -1
  102. data/spec/lib/hamster/list/break_spec.rb +4 -4
  103. data/spec/lib/hamster/list/cadr_spec.rb +9 -9
  104. data/spec/lib/hamster/list/chunk_spec.rb +5 -5
  105. data/spec/lib/hamster/list/clear_spec.rb +3 -3
  106. data/spec/lib/hamster/list/combination_spec.rb +3 -3
  107. data/spec/lib/hamster/list/compact_spec.rb +3 -3
  108. data/spec/lib/hamster/list/compare_spec.rb +3 -3
  109. data/spec/lib/hamster/list/cons_spec.rb +15 -17
  110. data/spec/lib/hamster/list/construction_spec.rb +20 -27
  111. data/spec/lib/hamster/list/copying_spec.rb +1 -1
  112. data/spec/lib/hamster/list/count_spec.rb +1 -1
  113. data/spec/lib/hamster/list/cycle_spec.rb +4 -4
  114. data/spec/lib/hamster/list/delete_at_spec.rb +4 -4
  115. data/spec/lib/hamster/list/drop_spec.rb +3 -3
  116. data/spec/lib/hamster/list/drop_while_spec.rb +3 -3
  117. data/spec/lib/hamster/list/each_slice_spec.rb +5 -5
  118. data/spec/lib/hamster/list/each_spec.rb +26 -28
  119. data/spec/lib/hamster/list/each_with_index_spec.rb +1 -1
  120. data/spec/lib/hamster/list/empty_spec.rb +13 -15
  121. data/spec/lib/hamster/list/eql_spec.rb +21 -21
  122. data/spec/lib/hamster/list/fill_spec.rb +8 -8
  123. data/spec/lib/hamster/list/find_all_spec.rb +3 -3
  124. data/spec/lib/hamster/list/find_index_spec.rb +1 -1
  125. data/spec/lib/hamster/list/find_spec.rb +1 -1
  126. data/spec/lib/hamster/list/flat_map_spec.rb +2 -2
  127. data/spec/lib/hamster/list/flatten_spec.rb +5 -5
  128. data/spec/lib/hamster/list/grep_spec.rb +4 -4
  129. data/spec/lib/hamster/list/group_by_spec.rb +6 -6
  130. data/spec/lib/hamster/list/hash_spec.rb +2 -2
  131. data/spec/lib/hamster/list/head_spec.rb +1 -1
  132. data/spec/lib/hamster/list/include_spec.rb +2 -2
  133. data/spec/lib/hamster/list/index_spec.rb +38 -0
  134. data/spec/lib/hamster/list/indices_spec.rb +62 -0
  135. data/spec/lib/hamster/list/init_spec.rb +3 -3
  136. data/spec/lib/hamster/list/inits_spec.rb +3 -3
  137. data/spec/lib/hamster/list/insert_spec.rb +1 -1
  138. data/spec/lib/hamster/list/inspect_spec.rb +1 -1
  139. data/spec/lib/hamster/list/intersperse_spec.rb +3 -3
  140. data/spec/lib/hamster/list/join_spec.rb +5 -5
  141. data/spec/lib/hamster/list/last_spec.rb +1 -1
  142. data/spec/lib/hamster/list/ltlt_spec.rb +20 -0
  143. data/spec/lib/hamster/list/map_spec.rb +4 -4
  144. data/spec/lib/hamster/list/maximum_spec.rb +24 -26
  145. data/spec/lib/hamster/list/merge_by_spec.rb +10 -10
  146. data/spec/lib/hamster/list/merge_spec.rb +10 -10
  147. data/spec/lib/hamster/list/minimum_spec.rb +24 -26
  148. data/spec/lib/hamster/list/multithreading_spec.rb +6 -6
  149. data/spec/lib/hamster/list/none_spec.rb +5 -5
  150. data/spec/lib/hamster/list/one_spec.rb +5 -5
  151. data/spec/lib/hamster/list/partition_spec.rb +8 -8
  152. data/spec/lib/hamster/list/permutation_spec.rb +8 -8
  153. data/spec/lib/hamster/list/pop_spec.rb +3 -3
  154. data/spec/lib/hamster/list/product_spec.rb +1 -1
  155. data/spec/lib/hamster/list/reduce_spec.rb +5 -48
  156. data/spec/lib/hamster/list/{remove_spec.rb → reject_spec.rb} +4 -4
  157. data/spec/lib/hamster/list/reverse_spec.rb +3 -3
  158. data/spec/lib/hamster/list/rotate_spec.rb +7 -7
  159. data/spec/lib/hamster/list/sample_spec.rb +1 -1
  160. data/spec/lib/hamster/list/select_spec.rb +3 -3
  161. data/spec/lib/hamster/list/size_spec.rb +1 -1
  162. data/spec/lib/hamster/list/slice_spec.rb +123 -123
  163. data/spec/lib/hamster/list/sorting_spec.rb +5 -5
  164. data/spec/lib/hamster/list/span_spec.rb +5 -5
  165. data/spec/lib/hamster/list/split_at_spec.rb +4 -4
  166. data/spec/lib/hamster/list/subsequences_spec.rb +1 -1
  167. data/spec/lib/hamster/list/sum_spec.rb +1 -1
  168. data/spec/lib/hamster/list/tail_spec.rb +4 -4
  169. data/spec/lib/hamster/list/tails_spec.rb +3 -3
  170. data/spec/lib/hamster/list/take_spec.rb +3 -3
  171. data/spec/lib/hamster/list/take_while_spec.rb +4 -4
  172. data/spec/lib/hamster/list/to_a_spec.rb +2 -2
  173. data/spec/lib/hamster/list/to_ary_spec.rb +1 -1
  174. data/spec/lib/hamster/list/to_list_spec.rb +1 -1
  175. data/spec/lib/hamster/list/to_set_spec.rb +1 -1
  176. data/spec/lib/hamster/list/union_spec.rb +4 -4
  177. data/spec/lib/hamster/list/uniq_spec.rb +23 -19
  178. data/spec/lib/hamster/list/zip_spec.rb +5 -5
  179. data/spec/lib/hamster/nested/construction_spec.rb +103 -0
  180. data/spec/lib/hamster/set/add_spec.rb +13 -11
  181. data/spec/lib/hamster/set/all_spec.rb +32 -34
  182. data/spec/lib/hamster/set/any_spec.rb +32 -34
  183. data/spec/lib/hamster/set/clear_spec.rb +3 -3
  184. data/spec/lib/hamster/set/compact_spec.rb +3 -3
  185. data/spec/lib/hamster/set/construction_spec.rb +3 -3
  186. data/spec/lib/hamster/set/copying_spec.rb +1 -1
  187. data/spec/lib/hamster/set/count_spec.rb +1 -1
  188. data/spec/lib/hamster/set/delete_spec.rb +8 -8
  189. data/spec/lib/hamster/set/difference_spec.rb +8 -8
  190. data/spec/lib/hamster/set/disjoint_spec.rb +1 -1
  191. data/spec/lib/hamster/set/each_spec.rb +2 -2
  192. data/spec/lib/hamster/set/empty_spec.rb +15 -17
  193. data/spec/lib/hamster/set/eqeq_spec.rb +3 -3
  194. data/spec/lib/hamster/set/eql_spec.rb +3 -3
  195. data/spec/lib/hamster/set/exclusion_spec.rb +7 -7
  196. data/spec/lib/hamster/set/find_spec.rb +2 -2
  197. data/spec/lib/hamster/set/first_spec.rb +29 -0
  198. data/spec/lib/hamster/set/flatten_spec.rb +9 -9
  199. data/spec/lib/hamster/set/grep_spec.rb +1 -1
  200. data/spec/lib/hamster/set/group_by_spec.rb +12 -12
  201. data/spec/lib/hamster/set/hash_spec.rb +3 -3
  202. data/spec/lib/hamster/set/include_spec.rb +8 -8
  203. data/spec/lib/hamster/set/inspect_spec.rb +2 -2
  204. data/spec/lib/hamster/set/intersect_spec.rb +1 -1
  205. data/spec/lib/hamster/set/intersection_spec.rb +13 -13
  206. data/spec/lib/hamster/set/join_spec.rb +6 -6
  207. data/spec/lib/hamster/set/map_spec.rb +7 -7
  208. data/spec/lib/hamster/set/marshal_spec.rb +2 -2
  209. data/spec/lib/hamster/set/maximum_spec.rb +22 -24
  210. data/spec/lib/hamster/set/minimum_spec.rb +22 -24
  211. data/spec/lib/hamster/set/new_spec.rb +5 -5
  212. data/spec/lib/hamster/set/none_spec.rb +5 -5
  213. data/spec/lib/hamster/set/one_spec.rb +6 -6
  214. data/spec/lib/hamster/set/partition_spec.rb +5 -5
  215. data/spec/lib/hamster/set/product_spec.rb +2 -2
  216. data/spec/lib/hamster/set/reduce_spec.rb +5 -5
  217. data/spec/lib/hamster/set/{remove_spec.rb → reject_spec.rb} +6 -6
  218. data/spec/lib/hamster/set/reverse_each_spec.rb +1 -1
  219. data/spec/lib/hamster/set/sample_spec.rb +1 -1
  220. data/spec/lib/hamster/set/{filter_spec.rb → select_spec.rb} +11 -11
  221. data/spec/lib/hamster/set/size_spec.rb +1 -1
  222. data/spec/lib/hamster/set/sorting_spec.rb +16 -5
  223. data/spec/lib/hamster/set/subset_spec.rb +2 -2
  224. data/spec/lib/hamster/set/sum_spec.rb +2 -2
  225. data/spec/lib/hamster/set/superset_spec.rb +2 -2
  226. data/spec/lib/hamster/set/to_a_spec.rb +2 -2
  227. data/spec/lib/hamster/set/to_list_spec.rb +2 -2
  228. data/spec/lib/hamster/set/to_set_spec.rb +1 -1
  229. data/spec/lib/hamster/set/union_spec.rb +23 -14
  230. data/spec/lib/hamster/sorted_set/above_spec.rb +11 -11
  231. data/spec/lib/hamster/sorted_set/add_spec.rb +8 -8
  232. data/spec/lib/hamster/sorted_set/at_spec.rb +1 -1
  233. data/spec/lib/hamster/sorted_set/below_spec.rb +11 -11
  234. data/spec/lib/hamster/sorted_set/between_spec.rb +11 -11
  235. data/spec/lib/hamster/sorted_set/clear_spec.rb +11 -2
  236. data/spec/lib/hamster/sorted_set/copying_spec.rb +21 -0
  237. data/spec/lib/hamster/sorted_set/delete_at_spec.rb +4 -4
  238. data/spec/lib/hamster/sorted_set/delete_spec.rb +21 -12
  239. data/spec/lib/hamster/sorted_set/difference_spec.rb +2 -2
  240. data/spec/lib/hamster/sorted_set/disjoint_spec.rb +1 -1
  241. data/spec/lib/hamster/sorted_set/drop_spec.rb +30 -3
  242. data/spec/lib/hamster/sorted_set/drop_while_spec.rb +4 -4
  243. data/spec/lib/hamster/sorted_set/each_spec.rb +16 -18
  244. data/spec/lib/hamster/sorted_set/empty_spec.rb +12 -14
  245. data/spec/lib/hamster/sorted_set/eql_spec.rb +5 -5
  246. data/spec/lib/hamster/sorted_set/exclusion_spec.rb +1 -1
  247. data/spec/lib/hamster/sorted_set/fetch_spec.rb +1 -1
  248. data/spec/lib/hamster/sorted_set/find_index_spec.rb +10 -2
  249. data/spec/lib/hamster/sorted_set/first_spec.rb +10 -12
  250. data/spec/lib/hamster/sorted_set/from_spec.rb +11 -11
  251. data/spec/lib/hamster/sorted_set/group_by_spec.rb +10 -10
  252. data/spec/lib/hamster/sorted_set/include_spec.rb +2 -2
  253. data/spec/lib/hamster/sorted_set/inspect_spec.rb +1 -1
  254. data/spec/lib/hamster/sorted_set/intersect_spec.rb +1 -1
  255. data/spec/lib/hamster/sorted_set/intersection_spec.rb +3 -3
  256. data/spec/lib/hamster/sorted_set/last_spec.rb +1 -1
  257. data/spec/lib/hamster/sorted_set/map_spec.rb +13 -5
  258. data/spec/lib/hamster/sorted_set/marshal_spec.rb +3 -3
  259. data/spec/lib/hamster/sorted_set/maximum_spec.rb +37 -0
  260. data/spec/lib/hamster/sorted_set/minimum_spec.rb +11 -13
  261. data/spec/lib/hamster/sorted_set/new_spec.rb +23 -3
  262. data/spec/lib/hamster/sorted_set/reverse_each_spec.rb +2 -2
  263. data/spec/lib/hamster/sorted_set/{filter_spec.rb → select_spec.rb} +10 -10
  264. data/spec/lib/hamster/sorted_set/size_spec.rb +1 -1
  265. data/spec/lib/hamster/sorted_set/slice_spec.rb +158 -142
  266. data/spec/lib/hamster/sorted_set/sorting_spec.rb +3 -3
  267. data/spec/lib/hamster/sorted_set/subset_spec.rb +2 -2
  268. data/spec/lib/hamster/sorted_set/superset_spec.rb +2 -2
  269. data/spec/lib/hamster/sorted_set/take_spec.rb +32 -3
  270. data/spec/lib/hamster/sorted_set/take_while_spec.rb +4 -4
  271. data/spec/lib/hamster/sorted_set/to_set_spec.rb +1 -1
  272. data/spec/lib/hamster/sorted_set/union_spec.rb +2 -2
  273. data/spec/lib/hamster/sorted_set/up_to_spec.rb +12 -11
  274. data/spec/lib/hamster/sorted_set/values_at_spec.rb +6 -6
  275. data/spec/lib/hamster/vector/add_spec.rb +3 -3
  276. data/spec/lib/hamster/vector/any_spec.rb +1 -1
  277. data/spec/lib/hamster/vector/assoc_spec.rb +11 -1
  278. data/spec/lib/hamster/vector/bsearch_spec.rb +10 -2
  279. data/spec/lib/hamster/vector/clear_spec.rb +3 -3
  280. data/spec/lib/hamster/vector/combination_spec.rb +4 -4
  281. data/spec/lib/hamster/vector/compact_spec.rb +2 -2
  282. data/spec/lib/hamster/vector/compare_spec.rb +3 -3
  283. data/spec/lib/hamster/vector/concat_spec.rb +2 -2
  284. data/spec/lib/hamster/vector/copying_spec.rb +1 -1
  285. data/spec/lib/hamster/vector/delete_at_spec.rb +8 -8
  286. data/spec/lib/hamster/vector/delete_spec.rb +2 -2
  287. data/spec/lib/hamster/vector/drop_spec.rb +10 -3
  288. data/spec/lib/hamster/vector/drop_while_spec.rb +5 -5
  289. data/spec/lib/hamster/vector/each_index_spec.rb +2 -2
  290. data/spec/lib/hamster/vector/each_spec.rb +27 -29
  291. data/spec/lib/hamster/vector/each_with_index_spec.rb +2 -2
  292. data/spec/lib/hamster/vector/empty_spec.rb +11 -13
  293. data/spec/lib/hamster/vector/eql_spec.rb +6 -6
  294. data/spec/lib/hamster/vector/fetch_spec.rb +1 -1
  295. data/spec/lib/hamster/vector/fill_spec.rb +9 -9
  296. data/spec/lib/hamster/vector/first_spec.rb +10 -12
  297. data/spec/lib/hamster/vector/flat_map_spec.rb +51 -0
  298. data/spec/lib/hamster/vector/flatten_spec.rb +15 -0
  299. data/spec/lib/hamster/vector/get_spec.rb +4 -4
  300. data/spec/lib/hamster/vector/group_by_spec.rb +12 -12
  301. data/spec/lib/hamster/vector/include_spec.rb +2 -2
  302. data/spec/lib/hamster/vector/insert_spec.rb +2 -2
  303. data/spec/lib/hamster/vector/inspect_spec.rb +1 -1
  304. data/spec/lib/hamster/vector/join_spec.rb +5 -5
  305. data/spec/lib/hamster/vector/last_spec.rb +1 -1
  306. data/spec/lib/hamster/vector/length_spec.rb +1 -1
  307. data/spec/lib/hamster/vector/ltlt_spec.rb +2 -2
  308. data/spec/lib/hamster/vector/map_spec.rb +5 -5
  309. data/spec/lib/hamster/vector/marshal_spec.rb +2 -2
  310. data/spec/lib/hamster/vector/maximum_spec.rb +20 -22
  311. data/spec/lib/hamster/vector/minimum_spec.rb +20 -22
  312. data/spec/lib/hamster/vector/multiply_spec.rb +4 -4
  313. data/spec/lib/hamster/vector/partition_spec.rb +5 -5
  314. data/spec/lib/hamster/vector/permutation_spec.rb +4 -4
  315. data/spec/lib/hamster/vector/pop_spec.rb +3 -3
  316. data/spec/lib/hamster/vector/product_spec.rb +10 -10
  317. data/spec/lib/hamster/vector/put_spec.rb +175 -0
  318. data/spec/lib/hamster/vector/reduce_spec.rb +5 -57
  319. data/spec/lib/hamster/vector/{remove_spec.rb → reject_spec.rb} +4 -4
  320. data/spec/lib/hamster/vector/repeated_combination_spec.rb +4 -4
  321. data/spec/lib/hamster/vector/repeated_permutation_spec.rb +6 -6
  322. data/spec/lib/hamster/vector/reverse_each_spec.rb +1 -1
  323. data/spec/lib/hamster/vector/reverse_spec.rb +1 -1
  324. data/spec/lib/hamster/vector/rindex_spec.rb +1 -1
  325. data/spec/lib/hamster/vector/rotate_spec.rb +9 -9
  326. data/spec/lib/hamster/vector/sample_spec.rb +1 -1
  327. data/spec/lib/hamster/vector/{filter_spec.rb → select_spec.rb} +8 -8
  328. data/spec/lib/hamster/vector/set_spec.rb +12 -141
  329. data/spec/lib/hamster/vector/shift_spec.rb +3 -3
  330. data/spec/lib/hamster/vector/shuffle_spec.rb +2 -2
  331. data/spec/lib/hamster/vector/slice_spec.rb +137 -137
  332. data/spec/lib/hamster/vector/sorting_spec.rb +5 -5
  333. data/spec/lib/hamster/vector/sum_spec.rb +1 -1
  334. data/spec/lib/hamster/vector/take_spec.rb +17 -3
  335. data/spec/lib/hamster/vector/take_while_spec.rb +4 -4
  336. data/spec/lib/hamster/vector/to_a_spec.rb +1 -1
  337. data/spec/lib/hamster/vector/to_ary_spec.rb +1 -1
  338. data/spec/lib/hamster/vector/to_list_spec.rb +2 -1
  339. data/spec/lib/hamster/vector/to_set_spec.rb +1 -1
  340. data/spec/lib/hamster/vector/uniq_spec.rb +27 -6
  341. data/spec/lib/hamster/vector/unshift_spec.rb +3 -3
  342. data/spec/lib/hamster/vector/values_at_spec.rb +6 -6
  343. data/spec/lib/hamster/vector/zip_spec.rb +2 -2
  344. data/spec/lib/load_spec.rb +42 -0
  345. data/spec/spec_helper.rb +25 -0
  346. metadata +85 -48
  347. data/spec/lib/hamster/deque/head_spec.rb +0 -20
  348. data/spec/lib/hamster/hash/uniq_spec.rb +0 -14
  349. data/spec/lib/hamster/list/elem_index_spec.rb +0 -36
  350. data/spec/lib/hamster/list/elem_indices_spec.rb +0 -31
  351. data/spec/lib/hamster/list/filter_spec.rb +0 -71
  352. data/spec/lib/hamster/list/find_indices_spec.rb +0 -37
  353. data/spec/lib/hamster/set/foreach_spec.rb +0 -40
  354. data/spec/lib/hamster/set/head_spec.rb +0 -31
  355. data/spec/lib/hamster/set/uniq_spec.rb +0 -14
  356. data/spec/lib/hamster/sorted_set/construction_spec.rb +0 -29
  357. data/spec/lib/hamster/vector/exist_spec.rb +0 -70
  358. data/spec/lib/hamster/vector/exists_spec.rb +0 -70
@@ -11,7 +11,7 @@ module Hamster
11
11
  # @private
12
12
  module ClassMethods
13
13
  def new(*args)
14
- super.immutable!
14
+ super.__send__(:immutable!)
15
15
  end
16
16
 
17
17
  def memoize(*names)
@@ -1,27 +1,14 @@
1
- require "forwardable"
2
1
  require "thread"
3
- require "atomic"
4
2
  require "set"
3
+ require "concurrent/atomics"
5
4
 
6
- require "hamster/core_ext/enumerable"
7
5
  require "hamster/undefined"
8
6
  require "hamster/enumerable"
7
+ require "hamster/hash"
9
8
  require "hamster/set"
10
9
 
11
10
  module Hamster
12
11
  class << self
13
- extend Forwardable
14
-
15
- # Create a list containing the given items.
16
- #
17
- # @example
18
- # list = Hamster.list(:a, :b, :c)
19
- # # => [:a, :b, :c]
20
- #
21
- # @return [List]
22
- def list(*items)
23
- items.to_list
24
- end
25
12
 
26
13
  # Create a lazy, infinite list.
27
14
  #
@@ -29,7 +16,7 @@ module Hamster
29
16
  #
30
17
  # @example
31
18
  # Hamster.stream { :hello }.take(3)
32
- # # => [:hello, :hello, :hello]
19
+ # # => Hamster::List[:hello, :hello, :hello]
33
20
  #
34
21
  # @return [List]
35
22
  def stream(&block)
@@ -41,7 +28,7 @@ module Hamster
41
28
  #
42
29
  # @example
43
30
  # Hamster.interval(5,9)
44
- # # => [5, 6, 7, 8, 9]
31
+ # # => Hamster::List[5, 6, 7, 8, 9]
45
32
  #
46
33
  # @param from [Integer] Start value, inclusive
47
34
  # @param to [Integer] End value, inclusive
@@ -50,13 +37,12 @@ module Hamster
50
37
  return EmptyList if from > to
51
38
  interval_exclusive(from, to.next)
52
39
  end
53
- def_delegator :self, :interval, :range
54
40
 
55
41
  # Create an infinite list repeating the same item indefinitely
56
42
  #
57
43
  # @example
58
44
  # Hamster.repeat(:chunky).take(4)
59
- # => [:chunky, :chunky, :chunky, :chunky]
45
+ # => Hamster::List[:chunky, :chunky, :chunky, :chunky]
60
46
  #
61
47
  # @return [List]
62
48
  def repeat(item)
@@ -66,8 +52,8 @@ module Hamster
66
52
  # Create a list that contains a given item a fixed number of times
67
53
  #
68
54
  # @example
69
- # Hamster.replicate(3).(:hamster)
70
- # #=> [:hamster, :hamster, :hamster]
55
+ # Hamster.replicate(3, :hamster)
56
+ # #=> Hamster::List[:hamster, :hamster, :hamster]
71
57
  #
72
58
  # @return [List]
73
59
  def replicate(number, item)
@@ -79,18 +65,18 @@ module Hamster
79
65
  #
80
66
  # @example
81
67
  # Hamster.iterate(0) { |i| i.next }.take(5)
82
- # # => [0, 1, 2, 3, 4]
68
+ # # => Hamster::List[0, 1, 2, 3, 4]
83
69
  #
84
- # @param item [Object] Starting value
85
- # @yieldparam [Object] The previous value
70
+ # @param [Object] item Starting value
71
+ # @yieldparam [Object] previous The previous value
86
72
  # @yieldreturn [Object] The next value
87
73
  # @return [List]
88
74
  def iterate(item, &block)
89
75
  LazyList.new { Cons.new(item, iterate(yield(item), &block)) }
90
76
  end
91
77
 
92
- # Turn an Enumerator into a `Hamster::List`. The result is a lazy collection
93
- # where the values are memoized as they are generated.
78
+ # Turn an `Enumerator` into a `Hamster::List`. The result is a lazy
79
+ # collection where the values are memoized as they are generated.
94
80
  #
95
81
  # If your code uses multiple threads, you need to make sure that the returned
96
82
  # lazy collection is realized on a single thread only. Otherwise, a `FiberError`
@@ -121,29 +107,58 @@ module Hamster
121
107
  end
122
108
  end
123
109
 
124
- # A `List` can be constructed with {Hamster.list Hamster.list} or {List.[] List[]}.
110
+ # A `List` can be constructed with {List.[] List[]}, or {Enumerable#to_list}.
125
111
  # It consists of a *head* (the first element) and a *tail* (which itself is also
126
112
  # a `List`, containing all the remaining elements).
127
113
  #
128
- # This is a singly linked list. Prepending to the list with {List#cons} runs
114
+ # This is a singly linked list. Prepending to the list with {List#add} runs
129
115
  # in constant time. Traversing the list from front to back is efficient,
130
116
  # however, indexed access runs in linear time because the list needs to be
131
117
  # traversed to find the element.
132
118
  #
133
119
  module List
134
- extend Forwardable
135
120
  include Enumerable
136
121
 
137
122
  # @private
138
123
  CADR = /^c([ad]+)r$/
139
124
 
140
- def_delegator :self, :head, :first
141
- def_delegator :self, :empty?, :null?
142
-
143
125
  # Create a new `List` populated with the given items.
144
- # @return [Set]
126
+ #
127
+ # @example
128
+ # list = Hamster::List[:a, :b, :c]
129
+ # # => Hamster::List[:a, :b, :c]
130
+ #
131
+ # @return [List]
145
132
  def self.[](*items)
146
- items.to_list
133
+ from_enum(items)
134
+ end
135
+
136
+ # Return an empty `List`.
137
+ #
138
+ # @return [List]
139
+ def self.empty
140
+ EmptyList
141
+ end
142
+
143
+ # This method exists distinct from `.[]` since it is ~30% faster
144
+ # than splatting the argument.
145
+ #
146
+ # Marking as private only because it was introduced for an internal
147
+ # refactoring. It could potentially be made public with a good name.
148
+ #
149
+ # @private
150
+ def self.from_enum(items)
151
+ # use destructive operations to build up a new list, like Common Lisp's NCONC
152
+ # this is a very fast way to build up a linked list
153
+ list = tail = Hamster::Cons.allocate
154
+ items.each do |item|
155
+ new_node = Hamster::Cons.allocate
156
+ new_node.instance_variable_set(:@head, item)
157
+ tail.instance_variable_set(:@tail, new_node)
158
+ tail = new_node
159
+ end
160
+ tail.instance_variable_set(:@tail, Hamster::EmptyList)
161
+ list.tail
147
162
  end
148
163
 
149
164
  # Return the number of items in this `List`.
@@ -160,30 +175,41 @@ module Hamster
160
175
  end
161
176
  result
162
177
  end
163
- def_delegator :self, :size, :length
178
+ alias :length :size
164
179
 
165
- # Create a new `List` with `item` added at the front.
180
+ # Create a new `List` with `item` added at the front. This is a constant
181
+ # time operation.
182
+ #
183
+ # @example
184
+ # Hamster::List[:b, :c].add(:a)
185
+ # # => Hamster::List[:a, :b, :c]
186
+ #
166
187
  # @param item [Object] The item to add
167
188
  # @return [List]
168
- def cons(item)
189
+ def add(item)
169
190
  Cons.new(item, self)
170
191
  end
171
- def_delegator :self, :cons, :>>
172
- def_delegator :self, :cons, :conj
173
- def_delegator :self, :cons, :conjoin
192
+ alias :cons :add
174
193
 
175
- # Create a new `List` with `item` added at the end.
194
+ # Create a new `List` with `item` added at the end. This is much less efficient
195
+ # than adding items at the front.
196
+ #
197
+ # @example
198
+ # Hamster::List[:a, :b] << :c
199
+ # # => Hamster::List[:a, :b, :c]
200
+ #
176
201
  # @param item [Object] The item to add
177
202
  # @return [List]
178
- def add(item)
179
- append(Hamster.list(item))
203
+ def <<(item)
204
+ append(List[item])
180
205
  end
181
- def_delegator :self, :add, :<<
182
206
 
183
207
  # Call the given block once for each item in the list, passing each
184
- # item from first to last successively to the block.
208
+ # item from first to last successively to the block. If no block is given,
209
+ # returns an `Enumerator`.
185
210
  #
186
211
  # @return [self]
212
+ # @yield [item]
187
213
  def each
188
214
  return to_enum unless block_given?
189
215
  list = self
@@ -193,10 +219,15 @@ module Hamster
193
219
  end
194
220
  end
195
221
 
196
- # Return a lazy list in which each element is derived from the corresponding
197
- # element in this `List`, transformed through the given block.
222
+ # Return a `List` in which each element is derived from the corresponding
223
+ # element in this `List`, transformed through the given block. If no block
224
+ # is given, returns an `Enumerator`.
198
225
  #
199
- # @return [List]
226
+ # @example
227
+ # Hamster::List[3, 2, 1].map { |e| e * e } # => Hamster::List[9, 4, 1]
228
+ #
229
+ # @return [List, Enumerator]
230
+ # @yield [item]
200
231
  def map(&block)
201
232
  return enum_for(:map) unless block_given?
202
233
  LazyList.new do
@@ -204,42 +235,58 @@ module Hamster
204
235
  Cons.new(yield(head), tail.map(&block))
205
236
  end
206
237
  end
207
- def_delegator :self, :map, :collect
238
+ alias :collect :map
208
239
 
209
- # Return a lazy list which is realized by transforming each item into a `List`,
240
+ # Return a `List` which is realized by transforming each item into a `List`,
210
241
  # and flattening the resulting lists.
211
242
  #
243
+ # @example
244
+ # Hamster::List[1, 2, 3].flat_map { |x| Hamster::List[x, 100] }
245
+ # # => Hamster::List[1, 100, 2, 100, 3, 100]
246
+ #
212
247
  # @return [List]
213
248
  def flat_map(&block)
214
249
  return enum_for(:flat_map) unless block_given?
215
250
  LazyList.new do
216
251
  next self if empty?
217
- head_list = Hamster.list(*yield(head))
252
+ head_list = List.from_enum(yield(head))
218
253
  next tail.flat_map(&block) if head_list.empty?
219
254
  Cons.new(head_list.first, head_list.drop(1).append(tail.flat_map(&block)))
220
255
  end
221
256
  end
222
257
 
223
- # Return a lazy list which contains all the items for which the given block
258
+ # Return a `List` which contains all the items for which the given block
224
259
  # returns true.
225
260
  #
261
+ # @example
262
+ # Hamster::List["Bird", "Cow", "Elephant"].select { |e| e.size >= 4 }
263
+ # # => Hamster::List["Bird", "Elephant"]
264
+ #
226
265
  # @return [List]
227
- def filter(&block)
228
- return enum_for(:filter) unless block_given?
266
+ # @yield [item] Once for each item.
267
+ def select(&block)
268
+ return enum_for(:select) unless block_given?
229
269
  LazyList.new do
230
270
  list = self
231
271
  while true
232
272
  break list if list.empty?
233
- break Cons.new(list.head, list.tail.filter(&block)) if yield(list.head)
273
+ break Cons.new(list.head, list.tail.select(&block)) if yield(list.head)
234
274
  list = list.tail
235
275
  end
236
276
  end
237
277
  end
278
+ alias :find_all :select
279
+ alias :keep_if :select
238
280
 
239
- # Return a lazy list which contains all elements up to, but not including, the
281
+ # Return a `List` which contains all elements up to, but not including, the
240
282
  # first element for which the block returns `nil` or `false`.
241
283
  #
284
+ # @example
285
+ # Hamster::List[1, 3, 5, 7, 6, 4, 2].take_while { |e| e < 5 }
286
+ # # => Hamster::List[1, 3]
287
+ #
242
288
  # @return [List, Enumerator]
289
+ # @yield [item]
243
290
  def take_while(&block)
244
291
  return enum_for(:take_while) unless block_given?
245
292
  LazyList.new do
@@ -249,10 +296,15 @@ module Hamster
249
296
  end
250
297
  end
251
298
 
252
- # Return a lazy list which contains all elements starting from the
299
+ # Return a `List` which contains all elements starting from the
253
300
  # first element for which the block returns `nil` or `false`.
254
301
  #
302
+ # @example
303
+ # Hamster::List[1, 3, 5, 7, 6, 4, 2].drop_while { |e| e < 5 }
304
+ # # => Hamster::List[5, 7, 6, 4, 2]
305
+ #
255
306
  # @return [List, Enumerator]
307
+ # @yield [item]
256
308
  def drop_while(&block)
257
309
  return enum_for(:drop_while) unless block_given?
258
310
  LazyList.new do
@@ -262,7 +314,12 @@ module Hamster
262
314
  end
263
315
  end
264
316
 
265
- # Return a lazy list containing the first `number` items from this `List`.
317
+ # Return a `List` containing the first `number` items from this `List`.
318
+ #
319
+ # @example
320
+ # Hamster::List[1, 3, 5, 7, 6, 4, 2].take(3)
321
+ # # => Hamster::List[1, 3, 5]
322
+ #
266
323
  # @param number [Integer] The number of items to retain
267
324
  # @return [List]
268
325
  def take(number)
@@ -273,7 +330,11 @@ module Hamster
273
330
  end
274
331
  end
275
332
 
276
- # Return a lazy list containing all but the last item from this `List`.
333
+ # Return a `List` containing all but the last item from this `List`.
334
+ #
335
+ # @example
336
+ # Hamster::List["A", "B", "C"].pop # => Hamster::List["A", "B"]
337
+ #
277
338
  # @return [List]
278
339
  def pop
279
340
  LazyList.new do
@@ -284,8 +345,13 @@ module Hamster
284
345
  end
285
346
  end
286
347
 
287
- # Return a lazy list containing all items after the first `number` items from
348
+ # Return a `List` containing all items after the first `number` items from
288
349
  # this `List`.
350
+ #
351
+ # @example
352
+ # Hamster::List[1, 3, 5, 7, 6, 4, 2].drop(3)
353
+ # # => Hamster::List[7, 6, 4, 2]
354
+ #
289
355
  # @param number [Integer] The number of items to skip over
290
356
  # @return [List]
291
357
  def drop(number)
@@ -299,9 +365,13 @@ module Hamster
299
365
  end
300
366
  end
301
367
 
302
- # Return a lazy list with all items from this `List`, followed by all items from
368
+ # Return a `List` with all items from this `List`, followed by all items from
303
369
  # `other`.
304
370
  #
371
+ # @example
372
+ # Hamster::List[1, 2, 3].append(Hamster::List[4, 5])
373
+ # # => Hamster::List[1, 2, 3, 4, 5]
374
+ #
305
375
  # @param other [List] The list to add onto the end of this one
306
376
  # @return [List]
307
377
  def append(other)
@@ -310,21 +380,31 @@ module Hamster
310
380
  Cons.new(head, tail.append(other))
311
381
  end
312
382
  end
313
- def_delegator :self, :append, :concat
314
- def_delegator :self, :append, :cat
315
- def_delegator :self, :append, :+
383
+ alias :concat :append
384
+ alias :+ :append
316
385
 
317
386
  # Return a `List` with the same items, but in reverse order.
387
+ #
388
+ # @example
389
+ # Hamster::List["A", "B", "C"].reverse # => Hamster::List["C", "B", "A"]
390
+ #
318
391
  # @return [List]
319
392
  def reverse
320
393
  LazyList.new { reduce(EmptyList) { |list, item| list.cons(item) }}
321
394
  end
322
395
 
323
- # Gather the corresponding elements from this `List` and `others` (that is,
324
- # the elements with the same indices) into new 2-element lists. Return a
325
- # lazy list of these 2-element lists.
396
+ # Combine two lists by "zipping" them together. The corresponding elements
397
+ # from this `List` and each of `others` (that is, the elements with the
398
+ # same indices) will be gathered into lists.
326
399
  #
327
- # @param others [List] A list of the lists to zip together with this one
400
+ # If `others` contains fewer elements than this list, `nil` will be used
401
+ # for padding.
402
+ #
403
+ # @example
404
+ # Hamster::List["A", "B", "C"].zip(Hamster::List[1, 2, 3])
405
+ # # => Hamster::List[Hamster::List["A", 1], Hamster::List["B", 2], Hamster::List["C", 3]]
406
+ #
407
+ # @param others [List] The list to zip together with this one
328
408
  # @return [List]
329
409
  def zip(others)
330
410
  LazyList.new do
@@ -335,7 +415,7 @@ module Hamster
335
415
 
336
416
  # Gather the first element of each nested list into a new `List`, then the second
337
417
  # element of each nested list, then the third, and so on. In other words, if each
338
- # nested list is a "row", return a lazy list of "columns" instead.
418
+ # nested list is a "row", return a `List` of "columns" instead.
339
419
  #
340
420
  # Although the returned list is lazy, each returned nested list (each "column")
341
421
  # is strict. So while each nested list in the input can be infinite, the parent
@@ -349,7 +429,7 @@ module Hamster
349
429
  # list3 = Hamster.iterate(3) { |n| n * 3 }
350
430
  #
351
431
  # # Now we transpose our 3 infinite "rows" into an infinite series of 3-element "columns"
352
- # Hamster.list(list1, list2, list3).transpose.take(4)
432
+ # Hamster::List[list1, list2, list3].transpose.take(4)
353
433
  # # => Hamster::List[
354
434
  # # Hamster::List[1, 2, 3],
355
435
  # # Hamster::List[2, 4, 9],
@@ -367,8 +447,12 @@ module Hamster
367
447
  end
368
448
  end
369
449
 
370
- # Concatenate an infinite series of copies of this `List` together (into a
371
- # new lazy list). Or, if empty, just return an empty list.
450
+ # Concatenate an infinite series of copies of this `List` together into a
451
+ # new `List`. Or, if empty, just return an empty list.
452
+ #
453
+ # @example
454
+ # Hamster::List[1, 2, 3].cycle.take(10)
455
+ # # => Hamster::List[1, 2, 3, 1, 2, 3, 1, 2, 3, 1]
372
456
  #
373
457
  # @return [List]
374
458
  def cycle
@@ -384,27 +468,43 @@ module Hamster
384
468
  # will be moved to the end. If `count` is negative, the elements will be shifted
385
469
  # right, and those shifted past the last position will be moved to the beginning.
386
470
  #
471
+ # @example
472
+ # l = Hamster::List["A", "B", "C", "D", "E", "F"]
473
+ # l.rotate(2) # => Hamster::List["C", "D", "E", "F", "A", "B"]
474
+ # l.rotate(-1) # => Hamster::List["F", "A", "B", "C", "D", "E"]
475
+ #
387
476
  # @param count [Integer] The number of positions to shift items by
388
477
  # @return [Vector]
478
+ # @raise [TypeError] if count is not an integer.
389
479
  def rotate(count = 1)
390
480
  raise TypeError, "expected Integer" if not count.is_a?(Integer)
391
- return self if empty? || (count % size) == 0
481
+ return self if empty? || (count % size) == 0
392
482
  count = (count >= 0) ? count % size : (size - (~count % size) - 1)
393
483
  drop(count).append(take(count))
394
484
  end
395
485
 
396
- # Return 2 `List`s, one of the first `number` items, and another of all the
397
- # remaining items.
486
+ # Return two `List`s, one of the first `number` items, and another with the
487
+ # remaining.
488
+ #
489
+ # @example
490
+ # Hamster::List["a", "b", "c", "d"].split_at(2)
491
+ # # => [Hamster::List["a", "b"], Hamster::List["c", "d"]]
492
+ #
398
493
  # @param number [Integer] The index at which to split this list
399
494
  # @return [Array]
400
495
  def split_at(number)
401
496
  [take(number), drop(number)].freeze
402
497
  end
403
498
 
404
- # Return 2 `List`s, one up to (but not including) the first item for which the
499
+ # Return two `List`s, one up to (but not including) the first item for which the
405
500
  # block returns `nil` or `false`, and another of all the remaining items.
406
501
  #
502
+ # @example
503
+ # Hamster::List[4, 3, 5, 2, 1].span { |x| x > 2 }
504
+ # # => [Hamster::List[4, 3, 5], Hamster::List[2, 1]]
505
+ #
407
506
  # @return [Array]
507
+ # @yield [item]
408
508
  def span(&block)
409
509
  return [self, EmptyList].freeze unless block_given?
410
510
  splitter = Splitter.new(self, block)
@@ -413,46 +513,75 @@ module Hamster
413
513
  Splitter::Right.new(splitter, mutex)].freeze
414
514
  end
415
515
 
416
- # Return 2 `List`s, one up to (but not including) the first item for which the
516
+ # Return two `List`s, one up to (but not including) the first item for which the
417
517
  # block returns true, and another of all the remaining items.
418
518
  #
519
+ # @example
520
+ # Hamster::List[1, 3, 4, 2, 5].break { |x| x > 3 }
521
+ # # => [Hamster::List[1, 3], Hamster::List[4, 2, 5]]
522
+ #
419
523
  # @return [Array]
524
+ # @yield [item]
420
525
  def break(&block)
421
526
  return span unless block_given?
422
527
  span { |item| !yield(item) }
423
528
  end
424
529
 
425
- # Return an empty `List`.
530
+ # Return an empty `List`. If used on a subclass, returns an empty instance
531
+ # of that class.
532
+ #
426
533
  # @return [List]
427
534
  def clear
428
535
  EmptyList
429
536
  end
430
537
 
431
- # Return a `List` with the same items, but sorted either in their natural order,
432
- # or using an optional comparator block. The block must take 2 parameters, and
433
- # return 0, 1, or -1 if the first one is equal, greater than, or less than the
434
- # second (respectively).
538
+ # Return a new `List` with the same items, but sorted.
539
+ #
540
+ # @overload sort
541
+ # Compare elements with their natural sort key (`#<=>`).
542
+ #
543
+ # @example
544
+ # Hamster::List["Elephant", "Dog", "Lion"].sort
545
+ # # => Hamster::List["Dog", "Elephant", "Lion"]
546
+ #
547
+ # @overload sort
548
+ # Uses the block as a comparator to determine sorted order.
549
+ #
550
+ # @yield [a, b] Any number of times with different pairs of elements.
551
+ # @yieldreturn [Integer] Negative if the first element should be sorted
552
+ # lower, positive if the latter element, or 0 if
553
+ # equal.
554
+ # @example
555
+ # Hamster::List["Elephant", "Dog", "Lion"].sort { |a,b| a.size <=> b.size }
556
+ # # => Hamster::List["Dog", "Lion", "Elephant"]
435
557
  #
436
558
  # @return [List]
437
559
  def sort(&comparator)
438
- LazyList.new { super(&comparator).to_list }
560
+ LazyList.new { List.from_enum(super(&comparator)) }
439
561
  end
440
562
 
441
- # Return a new `List` with the same items, but sorted. The sort order will be
442
- # determined by mapping the items through the given block to obtain sort keys,
443
- # and then sorting the keys according to their natural sort order.
563
+ # Return a new `List` with the same items, but sorted. The sort order is
564
+ # determined by mapping the items through the given block to obtain sort
565
+ # keys, and then sorting the keys according to their natural sort order
566
+ # (`#<=>`).
567
+ #
568
+ # @yield [element] Once for each element.
569
+ # @yieldreturn a sort key object for the yielded element.
570
+ # @example
571
+ # Hamster::List["Elephant", "Dog", "Lion"].sort_by { |e| e.size }
572
+ # # => Hamster::List["Dog", "Lion", "Elephant"]
444
573
  #
445
574
  # @return [List]
446
575
  def sort_by(&transformer)
447
576
  return sort unless block_given?
448
- LazyList.new { super(&transformer).to_list }
577
+ LazyList.new { List.from_enum(super(&transformer)) }
449
578
  end
450
579
 
451
580
  # Return a new `List` with `sep` inserted between each of the existing elements.
452
581
  #
453
582
  # @example
454
- # Hamster.list('one', 'two', 'three').intersperse(' ')
455
- # # => Hamster::List['one', ' ', 'two', ' ', 'three']
583
+ # Hamster::List["one", "two", "three"].intersperse(" ")
584
+ # # => Hamster::List["one", " ", "two", " ", "three"]
456
585
  #
457
586
  # @return [List]
458
587
  def intersperse(sep)
@@ -462,35 +591,62 @@ module Hamster
462
591
  end
463
592
  end
464
593
 
465
- # Return a lazy list with the same items, but all duplicates removed.
594
+ # Return a `List` with the same items, but all duplicates removed.
466
595
  # Use `#hash` and `#eql?` to determine which items are duplicates.
467
596
  #
597
+ # @example
598
+ # Hamster::List[:a, :b, :a, :c, :b].uniq # => Hamster::List[:a, :b, :c]
599
+ # Hamster::List["a", "A", "b"].uniq(&:upcase) # => Hamster::List["a", "b"]
600
+ #
468
601
  # @return [List]
469
- def uniq(items = ::Set.new)
470
- LazyList.new do
471
- next self if empty?
472
- next tail.uniq(items) if items.include?(head)
473
- Cons.new(head, tail.uniq(items.add(head)))
602
+ def uniq(&block)
603
+ _uniq(::Set.new, &block)
604
+ end
605
+
606
+ # @private
607
+ # Separate from `uniq` so as not to expose `items` in the public API.
608
+ def _uniq(items, &block)
609
+ if block_given?
610
+ LazyList.new do
611
+ next self if empty?
612
+ if items.add?(block.call(head))
613
+ Cons.new(head, tail._uniq(items, &block))
614
+ else
615
+ tail._uniq(items, &block)
616
+ end
617
+ end
618
+ else
619
+ LazyList.new do
620
+ next self if empty?
621
+ next tail._uniq(items) if items.include?(head)
622
+ Cons.new(head, tail._uniq(items.add(head)))
623
+ end
474
624
  end
475
625
  end
476
- def_delegator :self, :uniq, :nub
477
- def_delegator :self, :uniq, :remove_duplicates
626
+ protected :_uniq
478
627
 
479
628
  # Return a `List` with all the elements from both this list and `other`,
480
629
  # with all duplicates removed.
481
630
  #
631
+ # @example
632
+ # Hamster::List[1, 2].union(Hamster::List[2, 3]) # => Hamster::List[1, 2, 3]
633
+ #
482
634
  # @param other [List] The list to merge with
483
635
  # @return [List]
484
636
  def union(other, items = ::Set.new)
485
637
  LazyList.new do
486
- next other.uniq(items) if empty?
638
+ next other._uniq(items) if empty?
487
639
  next tail.union(other, items) if items.include?(head)
488
640
  Cons.new(head, tail.union(other, items.add(head)))
489
641
  end
490
642
  end
491
- def_delegator :self, :union, :|
643
+ alias :| :union
492
644
 
493
- # Return a lazy list with all elements except the last one.
645
+ # Return a `List` with all elements except the last one.
646
+ #
647
+ # @example
648
+ # Hamster::List["a", "b", "c"].init # => Hamster::List["a", "b"]
649
+ #
494
650
  # @return [List]
495
651
  def init
496
652
  return EmptyList if tail.empty?
@@ -505,10 +661,10 @@ module Hamster
505
661
  list.head
506
662
  end
507
663
 
508
- # Return a lazy list of all suffixes of this list.
664
+ # Return a `List` of all suffixes of this list.
509
665
  #
510
666
  # @example
511
- # Hamster.list(1,2,3).tails
667
+ # Hamster::List[1,2,3].tails
512
668
  # # => Hamster::List[
513
669
  # # Hamster::List[1, 2, 3],
514
670
  # # Hamster::List[2, 3],
@@ -522,10 +678,10 @@ module Hamster
522
678
  end
523
679
  end
524
680
 
525
- # Return a lazy list of all prefixes of this list.
681
+ # Return a `List` of all prefixes of this list.
526
682
  #
527
683
  # @example
528
- # Hamster.list(1,2,3).inits
684
+ # Hamster::List[1,2,3].inits
529
685
  # # => Hamster::List[
530
686
  # # Hamster::List[1],
531
687
  # # Hamster::List[1, 2],
@@ -535,14 +691,14 @@ module Hamster
535
691
  def inits
536
692
  LazyList.new do
537
693
  next self if empty?
538
- Cons.new(Hamster.list(head), tail.inits.map { |list| list.cons(head) })
694
+ Cons.new(List[head], tail.inits.map { |list| list.cons(head) })
539
695
  end
540
696
  end
541
697
 
542
- # Return a lazy list of all combinations of length `n` of items from this `List`.
698
+ # Return a `List` of all combinations of length `n` of items from this `List`.
543
699
  #
544
700
  # @example
545
- # Hamster.list(1,2,3).combination(2)
701
+ # Hamster::List[1,2,3].combination(2)
546
702
  # # => Hamster::List[
547
703
  # # Hamster::List[1, 2],
548
704
  # # Hamster::List[1, 3],
@@ -558,6 +714,14 @@ module Hamster
558
714
  end
559
715
 
560
716
  # Split the items in this list in groups of `number`. Return a list of lists.
717
+ #
718
+ # @example
719
+ # ("a".."o").to_list.chunk(5)
720
+ # # => Hamster::List[
721
+ # # Hamster::List["a", "b", "c", "d", "e"],
722
+ # # Hamster::List["f", "g", "h", "i", "j"],
723
+ # # Hamster::List["k", "l", "m", "n", "o"]]
724
+ #
561
725
  # @return [List]
562
726
  def chunk(number)
563
727
  LazyList.new do
@@ -568,19 +732,26 @@ module Hamster
568
732
  end
569
733
 
570
734
  # Split the items in this list in groups of `number`, and yield each group
571
- # to the block (as a `List`).
572
- # @return [self]
735
+ # to the block (as a `List`). If no block is given, returns an
736
+ # `Enumerator`.
737
+ #
738
+ # @return [self, Enumerator]
739
+ # @yield [list] Once for each chunk.
573
740
  def each_chunk(number, &block)
574
741
  return enum_for(:each_chunk, number) unless block_given?
575
742
  chunk(number).each(&block)
576
743
  self
577
744
  end
578
- def_delegator :self, :each_chunk, :each_slice
745
+ alias :each_slice :each_chunk
579
746
 
580
747
  # Return a new `List` with all nested lists recursively "flattened out",
581
748
  # that is, their elements inserted into the new `List` in the place where
582
749
  # the nested list originally was.
583
750
  #
751
+ # @example
752
+ # Hamster::List[Hamster::List[1, 2], Hamster::List[3, 4]].flatten
753
+ # # => Hamster::List[1, 2, 3, 4]
754
+ #
584
755
  # @return [List]
585
756
  def flatten
586
757
  LazyList.new do
@@ -595,10 +766,17 @@ module Hamster
595
766
  # for which the block returned that value.
596
767
  #
597
768
  # @return [Hash]
769
+ # @yield [item]
770
+ # @example
771
+ # Hamster::List["a", "b", "ab"].group_by { |e| e.size }
772
+ # # Hamster::Hash[
773
+ # # 1 => Hamster::List["b", "a"],
774
+ # # 2 => Hamster::List["ab"]
775
+ # # ]
598
776
  def group_by(&block)
599
777
  group_by_with(EmptyList, &block)
600
778
  end
601
- def_delegator :self, :group_by, :group
779
+ alias :group :group_by
602
780
 
603
781
  # Retrieve the item at `index`. Negative indices count back from the end of
604
782
  # the list (-1 is the last item). If `index` is invalid (either too high or
@@ -617,22 +795,47 @@ module Hamster
617
795
  node.head
618
796
  end
619
797
 
620
- # Element reference. Return the item at a specific index, or a specified,
621
- # contiguous range of items (as a new list).
798
+ # Return specific objects from the `List`. All overloads return `nil` if
799
+ # the starting index is out of range.
800
+ #
801
+ # @overload list.slice(index)
802
+ # Returns a single object at the given `index`. If `index` is negative,
803
+ # count backwards from the end.
804
+ #
805
+ # @param index [Integer] The index to retrieve. May be negative.
806
+ # @return [Object]
807
+ # @example
808
+ # l = Hamster::List["A", "B", "C", "D", "E", "F"]
809
+ # l[2] # => "C"
810
+ # l[-1] # => "F"
811
+ # l[6] # => nil
622
812
  #
623
- # @overload list[index]
624
- # Return the item at `index`.
625
- # @param index [Integer] The index to retrieve.
626
- # @overload list[start, length]
627
- # Return a sublist starting at index `start` and continuing for `length` elements.
628
- # @param start [Integer] The index to start retrieving items from.
813
+ # @overload list.slice(index, length)
814
+ # Return a sublist starting at `index` and continuing for `length`
815
+ # elements or until the end of the `List`, whichever occurs first.
816
+ #
817
+ # @param start [Integer] The index to start retrieving items from. May be
818
+ # negative.
629
819
  # @param length [Integer] The number of items to retrieve.
630
- # @overload list[range]
631
- # Return a sublist specified by the given `range` of indices.
632
- # @param range [Range] The range of indices to retrieve.
820
+ # @return [List]
821
+ # @example
822
+ # l = Hamster::List["A", "B", "C", "D", "E", "F"]
823
+ # l[2, 3] # => Hamster::List["C", "D", "E"]
824
+ # l[-2, 3] # => Hamster::List["E", "F"]
825
+ # l[20, 1] # => nil
633
826
  #
634
- # @return [Object]
635
- def [](arg, length = (missing_length = true))
827
+ # @overload list.slice(index..end)
828
+ # Return a sublist starting at `index` and continuing to index
829
+ # `end` or the end of the `List`, whichever occurs first.
830
+ #
831
+ # @param range [Range] The range of indices to retrieve.
832
+ # @return [Vector]
833
+ # @example
834
+ # l = Hamster::List["A", "B", "C", "D", "E", "F"]
835
+ # l[2..3] # => Hamster::List["C", "D"]
836
+ # l[-2..100] # => Hamster::List["E", "F"]
837
+ # l[20..21] # => nil
838
+ def slice(arg, length = (missing_length = true))
636
839
  if missing_length
637
840
  if arg.is_a?(Range)
638
841
  from, to = arg.begin, arg.end
@@ -665,18 +868,35 @@ module Hamster
665
868
  list.take(length)
666
869
  end
667
870
  end
668
- def_delegator :self, :[], :slice
871
+ alias :[] :slice
669
872
 
670
- # Pass each item successively to the block, and return a `List` of indices where
671
- # the block returns true.
873
+ # Return a `List` of indices of matching objects.
874
+ #
875
+ # @overload indices(object)
876
+ # Return a `List` of indices where `object` is found. Use `#==` for
877
+ # testing equality.
878
+ #
879
+ # @example
880
+ # Hamster::List[1, 2, 3, 4].indices(2)
881
+ # # => Hamster::List[1]
882
+ #
883
+ # @overload indices
884
+ # Pass each item successively to the block. Return a list of indices
885
+ # where the block returns true.
886
+ #
887
+ # @yield [item]
888
+ # @example
889
+ # Hamster::List[1, 2, 3, 4].indices { |e| e.even? }
890
+ # # => Hamster::List[1, 3]
672
891
  #
673
892
  # @return [List]
674
- def find_indices(i = 0, &block)
675
- return EmptyList if empty? || !block_given?
893
+ def indices(object = Undefined, i = 0, &block)
894
+ return indices { |item| item == object } if not block_given?
895
+ return EmptyList if empty?
676
896
  LazyList.new do
677
897
  node = self
678
898
  while true
679
- break Cons.new(i, node.tail.find_indices(i + 1, &block)) if yield(node.head)
899
+ break Cons.new(i, node.tail.indices(Undefined, i + 1, &block)) if yield(node.head)
680
900
  node = node.tail
681
901
  break EmptyList if node.empty?
682
902
  i += 1
@@ -684,42 +904,25 @@ module Hamster
684
904
  end
685
905
  end
686
906
 
687
- # Return a `List` of indices where `object` is found. Use `#==` for testing equality.
688
- #
689
- # @param object [Object] The object to search for
690
- # @return [List]
691
- def elem_indices(object)
692
- find_indices { |item| item == object }
693
- end
694
-
695
- # Return a `List` of indices where the given object is found, or where the given
696
- # block returns true.
697
- #
698
- # @overload indices(obj)
699
- # Return a `List` of indices where `obj` is found. Use `#==` for testing equality.
700
- # @overload indices { |item| ... }
701
- # Pass each item successively to the block. Return a list of indices where the
702
- # block returns true.
703
- #
704
- # @return [List]
705
- def indices(object = Undefined, &block)
706
- return elem_indices(object) unless object.equal?(Undefined)
707
- find_indices(&block)
708
- end
709
-
710
907
  # Merge all the nested lists into a single list, using the given comparator
711
908
  # block to determine the order which items should be shifted out of the nested
712
- # lists and into the output list. The comparator should take 2 parameters and
713
- # return 0, 1, or -1 if the first parameter is (respectively) equal to, greater
714
- # than, or less than the second parameter. Whichever nested list's `#head` is
715
- # determined to be "lowest" according to the comparator will be the first in
716
- # the merged `List`.
909
+ # lists and into the output list.
910
+ #
911
+ # @example
912
+ # list_1 = Hamster::List[1, -3, -5]
913
+ # list_2 = Hamster::List[-2, 4, 6]
914
+ # Hamster::List[list_1, list_2].merge { |a,b| a.abs <=> b.abs }
915
+ # # => Hamster::List[1, -2, -3, 4, -5, 6]
717
916
  #
718
917
  # @return [List]
918
+ # @yield [a, b] Pairs of items from matching indices in each list.
919
+ # @yieldreturn [Integer] Negative if the first element should be selected
920
+ # first, positive if the latter element, or zero if
921
+ # either.
719
922
  def merge(&comparator)
720
923
  return merge_by unless block_given?
721
924
  LazyList.new do
722
- sorted = remove(&:empty?).sort do |a, b|
925
+ sorted = reject(&:empty?).sort do |a, b|
723
926
  yield(a.head, b.head)
724
927
  end
725
928
  next EmptyList if sorted.empty?
@@ -733,11 +936,19 @@ module Hamster
733
936
  # list. Whichever nested list's `#head` has the "lowest" sort key (according to
734
937
  # their natural order) will be the first in the merged `List`.
735
938
  #
939
+ # @example
940
+ # list_1 = Hamster::List[1, -3, -5]
941
+ # list_2 = Hamster::List[-2, 4, 6]
942
+ # Hamster::List[list_1, list_2].merge_by { |x| x.abs }
943
+ # # => Hamster::List[1, -2, -3, 4, -5, 6]
944
+ #
736
945
  # @return [List]
946
+ # @yield [item] Once for each item in either list.
947
+ # @yieldreturn [Object] A sort key for the element.
737
948
  def merge_by(&transformer)
738
949
  return merge_by { |item| item } unless block_given?
739
950
  LazyList.new do
740
- sorted = remove(&:empty?).sort_by do |list|
951
+ sorted = reject(&:empty?).sort_by do |list|
741
952
  yield(list.head)
742
953
  end
743
954
  next EmptyList if sorted.empty?
@@ -753,12 +964,15 @@ module Hamster
753
964
 
754
965
  # Return a new `List` with the given items inserted before the item at `index`.
755
966
  #
967
+ # @example
968
+ # Hamster::List["A", "D", "E"].insert(1, "B", "C") # => Hamster::List["A", "B", "C", "D", "E"]
969
+ #
756
970
  # @param index [Integer] The index where the new items should go
757
971
  # @param items [Array] The items to add
758
972
  # @return [List]
759
973
  def insert(index, *items)
760
974
  if index == 0
761
- return items.to_list.append(self)
975
+ return List.from_enum(items).append(self)
762
976
  elsif index > 0
763
977
  LazyList.new do
764
978
  Cons.new(head, tail.insert(index-1, *items))
@@ -769,8 +983,12 @@ module Hamster
769
983
  end
770
984
  end
771
985
 
772
- # Return a lazy list with all elements equal to `obj` removed. `#==` is used
986
+ # Return a `List` with all elements equal to `obj` removed. `#==` is used
773
987
  # for testing equality.
988
+ #
989
+ # @example
990
+ # Hamster::List[:a, :b, :a, :a, :c].delete(:a) # => Hamster::List[:b, :c]
991
+ #
774
992
  # @param obj [Object] The object to remove.
775
993
  # @return [List]
776
994
  def delete(obj)
@@ -780,9 +998,13 @@ module Hamster
780
998
  LazyList.new { Cons.new(list.head, list.tail.delete(obj)) }
781
999
  end
782
1000
 
783
- # Return a lazy list containing the same items, minus the one at `index`.
1001
+ # Return a `List` containing the same items, minus the one at `index`.
784
1002
  # If `index` is negative, it counts back from the end of the list.
785
1003
  #
1004
+ # @example
1005
+ # Hamster::List[1, 2, 3].delete_at(1) # => Hamster::List[1, 3]
1006
+ # Hamster::List[1, 2, 3].delete_at(-1) # => Hamster::List[1, 2]
1007
+ #
786
1008
  # @param index [Integer] The index of the item to remove
787
1009
  # @return [List]
788
1010
  def delete_at(index)
@@ -799,16 +1021,40 @@ module Hamster
799
1021
 
800
1022
  # Replace a range of indexes with the given object.
801
1023
  #
802
- # @overload fill(obj)
803
- # Return a new `List` of the same size, with every item set to `obj`.
804
- # @overload fill(obj, start)
805
- # Return a new `List` with all indexes from `start` to the end of the
806
- # list set to `obj`.
807
- # @overload fill(obj, start, length)
808
- # Return a new `List` with `length` indexes, beginning from `start`,
809
- # set to `obj`.
1024
+ # @overload fill(object)
1025
+ # Return a new `List` of the same size, with every index set to `object`.
1026
+ #
1027
+ # @param [Object] object Fill value.
1028
+ # @example
1029
+ # Hamster::List["A", "B", "C", "D", "E", "F"].fill("Z")
1030
+ # # => Hamster::List["Z", "Z", "Z", "Z", "Z", "Z"]
1031
+ #
1032
+ # @overload fill(object, index)
1033
+ # Return a new `List` with all indexes from `index` to the end of the
1034
+ # vector set to `obj`.
1035
+ #
1036
+ # @param [Object] object Fill value.
1037
+ # @param [Integer] index Starting index. May be negative.
1038
+ # @example
1039
+ # Hamster::List["A", "B", "C", "D", "E", "F"].fill("Z", 3)
1040
+ # # => Hamster::List["A", "B", "C", "Z", "Z", "Z"]
1041
+ #
1042
+ # @overload fill(object, index, length)
1043
+ # Return a new `List` with `length` indexes, beginning from `index`,
1044
+ # set to `obj`. Expands the `List` if `length` would extend beyond the
1045
+ # current length.
1046
+ #
1047
+ # @param [Object] object Fill value.
1048
+ # @param [Integer] index Starting index. May be negative.
1049
+ # @param [Integer] length
1050
+ # @example
1051
+ # Hamster::List["A", "B", "C", "D", "E", "F"].fill("Z", 3, 2)
1052
+ # # => Hamster::List["A", "B", "C", "Z", "Z", "F"]
1053
+ # Hamster::List["A", "B"].fill("Z", 1, 5)
1054
+ # # => Hamster::List["A", "Z", "Z", "Z", "Z", "Z"]
810
1055
  #
811
1056
  # @return [List]
1057
+ # @raise [IndexError] if index is out of negative range.
812
1058
  def fill(obj, index = 0, length = nil)
813
1059
  if index == 0
814
1060
  length ||= size
@@ -837,7 +1083,17 @@ module Hamster
837
1083
  #
838
1084
  # If no block is given, an `Enumerator` is returned instead.
839
1085
  #
1086
+ # @example
1087
+ # Hamster::List[1, 2, 3].permutation.to_a
1088
+ # # => [Hamster::List[1, 2, 3],
1089
+ # # Hamster::List[2, 1, 3],
1090
+ # # Hamster::List[2, 3, 1],
1091
+ # # Hamster::List[1, 3, 2],
1092
+ # # Hamster::List[3, 1, 2],
1093
+ # # Hamster::List[3, 2, 1]]
1094
+ #
840
1095
  # @return [self, Enumerator]
1096
+ # @yield [list] Once for each permutation.
841
1097
  def permutation(length = size, &block)
842
1098
  return enum_for(:permutation, length) if not block_given?
843
1099
  if length == 0
@@ -863,7 +1119,7 @@ module Hamster
863
1119
  # counts as one sublist.)
864
1120
  #
865
1121
  # @example
866
- # Hamster.list(1, 2, 3).subsequences { |list| p list }
1122
+ # Hamster::List[1, 2, 3].subsequences { |list| p list }
867
1123
  # # prints:
868
1124
  # # Hamster::List[1]
869
1125
  # # Hamster::List[1, 2]
@@ -885,10 +1141,15 @@ module Hamster
885
1141
  self
886
1142
  end
887
1143
 
888
- # Return 2 `List`s, the first containing all the elements for which the block
889
- # evaluates to true, the second containing the rest.
1144
+ # Return two `List`s, the first containing all the elements for which the
1145
+ # block evaluates to true, the second containing the rest.
1146
+ #
1147
+ # @example
1148
+ # Hamster::List[1, 2, 3, 4, 5, 6].partition { |x| x.even? }
1149
+ # # => [Hamster::List[2, 4, 6], Hamster::List[1, 3, 5]]
890
1150
  #
891
1151
  # @return [List]
1152
+ # @yield [item] Once for each item.
892
1153
  def partition(&block)
893
1154
  return enum_for(:partition) if not block_given?
894
1155
  partitioner = Partitioner.new(self, block)
@@ -920,12 +1181,13 @@ module Hamster
920
1181
  reduce(0) { |hash, item| (hash << 5) - hash + item.hash }
921
1182
  end
922
1183
 
923
- # Return `self`.
1184
+ # Return `self`. Since this is an immutable object duplicates are
1185
+ # equivalent.
924
1186
  # @return [List]
925
1187
  def dup
926
1188
  self
927
1189
  end
928
- def_delegator :self, :dup, :clone
1190
+ alias :clone :dup
929
1191
 
930
1192
  # Return `self`.
931
1193
  # @return [List]
@@ -971,13 +1233,21 @@ module Hamster
971
1233
 
972
1234
  private
973
1235
 
1236
+ # Perform compositions of `car` and `cdr` operations (traditional shorthand
1237
+ # for `head` and `tail` respectively). Their names consist of a `c`,
1238
+ # followed by at least one `a` or `d`, and finally an `r`. The series of
1239
+ # `a`s and `d`s in the method name identify the series of `car` and `cdr`
1240
+ # operations performed, in inverse order.
1241
+ #
1242
+ # @return [Object, List]
1243
+ # @example
1244
+ # l = Hamster::List[nil, Hamster::List[1]]
1245
+ # l.car # => nil
1246
+ # l.cdr # => Hamster::List[Hamster::List[1]]
1247
+ # l.cadr # => Hamster::List[1]
1248
+ # l.caadr # => 1
974
1249
  def method_missing(name, *args, &block)
975
1250
  if name.to_s.match(CADR)
976
- # Perform compositions of car and cdr operations. Their names consist of a 'c',
977
- # followed by at least one 'a' or 'd', and finally an 'r'. The series of 'a's and
978
- # 'd's in the method name identify the series of car and cdr operations performed.
979
- # The order in which the 'a's and 'd's appear is the inverse of the order in which
980
- # the corresponding operations are performed.
981
1251
  code = "def #{name}; self."
982
1252
  code << Regexp.last_match[1].reverse.chars.map do |char|
983
1253
  {'a' => 'head', 'd' => 'tail'}[char]
@@ -1020,6 +1290,7 @@ module Hamster
1020
1290
  def size
1021
1291
  @size ||= super
1022
1292
  end
1293
+ alias :length :size
1023
1294
 
1024
1295
  def cached_size?
1025
1296
  @size != nil
@@ -1031,7 +1302,7 @@ module Hamster
1031
1302
  # only called) when one of these operations is performed.
1032
1303
  #
1033
1304
  # By returning a `Cons` that in turn has a {LazyList} as its tail, one can
1034
- # construct infinite lazy lists.
1305
+ # construct infinite `List`s.
1035
1306
  #
1036
1307
  # @private
1037
1308
  class LazyList
@@ -1040,7 +1311,7 @@ module Hamster
1040
1311
  def initialize(&block)
1041
1312
  @head = block # doubles as storage for block while yet unrealized
1042
1313
  @tail = nil
1043
- @atomic = Atomic.new(0) # haven't yet run block
1314
+ @atomic = Concurrent::Atomic.new(0) # haven't yet run block
1044
1315
  @size = nil
1045
1316
  end
1046
1317
 
@@ -1048,6 +1319,7 @@ module Hamster
1048
1319
  realize if @atomic.get != 2
1049
1320
  @head
1050
1321
  end
1322
+ alias :first :head
1051
1323
 
1052
1324
  def tail
1053
1325
  realize if @atomic.get != 2
@@ -1062,6 +1334,7 @@ module Hamster
1062
1334
  def size
1063
1335
  @size ||= super
1064
1336
  end
1337
+ alias :length :size
1065
1338
 
1066
1339
  def cached_size?
1067
1340
  @size != nil
@@ -1106,7 +1379,7 @@ module Hamster
1106
1379
  end
1107
1380
  end
1108
1381
 
1109
- # Common behavior for other classes which implement various kinds of lazy lists
1382
+ # Common behavior for other classes which implement various kinds of `List`s
1110
1383
  # @private
1111
1384
  class Realizable
1112
1385
  include List
@@ -1119,6 +1392,7 @@ module Hamster
1119
1392
  realize if @head == Undefined
1120
1393
  @head
1121
1394
  end
1395
+ alias :first :head
1122
1396
 
1123
1397
  def tail
1124
1398
  realize if @tail == Undefined
@@ -1133,6 +1407,7 @@ module Hamster
1133
1407
  def size
1134
1408
  @size ||= super
1135
1409
  end
1410
+ alias :length :size
1136
1411
 
1137
1412
  def cached_size?
1138
1413
  @size != nil
@@ -1143,7 +1418,7 @@ module Hamster
1143
1418
  end
1144
1419
  end
1145
1420
 
1146
- # This class can divide a collection into 2 lazy lists, one of items
1421
+ # This class can divide a collection into 2 `List`s, one of items
1147
1422
  # for which the block returns true, and another for false
1148
1423
  # At the same time, it guarantees the block will only be called ONCE for each item
1149
1424
  #
@@ -1167,7 +1442,7 @@ module Hamster
1167
1442
  end
1168
1443
  end
1169
1444
 
1170
- # One of the lazy lists which gets its items from a Partitioner
1445
+ # One of the `List`s which gets its items from a Partitioner
1171
1446
  # @private
1172
1447
  class Partitioned < Realizable
1173
1448
  def initialize(partitioner, buffer, mutex)
@@ -1176,7 +1451,9 @@ module Hamster
1176
1451
  end
1177
1452
 
1178
1453
  def realize
1179
- @mutex.synchronize do
1454
+ # another thread may get ahead of us and null out @mutex
1455
+ mutex = @mutex
1456
+ mutex && mutex.synchronize do
1180
1457
  return if @head != Undefined # another thread got ahead of us
1181
1458
  while true
1182
1459
  if !@buffer.empty?
@@ -1198,9 +1475,10 @@ module Hamster
1198
1475
  end
1199
1476
  end
1200
1477
 
1201
- # This class can divide a list up into 2 lazy lists, one for the prefix of elements
1202
- # for which the block returns true, and another for all the elements after that
1203
- # It guarantees that the block will only be called ONCE for each item
1478
+ # This class can divide a list up into 2 `List`s, one for the prefix of
1479
+ # elements for which the block returns true, and another for all the elements
1480
+ # after that. It guarantees that the block will only be called ONCE for each
1481
+ # item
1204
1482
  #
1205
1483
  # @private
1206
1484
  class Splitter
@@ -1226,6 +1504,7 @@ module Hamster
1226
1504
  @list.empty?
1227
1505
  end
1228
1506
 
1507
+ # @private
1229
1508
  class Left < Realizable
1230
1509
  def initialize(splitter, buffer, mutex)
1231
1510
  super()
@@ -1233,7 +1512,9 @@ module Hamster
1233
1512
  end
1234
1513
 
1235
1514
  def realize
1236
- @mutex.synchronize do
1515
+ # another thread may get ahead of us and null out @mutex
1516
+ mutex = @mutex
1517
+ mutex && mutex.synchronize do
1237
1518
  return if @head != Undefined # another thread got ahead of us
1238
1519
  while true
1239
1520
  if !@buffer.empty?
@@ -1253,6 +1534,7 @@ module Hamster
1253
1534
  end
1254
1535
  end
1255
1536
 
1537
+ # @private
1256
1538
  class Right < Realizable
1257
1539
  def initialize(splitter, mutex)
1258
1540
  super()
@@ -1260,7 +1542,8 @@ module Hamster
1260
1542
  end
1261
1543
 
1262
1544
  def realize
1263
- @mutex.synchronize do
1545
+ mutex = @mutex
1546
+ mutex && mutex.synchronize do
1264
1547
  return if @head != Undefined
1265
1548
  @splitter.next_item until @splitter.done?
1266
1549
  if @splitter.right.empty?
@@ -1275,7 +1558,7 @@ module Hamster
1275
1558
  end
1276
1559
 
1277
1560
  # A list without any elements. This is a singleton, since all empty lists are equivalent.
1278
- #
1561
+ # @private
1279
1562
  module EmptyList
1280
1563
  class << self
1281
1564
  include List
@@ -1285,6 +1568,7 @@ module Hamster
1285
1568
  def head
1286
1569
  nil
1287
1570
  end
1571
+ alias :first :head
1288
1572
 
1289
1573
  # There are no subsequent elements, so return an empty list.
1290
1574
  # @return [self]
@@ -1301,10 +1585,11 @@ module Hamster
1301
1585
  def size
1302
1586
  0
1303
1587
  end
1588
+ alias :length :size
1304
1589
 
1305
1590
  def cached_size?
1306
1591
  true
1307
1592
  end
1308
1593
  end
1309
1594
  end
1310
- end
1595
+ end.freeze