hamster 1.0.1.pre.rc3 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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