hamster 1.0.1.pre.rc2 → 1.0.1.pre.rc3

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 (482) hide show
  1. checksums.yaml +4 -4
  2. data/lib/hamster.rb +2 -2
  3. data/lib/hamster/core_ext.rb +0 -1
  4. data/lib/hamster/core_ext/enumerable.rb +17 -17
  5. data/lib/hamster/core_ext/io.rb +15 -17
  6. data/lib/hamster/deque.rb +229 -0
  7. data/lib/hamster/enumerable.rb +147 -105
  8. data/lib/hamster/experimental/mutable_queue.rb +2 -2
  9. data/lib/hamster/hash.rb +488 -82
  10. data/lib/hamster/immutable.rb +4 -0
  11. data/lib/hamster/list.rb +839 -196
  12. data/lib/hamster/read_copy_update.rb +1 -0
  13. data/lib/hamster/set.rb +317 -54
  14. data/lib/hamster/sorted_set.rb +1014 -0
  15. data/lib/hamster/trie.rb +67 -47
  16. data/lib/hamster/undefined.rb +1 -3
  17. data/lib/hamster/vector.rb +989 -76
  18. data/lib/hamster/version.rb +1 -1
  19. data/spec/{hamster → lib/hamster}/core_ext/array_spec.rb +1 -1
  20. data/spec/{hamster → lib/hamster}/core_ext/enumerable_spec.rb +4 -0
  21. data/spec/{hamster → lib/hamster}/core_ext/io_spec.rb +0 -0
  22. data/spec/lib/hamster/deque/clear_spec.rb +34 -0
  23. data/spec/lib/hamster/deque/construction_spec.rb +30 -0
  24. data/spec/lib/hamster/deque/copying_spec.rb +20 -0
  25. data/spec/lib/hamster/deque/dequeue_spec.rb +27 -0
  26. data/spec/lib/hamster/deque/empty_spec.rb +42 -0
  27. data/spec/{hamster/queue → lib/hamster/deque}/enqueue_spec.rb +7 -10
  28. data/spec/lib/hamster/deque/head_spec.rb +20 -0
  29. data/spec/lib/hamster/deque/inspect_spec.rb +24 -0
  30. data/spec/lib/hamster/deque/last_spec.rb +20 -0
  31. data/spec/lib/hamster/deque/marshal_spec.rb +34 -0
  32. data/spec/lib/hamster/deque/new_spec.rb +44 -0
  33. data/spec/lib/hamster/deque/pop_spec.rb +25 -0
  34. data/spec/lib/hamster/deque/random_modification_spec.rb +34 -0
  35. data/spec/{hamster/queue → lib/hamster/deque}/size_spec.rb +4 -9
  36. data/spec/lib/hamster/deque/to_a_spec.rb +27 -0
  37. data/spec/{hamster/queue → lib/hamster/deque}/to_ary_spec.rb +6 -6
  38. data/spec/lib/hamster/deque/to_list_spec.rb +26 -0
  39. data/spec/lib/hamster/deque/unshift_spec.rb +26 -0
  40. data/spec/{hamster → lib/hamster}/experimental/mutable_set/add_qm_spec.rb +0 -0
  41. data/spec/{hamster → lib/hamster}/experimental/mutable_set/add_spec.rb +0 -0
  42. data/spec/{hamster → lib/hamster}/experimental/mutable_set/delete_qm_spec.rb +0 -0
  43. data/spec/{hamster → lib/hamster}/experimental/mutable_set/delete_spec.rb +0 -0
  44. data/spec/{hamster → lib/hamster}/hash/all_spec.rb +10 -0
  45. data/spec/lib/hamster/hash/any_spec.rb +56 -0
  46. data/spec/lib/hamster/hash/assoc_spec.rb +52 -0
  47. data/spec/lib/hamster/hash/clear_spec.rb +43 -0
  48. data/spec/lib/hamster/hash/construction_spec.rb +39 -0
  49. data/spec/{hamster → lib/hamster}/hash/copying_spec.rb +2 -4
  50. data/spec/lib/hamster/hash/default_proc_spec.rb +73 -0
  51. data/spec/lib/hamster/hash/delete_spec.rb +40 -0
  52. data/spec/lib/hamster/hash/each_spec.rb +78 -0
  53. data/spec/lib/hamster/hash/each_with_index_spec.rb +30 -0
  54. data/spec/lib/hamster/hash/empty_spec.rb +46 -0
  55. data/spec/lib/hamster/hash/eql_spec.rb +70 -0
  56. data/spec/lib/hamster/hash/except_spec.rb +43 -0
  57. data/spec/lib/hamster/hash/fetch_spec.rb +58 -0
  58. data/spec/lib/hamster/hash/filter_spec.rb +58 -0
  59. data/spec/lib/hamster/hash/find_spec.rb +44 -0
  60. data/spec/lib/hamster/hash/flat_map_spec.rb +36 -0
  61. data/spec/lib/hamster/hash/flatten_spec.rb +99 -0
  62. data/spec/lib/hamster/hash/get_spec.rb +80 -0
  63. data/spec/lib/hamster/hash/has_key_spec.rb +32 -0
  64. data/spec/lib/hamster/hash/has_value_spec.rb +28 -0
  65. data/spec/{hamster → lib/hamster}/hash/hash_spec.rb +5 -12
  66. data/spec/{hamster → lib/hamster}/hash/immutable_spec.rb +0 -0
  67. data/spec/lib/hamster/hash/inspect_spec.rb +31 -0
  68. data/spec/lib/hamster/hash/invert_spec.rb +31 -0
  69. data/spec/lib/hamster/hash/key_spec.rb +28 -0
  70. data/spec/{hamster → lib/hamster}/hash/keys_spec.rb +3 -6
  71. data/spec/lib/hamster/hash/map_spec.rb +46 -0
  72. data/spec/{hamster → lib/hamster}/hash/marshal_spec.rb +3 -3
  73. data/spec/lib/hamster/hash/merge_spec.rb +77 -0
  74. data/spec/lib/hamster/hash/min_max_spec.rb +50 -0
  75. data/spec/lib/hamster/hash/new_spec.rb +71 -0
  76. data/spec/{hamster → lib/hamster}/hash/none_spec.rb +12 -14
  77. data/spec/lib/hamster/hash/partition_spec.rb +36 -0
  78. data/spec/lib/hamster/hash/pretty_print_spec.rb +35 -0
  79. data/spec/lib/hamster/hash/put_spec.rb +81 -0
  80. data/spec/lib/hamster/hash/reduce_spec.rb +36 -0
  81. data/spec/lib/hamster/hash/remove_spec.rb +62 -0
  82. data/spec/lib/hamster/hash/reverse_each_spec.rb +28 -0
  83. data/spec/lib/hamster/hash/sample_spec.rb +14 -0
  84. data/spec/{hamster → lib/hamster}/hash/size_spec.rb +2 -2
  85. data/spec/lib/hamster/hash/slice_spec.rb +45 -0
  86. data/spec/lib/hamster/hash/sort_spec.rb +27 -0
  87. data/spec/lib/hamster/hash/store_spec.rb +54 -0
  88. data/spec/lib/hamster/hash/take_spec.rb +36 -0
  89. data/spec/lib/hamster/hash/to_a_spec.rb +14 -0
  90. data/spec/lib/hamster/hash/to_hash_spec.rb +22 -0
  91. data/spec/{hamster → lib/hamster}/hash/uniq_spec.rb +2 -4
  92. data/spec/lib/hamster/hash/values_at_spec.rb +14 -0
  93. data/spec/lib/hamster/hash/values_spec.rb +25 -0
  94. data/spec/{hamster → lib/hamster}/immutable/copying_spec.rb +0 -0
  95. data/spec/{hamster → lib/hamster}/immutable/immutable_spec.rb +0 -0
  96. data/spec/{hamster → lib/hamster}/immutable/memoize_spec.rb +2 -2
  97. data/spec/{hamster → lib/hamster}/immutable/new_spec.rb +0 -0
  98. data/spec/{hamster → lib/hamster}/immutable/transform_spec.rb +0 -0
  99. data/spec/{hamster → lib/hamster}/immutable/transform_unless_spec.rb +0 -0
  100. data/spec/lib/hamster/list/add_spec.rb +20 -0
  101. data/spec/lib/hamster/list/all_spec.rb +60 -0
  102. data/spec/{hamster → lib/hamster}/list/any_spec.rb +12 -20
  103. data/spec/{hamster → lib/hamster}/list/append_spec.rb +9 -10
  104. data/spec/lib/hamster/list/at_spec.rb +30 -0
  105. data/spec/lib/hamster/list/break_spec.rb +70 -0
  106. data/spec/{hamster → lib/hamster}/list/cadr_spec.rb +5 -8
  107. data/spec/{hamster → lib/hamster}/list/chunk_spec.rb +5 -8
  108. data/spec/{hamster → lib/hamster}/list/clear_spec.rb +4 -7
  109. data/spec/lib/hamster/list/combination_spec.rb +34 -0
  110. data/spec/{hamster → lib/hamster}/list/compact_spec.rb +5 -8
  111. data/spec/lib/hamster/list/compare_spec.rb +31 -0
  112. data/spec/{hamster → lib/hamster}/list/cons_spec.rb +5 -9
  113. data/spec/lib/hamster/list/construction_spec.rb +118 -0
  114. data/spec/{hamster → lib/hamster}/list/copying_spec.rb +3 -7
  115. data/spec/lib/hamster/list/count_spec.rb +37 -0
  116. data/spec/lib/hamster/list/cycle_spec.rb +29 -0
  117. data/spec/lib/hamster/list/delete_at_spec.rb +19 -0
  118. data/spec/lib/hamster/list/delete_spec.rb +17 -0
  119. data/spec/{hamster → lib/hamster}/list/drop_spec.rb +5 -8
  120. data/spec/lib/hamster/list/drop_while_spec.rb +39 -0
  121. data/spec/lib/hamster/list/each_slice_spec.rb +52 -0
  122. data/spec/lib/hamster/list/each_spec.rb +43 -0
  123. data/spec/lib/hamster/list/each_with_index_spec.rb +29 -0
  124. data/spec/{hamster → lib/hamster}/list/elem_index_spec.rb +4 -14
  125. data/spec/{hamster → lib/hamster}/list/elem_indices_spec.rb +5 -9
  126. data/spec/{hamster → lib/hamster}/list/empty_spec.rb +4 -13
  127. data/spec/{hamster → lib/hamster}/list/eql_spec.rb +2 -8
  128. data/spec/lib/hamster/list/fill_spec.rb +50 -0
  129. data/spec/{hamster → lib/hamster}/list/filter_spec.rb +3 -2
  130. data/spec/{hamster → lib/hamster}/list/find_all_spec.rb +3 -2
  131. data/spec/{hamster → lib/hamster}/list/find_index_spec.rb +4 -14
  132. data/spec/{hamster → lib/hamster}/list/find_indices_spec.rb +11 -9
  133. data/spec/{hamster → lib/hamster}/list/find_spec.rb +10 -16
  134. data/spec/{hamster → lib/hamster}/list/flat_map_spec.rb +0 -0
  135. data/spec/{hamster → lib/hamster}/list/flatten_spec.rb +5 -8
  136. data/spec/{hamster → lib/hamster}/list/grep_spec.rb +9 -17
  137. data/spec/{hamster → lib/hamster}/list/group_by_spec.rb +8 -24
  138. data/spec/{hamster → lib/hamster}/list/hash_spec.rb +4 -12
  139. data/spec/{hamster → lib/hamster}/list/head_spec.rb +2 -7
  140. data/spec/{hamster → lib/hamster}/list/include_spec.rb +4 -13
  141. data/spec/{hamster → lib/hamster}/list/init_spec.rb +5 -9
  142. data/spec/lib/hamster/list/inits_spec.rb +29 -0
  143. data/spec/lib/hamster/list/insert_spec.rb +47 -0
  144. data/spec/lib/hamster/list/inspect_spec.rb +30 -0
  145. data/spec/{hamster → lib/hamster}/list/intersperse_spec.rb +5 -8
  146. data/spec/lib/hamster/list/join_spec.rb +64 -0
  147. data/spec/lib/hamster/list/last_spec.rb +24 -0
  148. data/spec/{hamster → lib/hamster}/list/map_spec.rb +11 -20
  149. data/spec/lib/hamster/list/maximum_spec.rb +42 -0
  150. data/spec/{hamster → lib/hamster}/list/merge_by_spec.rb +4 -13
  151. data/spec/{hamster → lib/hamster}/list/merge_spec.rb +0 -0
  152. data/spec/lib/hamster/list/minimum_spec.rb +42 -0
  153. data/spec/lib/hamster/list/multithreading_spec.rb +48 -0
  154. data/spec/{hamster → lib/hamster}/list/none_spec.rb +11 -21
  155. data/spec/{hamster → lib/hamster}/list/one_spec.rb +12 -22
  156. data/spec/lib/hamster/list/partition_spec.rb +116 -0
  157. data/spec/lib/hamster/list/permutation_spec.rb +56 -0
  158. data/spec/{hamster → lib/hamster}/list/pop_spec.rb +1 -1
  159. data/spec/lib/hamster/list/product_spec.rb +24 -0
  160. data/spec/lib/hamster/list/reduce_spec.rb +97 -0
  161. data/spec/{hamster → lib/hamster}/list/remove_spec.rb +9 -19
  162. data/spec/{hamster → lib/hamster}/list/reverse_spec.rb +7 -14
  163. data/spec/lib/hamster/list/rotate_spec.rb +37 -0
  164. data/spec/lib/hamster/list/sample_spec.rb +14 -0
  165. data/spec/{hamster → lib/hamster}/list/select_spec.rb +3 -2
  166. data/spec/{hamster → lib/hamster}/list/size_spec.rb +4 -13
  167. data/spec/lib/hamster/list/slice_spec.rb +230 -0
  168. data/spec/{hamster → lib/hamster}/list/sorting_spec.rb +10 -20
  169. data/spec/lib/hamster/list/span_spec.rb +77 -0
  170. data/spec/{hamster → lib/hamster}/list/split_at_spec.rb +13 -14
  171. data/spec/lib/hamster/list/subsequences_spec.rb +24 -0
  172. data/spec/lib/hamster/list/sum_spec.rb +24 -0
  173. data/spec/lib/hamster/list/tail_spec.rb +31 -0
  174. data/spec/lib/hamster/list/tails_spec.rb +29 -0
  175. data/spec/{hamster → lib/hamster}/list/take_spec.rb +5 -8
  176. data/spec/{hamster → lib/hamster}/list/take_while_spec.rb +11 -17
  177. data/spec/lib/hamster/list/to_a_spec.rb +40 -0
  178. data/spec/{hamster → lib/hamster}/list/to_ary_spec.rb +1 -3
  179. data/spec/{hamster → lib/hamster}/list/to_list_spec.rb +3 -7
  180. data/spec/{hamster → lib/hamster}/list/to_set_spec.rb +2 -10
  181. data/spec/lib/hamster/list/transpose_spec.rb +20 -0
  182. data/spec/{hamster → lib/hamster}/list/union_spec.rb +5 -12
  183. data/spec/{hamster → lib/hamster}/list/uniq_spec.rb +5 -8
  184. data/spec/{hamster → lib/hamster}/list/zip_spec.rb +2 -9
  185. data/spec/lib/hamster/set/add_spec.rb +76 -0
  186. data/spec/{hamster → lib/hamster}/set/all_spec.rb +18 -14
  187. data/spec/{hamster → lib/hamster}/set/any_spec.rb +19 -16
  188. data/spec/{hamster → lib/hamster}/set/clear_spec.rb +8 -11
  189. data/spec/{hamster → lib/hamster}/set/compact_spec.rb +4 -7
  190. data/spec/{hamster → lib/hamster}/set/construction_spec.rb +4 -8
  191. data/spec/{hamster → lib/hamster}/set/copying_spec.rb +3 -5
  192. data/spec/{hamster → lib/hamster}/set/count_spec.rb +11 -16
  193. data/spec/lib/hamster/set/delete_spec.rb +72 -0
  194. data/spec/lib/hamster/set/difference_spec.rb +50 -0
  195. data/spec/lib/hamster/set/disjoint_spec.rb +26 -0
  196. data/spec/lib/hamster/set/each_spec.rb +46 -0
  197. data/spec/lib/hamster/set/empty_spec.rb +47 -0
  198. data/spec/{hamster → lib/hamster}/set/eqeq_spec.rb +0 -0
  199. data/spec/{hamster → lib/hamster}/set/eql_spec.rb +7 -1
  200. data/spec/lib/hamster/set/exclusion_spec.rb +48 -0
  201. data/spec/lib/hamster/set/filter_spec.rb +74 -0
  202. data/spec/{hamster → lib/hamster}/set/find_spec.rb +7 -11
  203. data/spec/lib/hamster/set/flatten_spec.rb +47 -0
  204. data/spec/{hamster → lib/hamster}/set/foreach_spec.rb +5 -4
  205. data/spec/{hamster → lib/hamster}/set/grep_spec.rb +1 -1
  206. data/spec/lib/hamster/set/group_by_spec.rb +60 -0
  207. data/spec/lib/hamster/set/hash_spec.rb +23 -0
  208. data/spec/lib/hamster/set/head_spec.rb +31 -0
  209. data/spec/{hamster → lib/hamster}/set/immutable_spec.rb +0 -0
  210. data/spec/lib/hamster/set/include_spec.rb +61 -0
  211. data/spec/lib/hamster/set/inspect_spec.rb +48 -0
  212. data/spec/lib/hamster/set/intersect_spec.rb +26 -0
  213. data/spec/lib/hamster/set/intersection_spec.rb +53 -0
  214. data/spec/lib/hamster/set/join_spec.rb +65 -0
  215. data/spec/lib/hamster/set/map_spec.rb +60 -0
  216. data/spec/{hamster → lib/hamster}/set/marshal_spec.rb +3 -3
  217. data/spec/{hamster → lib/hamster}/set/maximum_spec.rb +6 -15
  218. data/spec/{hamster → lib/hamster}/set/minimum_spec.rb +6 -16
  219. data/spec/lib/hamster/set/new_spec.rb +54 -0
  220. data/spec/{hamster → lib/hamster}/set/none_spec.rb +15 -15
  221. data/spec/{hamster → lib/hamster}/set/one_spec.rb +14 -16
  222. data/spec/lib/hamster/set/partition_spec.rb +53 -0
  223. data/spec/{hamster → lib/hamster}/set/product_spec.rb +6 -6
  224. data/spec/lib/hamster/set/reduce_spec.rb +56 -0
  225. data/spec/lib/hamster/set/remove_spec.rb +51 -0
  226. data/spec/{hamster/set/each_spec.rb → lib/hamster/set/reverse_each_spec.rb} +8 -7
  227. data/spec/lib/hamster/set/sample_spec.rb +14 -0
  228. data/spec/{hamster → lib/hamster}/set/size_spec.rb +0 -1
  229. data/spec/{hamster → lib/hamster}/set/sorting_spec.rb +17 -13
  230. data/spec/lib/hamster/set/subset_spec.rb +52 -0
  231. data/spec/lib/hamster/set/sum_spec.rb +24 -0
  232. data/spec/lib/hamster/set/superset_spec.rb +52 -0
  233. data/spec/lib/hamster/set/to_a_spec.rb +31 -0
  234. data/spec/lib/hamster/set/to_list_spec.rb +37 -0
  235. data/spec/{hamster → lib/hamster}/set/to_set_spec.rb +2 -6
  236. data/spec/lib/hamster/set/union_spec.rb +55 -0
  237. data/spec/{hamster → lib/hamster}/set/uniq_spec.rb +2 -5
  238. data/spec/lib/hamster/sorted_set/above_spec.rb +52 -0
  239. data/spec/lib/hamster/sorted_set/add_spec.rb +63 -0
  240. data/spec/lib/hamster/sorted_set/at_spec.rb +25 -0
  241. data/spec/lib/hamster/sorted_set/below_spec.rb +52 -0
  242. data/spec/lib/hamster/sorted_set/between_spec.rb +52 -0
  243. data/spec/lib/hamster/sorted_set/clear_spec.rb +35 -0
  244. data/spec/lib/hamster/sorted_set/construction_spec.rb +29 -0
  245. data/spec/lib/hamster/sorted_set/delete_at_spec.rb +19 -0
  246. data/spec/lib/hamster/sorted_set/delete_spec.rb +81 -0
  247. data/spec/{hamster/set → lib/hamster/sorted_set}/difference_spec.rb +5 -9
  248. data/spec/lib/hamster/sorted_set/disjoint_spec.rb +26 -0
  249. data/spec/lib/hamster/sorted_set/drop_spec.rb +29 -0
  250. data/spec/lib/hamster/sorted_set/drop_while_spec.rb +35 -0
  251. data/spec/lib/hamster/sorted_set/each_spec.rb +31 -0
  252. data/spec/lib/hamster/sorted_set/empty_spec.rb +37 -0
  253. data/spec/lib/hamster/sorted_set/eql_spec.rb +121 -0
  254. data/spec/{hamster/set → lib/hamster/sorted_set}/exclusion_spec.rb +4 -9
  255. data/spec/lib/hamster/sorted_set/fetch_spec.rb +65 -0
  256. data/spec/lib/hamster/sorted_set/filter_spec.rb +62 -0
  257. data/spec/lib/hamster/sorted_set/find_index_spec.rb +33 -0
  258. data/spec/lib/hamster/sorted_set/first_spec.rb +21 -0
  259. data/spec/lib/hamster/sorted_set/from_spec.rb +52 -0
  260. data/spec/lib/hamster/sorted_set/group_by_spec.rb +58 -0
  261. data/spec/lib/hamster/sorted_set/include_spec.rb +24 -0
  262. data/spec/lib/hamster/sorted_set/inspect_spec.rb +38 -0
  263. data/spec/lib/hamster/sorted_set/intersect_spec.rb +26 -0
  264. data/spec/lib/hamster/sorted_set/intersection_spec.rb +29 -0
  265. data/spec/lib/hamster/sorted_set/last_spec.rb +37 -0
  266. data/spec/lib/hamster/sorted_set/map_spec.rb +36 -0
  267. data/spec/lib/hamster/sorted_set/marshal_spec.rb +37 -0
  268. data/spec/lib/hamster/sorted_set/minimum_spec.rb +22 -0
  269. data/spec/lib/hamster/sorted_set/new_spec.rb +52 -0
  270. data/spec/lib/hamster/sorted_set/reverse_each_spec.rb +29 -0
  271. data/spec/lib/hamster/sorted_set/sample_spec.rb +14 -0
  272. data/spec/lib/hamster/sorted_set/size_spec.rb +18 -0
  273. data/spec/lib/hamster/sorted_set/slice_spec.rb +241 -0
  274. data/spec/lib/hamster/sorted_set/sorting_spec.rb +45 -0
  275. data/spec/lib/hamster/sorted_set/subset_spec.rb +48 -0
  276. data/spec/lib/hamster/sorted_set/superset_spec.rb +48 -0
  277. data/spec/lib/hamster/sorted_set/take_spec.rb +26 -0
  278. data/spec/lib/hamster/sorted_set/take_while_spec.rb +34 -0
  279. data/spec/lib/hamster/sorted_set/to_set_spec.rb +19 -0
  280. data/spec/lib/hamster/sorted_set/union_spec.rb +28 -0
  281. data/spec/lib/hamster/sorted_set/up_to_spec.rb +52 -0
  282. data/spec/lib/hamster/sorted_set/values_at_spec.rb +34 -0
  283. data/spec/lib/hamster/vector/add_spec.rb +68 -0
  284. data/spec/{hamster → lib/hamster}/vector/any_spec.rb +0 -0
  285. data/spec/lib/hamster/vector/assoc_spec.rb +36 -0
  286. data/spec/lib/hamster/vector/bsearch_spec.rb +58 -0
  287. data/spec/lib/hamster/vector/clear_spec.rb +34 -0
  288. data/spec/lib/hamster/vector/combination_spec.rb +82 -0
  289. data/spec/lib/hamster/vector/compact_spec.rb +30 -0
  290. data/spec/lib/hamster/vector/compare_spec.rb +32 -0
  291. data/spec/lib/hamster/vector/concat_spec.rb +35 -0
  292. data/spec/{hamster → lib/hamster}/vector/copying_spec.rb +3 -6
  293. data/spec/lib/hamster/vector/count_spec.rb +18 -0
  294. data/spec/lib/hamster/vector/delete_at_spec.rb +54 -0
  295. data/spec/lib/hamster/vector/delete_spec.rb +31 -0
  296. data/spec/lib/hamster/vector/drop_spec.rb +35 -0
  297. data/spec/lib/hamster/vector/drop_while_spec.rb +55 -0
  298. data/spec/lib/hamster/vector/each_index_spec.rb +41 -0
  299. data/spec/lib/hamster/vector/each_spec.rb +47 -0
  300. data/spec/lib/hamster/vector/each_with_index_spec.rb +40 -0
  301. data/spec/lib/hamster/vector/empty_spec.rb +44 -0
  302. data/spec/lib/hamster/vector/eql_spec.rb +77 -0
  303. data/spec/lib/hamster/vector/exist_spec.rb +4 -4
  304. data/spec/lib/hamster/vector/exists_spec.rb +4 -4
  305. data/spec/lib/hamster/vector/fetch_spec.rb +65 -0
  306. data/spec/lib/hamster/vector/fill_spec.rb +89 -0
  307. data/spec/lib/hamster/vector/filter_spec.rb +64 -0
  308. data/spec/{hamster → lib/hamster}/vector/first_spec.rb +2 -6
  309. data/spec/lib/hamster/vector/flatten_spec.rb +44 -0
  310. data/spec/lib/hamster/vector/get_spec.rb +75 -0
  311. data/spec/lib/hamster/vector/group_by_spec.rb +58 -0
  312. data/spec/{hamster → lib/hamster}/vector/include_spec.rb +2 -6
  313. data/spec/lib/hamster/vector/insert_spec.rb +69 -0
  314. data/spec/lib/hamster/vector/inspect_spec.rb +50 -0
  315. data/spec/{hamster/set → lib/hamster/vector}/join_spec.rb +23 -18
  316. data/spec/{hamster → lib/hamster}/vector/last_spec.rb +12 -3
  317. data/spec/{hamster → lib/hamster}/vector/length_spec.rb +12 -3
  318. data/spec/lib/hamster/vector/ltlt_spec.rb +20 -2
  319. data/spec/lib/hamster/vector/map_spec.rb +52 -0
  320. data/spec/lib/hamster/vector/marshal_spec.rb +32 -0
  321. data/spec/lib/hamster/vector/maximum_spec.rb +36 -0
  322. data/spec/lib/hamster/vector/minimum_spec.rb +36 -0
  323. data/spec/lib/hamster/vector/multiply_spec.rb +48 -0
  324. data/spec/lib/hamster/vector/new_spec.rb +51 -0
  325. data/spec/lib/hamster/vector/partition_spec.rb +53 -0
  326. data/spec/lib/hamster/vector/permutation_spec.rb +92 -0
  327. data/spec/lib/hamster/vector/pop_spec.rb +27 -0
  328. data/spec/lib/hamster/vector/product_spec.rb +71 -0
  329. data/spec/lib/hamster/vector/reduce_spec.rb +108 -0
  330. data/spec/lib/hamster/vector/remove_spec.rb +44 -0
  331. data/spec/lib/hamster/vector/repeated_combination_spec.rb +78 -0
  332. data/spec/lib/hamster/vector/repeated_permutation_spec.rb +94 -0
  333. data/spec/lib/hamster/vector/reverse_each_spec.rb +32 -0
  334. data/spec/lib/hamster/vector/reverse_spec.rb +22 -0
  335. data/spec/lib/hamster/vector/rindex_spec.rb +37 -0
  336. data/spec/lib/hamster/vector/rotate_spec.rb +74 -0
  337. data/spec/lib/hamster/vector/sample_spec.rb +14 -0
  338. data/spec/{hamster → lib/hamster}/vector/set_spec.rb +48 -14
  339. data/spec/lib/hamster/vector/shift_spec.rb +28 -0
  340. data/spec/lib/hamster/vector/shuffle_spec.rb +44 -0
  341. data/spec/lib/hamster/vector/slice_spec.rb +241 -0
  342. data/spec/lib/hamster/vector/sorting_spec.rb +57 -0
  343. data/spec/{hamster/set → lib/hamster/vector}/sum_spec.rb +3 -9
  344. data/spec/lib/hamster/vector/take_spec.rb +29 -0
  345. data/spec/lib/hamster/vector/take_while_spec.rb +35 -0
  346. data/spec/{hamster → lib/hamster}/vector/to_a_spec.rb +11 -12
  347. data/spec/{hamster → lib/hamster}/vector/to_ary_spec.rb +0 -0
  348. data/spec/{hamster/set → lib/hamster/vector}/to_list_spec.rb +7 -12
  349. data/spec/lib/hamster/vector/to_set_spec.rb +23 -0
  350. data/spec/lib/hamster/vector/transpose_spec.rb +49 -0
  351. data/spec/lib/hamster/vector/uniq_spec.rb +56 -0
  352. data/spec/lib/hamster/vector/unshift_spec.rb +29 -0
  353. data/spec/lib/hamster/vector/values_at_spec.rb +34 -0
  354. data/spec/lib/hamster/vector/zip_spec.rb +58 -0
  355. data/spec/spec_helper.rb +34 -1
  356. metadata +684 -467
  357. data/lib/hamster/core_ext/enumerator.rb +0 -16
  358. data/lib/hamster/experimental/mutable_stack.rb +0 -30
  359. data/lib/hamster/groupable.rb +0 -12
  360. data/lib/hamster/queue.rb +0 -86
  361. data/lib/hamster/sorter.rb +0 -25
  362. data/lib/hamster/stack.rb +0 -77
  363. data/lib/hamster/tuple.rb +0 -24
  364. data/spec/hamster/core_ext/enumerator_spec.rb +0 -19
  365. data/spec/hamster/experimental/mutable_stack/pop_spec.rb +0 -35
  366. data/spec/hamster/experimental/mutable_stack/push_spec.rb +0 -21
  367. data/spec/hamster/hash/any_spec.rb +0 -52
  368. data/spec/hamster/hash/clear_spec.rb +0 -29
  369. data/spec/hamster/hash/construction_spec.rb +0 -27
  370. data/spec/hamster/hash/delete_spec.rb +0 -38
  371. data/spec/hamster/hash/each_spec.rb +0 -30
  372. data/spec/hamster/hash/empty_spec.rb +0 -27
  373. data/spec/hamster/hash/eql_spec.rb +0 -70
  374. data/spec/hamster/hash/except_spec.rb +0 -22
  375. data/spec/hamster/hash/fetch_spec.rb +0 -72
  376. data/spec/hamster/hash/filter_spec.rb +0 -48
  377. data/spec/hamster/hash/find_spec.rb +0 -45
  378. data/spec/hamster/hash/get_spec.rb +0 -55
  379. data/spec/hamster/hash/has_key_spec.rb +0 -26
  380. data/spec/hamster/hash/inspect_spec.rb +0 -24
  381. data/spec/hamster/hash/map_spec.rb +0 -49
  382. data/spec/hamster/hash/merge_spec.rb +0 -30
  383. data/spec/hamster/hash/new_spec.rb +0 -21
  384. data/spec/hamster/hash/put_spec.rb +0 -67
  385. data/spec/hamster/hash/reduce_spec.rb +0 -52
  386. data/spec/hamster/hash/remove_spec.rb +0 -48
  387. data/spec/hamster/hash/slice_spec.rb +0 -26
  388. data/spec/hamster/hash/values_spec.rb +0 -29
  389. data/spec/hamster/list/add_spec.rb +0 -11
  390. data/spec/hamster/list/all_spec.rb +0 -84
  391. data/spec/hamster/list/at_spec.rb +0 -37
  392. data/spec/hamster/list/break_spec.rb +0 -73
  393. data/spec/hamster/list/combinations_spec.rb +0 -41
  394. data/spec/hamster/list/construction_spec.rb +0 -137
  395. data/spec/hamster/list/count_spec.rb +0 -52
  396. data/spec/hamster/list/cycle_spec.rb +0 -36
  397. data/spec/hamster/list/drop_while_spec.rb +0 -47
  398. data/spec/hamster/list/each_slice_spec.rb +0 -64
  399. data/spec/hamster/list/each_spec.rb +0 -56
  400. data/spec/hamster/list/each_with_index_spec.rb +0 -33
  401. data/spec/hamster/list/inits_spec.rb +0 -34
  402. data/spec/hamster/list/inspect_spec.rb +0 -33
  403. data/spec/hamster/list/join_spec.rb +0 -64
  404. data/spec/hamster/list/last_spec.rb +0 -34
  405. data/spec/hamster/list/maximum_spec.rb +0 -58
  406. data/spec/hamster/list/minimum_spec.rb +0 -58
  407. data/spec/hamster/list/partition_spec.rb +0 -63
  408. data/spec/hamster/list/product_spec.rb +0 -34
  409. data/spec/hamster/list/reduce_spec.rb +0 -72
  410. data/spec/hamster/list/slice_spec.rb +0 -40
  411. data/spec/hamster/list/span_spec.rb +0 -75
  412. data/spec/hamster/list/sum_spec.rb +0 -34
  413. data/spec/hamster/list/tail_spec.rb +0 -38
  414. data/spec/hamster/list/tails_spec.rb +0 -34
  415. data/spec/hamster/list/to_a_spec.rb +0 -42
  416. data/spec/hamster/queue/clear_spec.rb +0 -28
  417. data/spec/hamster/queue/construction_spec.rb +0 -34
  418. data/spec/hamster/queue/dequeue_spec.rb +0 -30
  419. data/spec/hamster/queue/empty_spec.rb +0 -35
  420. data/spec/hamster/queue/head_spec.rb +0 -25
  421. data/spec/hamster/queue/inspect_spec.rb +0 -23
  422. data/spec/hamster/queue/to_a_spec.rb +0 -32
  423. data/spec/hamster/queue/to_list_spec.rb +0 -34
  424. data/spec/hamster/set/add_spec.rb +0 -40
  425. data/spec/hamster/set/delete_spec.rb +0 -38
  426. data/spec/hamster/set/empty_spec.rb +0 -25
  427. data/spec/hamster/set/filter_spec.rb +0 -72
  428. data/spec/hamster/set/flatten_spec.rb +0 -47
  429. data/spec/hamster/set/group_by_spec.rb +0 -56
  430. data/spec/hamster/set/hash_spec.rb +0 -20
  431. data/spec/hamster/set/head_spec.rb +0 -28
  432. data/spec/hamster/set/include_spec.rb +0 -27
  433. data/spec/hamster/set/inspect_spec.rb +0 -24
  434. data/spec/hamster/set/intersection_spec.rb +0 -36
  435. data/spec/hamster/set/map_spec.rb +0 -49
  436. data/spec/hamster/set/new_spec.rb +0 -21
  437. data/spec/hamster/set/partition_spec.rb +0 -59
  438. data/spec/hamster/set/reduce_spec.rb +0 -62
  439. data/spec/hamster/set/remove_spec.rb +0 -48
  440. data/spec/hamster/set/subset_spec.rb +0 -31
  441. data/spec/hamster/set/superset_spec.rb +0 -31
  442. data/spec/hamster/set/to_a_spec.rb +0 -32
  443. data/spec/hamster/set/union_spec.rb +0 -35
  444. data/spec/hamster/sorter/immutable_spec.rb +0 -9
  445. data/spec/hamster/stack/clear_spec.rb +0 -28
  446. data/spec/hamster/stack/construction_spec.rb +0 -34
  447. data/spec/hamster/stack/copying_spec.rb +0 -23
  448. data/spec/hamster/stack/empty_spec.rb +0 -23
  449. data/spec/hamster/stack/eql_spec.rb +0 -48
  450. data/spec/hamster/stack/immutable_spec.rb +0 -9
  451. data/spec/hamster/stack/inspect_spec.rb +0 -23
  452. data/spec/hamster/stack/peek_spec.rb +0 -30
  453. data/spec/hamster/stack/pop_spec.rb +0 -31
  454. data/spec/hamster/stack/push_spec.rb +0 -31
  455. data/spec/hamster/stack/size_spec.rb +0 -25
  456. data/spec/hamster/stack/to_a_spec.rb +0 -32
  457. data/spec/hamster/stack/to_ary.rb +0 -37
  458. data/spec/hamster/stack/to_list_spec.rb +0 -25
  459. data/spec/hamster/trie/remove_spec.rb +0 -117
  460. data/spec/hamster/tuple/construction_spec.rb +0 -30
  461. data/spec/hamster/tuple/copying_spec.rb +0 -17
  462. data/spec/hamster/tuple/eql_spec.rb +0 -78
  463. data/spec/hamster/tuple/first_spec.rb +0 -14
  464. data/spec/hamster/tuple/immutable_spec.rb +0 -9
  465. data/spec/hamster/tuple/inspect_spec.rb +0 -14
  466. data/spec/hamster/tuple/last_spec.rb +0 -14
  467. data/spec/hamster/tuple/to_a_spec.rb +0 -30
  468. data/spec/hamster/tuple/to_ary_spec.rb +0 -37
  469. data/spec/hamster/undefined/erase_spec.rb +0 -36
  470. data/spec/hamster/vector/add_spec.rb +0 -56
  471. data/spec/hamster/vector/clear_spec.rb +0 -28
  472. data/spec/hamster/vector/each_spec.rb +0 -35
  473. data/spec/hamster/vector/each_with_index_spec.rb +0 -33
  474. data/spec/hamster/vector/empty_spec.rb +0 -32
  475. data/spec/hamster/vector/eql_spec.rb +0 -53
  476. data/spec/hamster/vector/filter_spec.rb +0 -58
  477. data/spec/hamster/vector/get_spec.rb +0 -58
  478. data/spec/hamster/vector/inspect_spec.rb +0 -33
  479. data/spec/hamster/vector/map_spec.rb +0 -57
  480. data/spec/hamster/vector/new_spec.rb +0 -48
  481. data/spec/hamster/vector/reduce_spec.rb +0 -62
  482. data/spec/lib/hamster/vector/cons_spec.rb +0 -48
@@ -1,10 +1,10 @@
1
1
  require "forwardable"
2
- require "hamster/queue"
2
+ require "hamster/deque"
3
3
  require "hamster/read_copy_update"
4
4
 
5
5
  module Hamster
6
6
  def self.mutable_queue(*items)
7
- MutableQueue.new(queue(*items))
7
+ MutableQueue.new(deque(*items))
8
8
  end
9
9
 
10
10
  class MutableQueue
@@ -3,50 +3,141 @@ require "forwardable"
3
3
  require "hamster/immutable"
4
4
  require "hamster/undefined"
5
5
  require "hamster/trie"
6
- require "hamster/list"
6
+ require "hamster/set"
7
+ require "hamster/vector"
7
8
 
8
9
  module Hamster
9
10
  def self.hash(pairs = nil, &block)
10
- Hash.new(pairs, &block)
11
+ (pairs.nil? && block.nil?) ? EmptyHash : Hash.new(pairs, &block)
11
12
  end
12
13
 
14
+ # A `Hamster::Hash` maps from a set of unique keys to corresponding values,
15
+ # much like a dictionary maps from words to definitions. Given a key, it can
16
+ # efficiently store and retrieve values. Looking up a key given its value is also
17
+ # possible, but less efficient. If an existing key is stored again, the new value
18
+ # will replace that which was previously stored.
19
+ #
20
+ # It behaves much like Ruby's built-in Hash, which we will call RubyHash
21
+ # for clarity. Like RubyHash, `Hamster::Hash` uses `#hash` and `#eql?` to define
22
+ # equality between keys. Keys with the same `#hash` code, but which are not `#eql?`
23
+ # to each other, can coexist in the same `Hamster::Hash`. To retrieve a previously
24
+ # stored value, the key provided must have the same `#hash` code and be `#eql?`
25
+ # to the one used for storage.
26
+ #
27
+ # A `Hamster::Hash` can be created in several ways:
28
+ #
29
+ # Hamster.hash('Jane Doe' => 10, 'Jim Doe' => 6)
30
+ # Hamster::Hash.new(font_size: 10, font_family: 'Arial')
31
+ # Hamster::Hash[first_name: 'John', last_name: 'Smith']
32
+ #
33
+ # If you want to write your own class which inherits from `Hamster::Hash`, you can
34
+ # use either of the latter 2 forms of initialization.
35
+ #
36
+ # Note that any `Enumerable` object which yields 2-element `[key, value]` arrays
37
+ # can be used to initialize a `Hamster::Hash`. So this is also possible:
38
+ #
39
+ # Hamster::Hash.new([[:first_name, 'John'], [:last_name, 'Smith']])
40
+ #
41
+ # Like RubyHash, key/value pairs can be added using {#store}. Unlike RubyHash,
42
+ # a new hash is returned, and the existing one is left unchanged:
43
+ #
44
+ # hash = Hamster::Hash[a: 100, b: 200]
45
+ # hash.store(:c, 500) # => Hamster::Hash[:a => 100, :b => 200, :c => 500]
46
+ # hash # => Hamster::Hash[:a => 100, :b => 200]
47
+ #
48
+ # You also use {#put}. The difference is that {#put} can optionally take a block which
49
+ # is used to calculate the value to be stored:
50
+ #
51
+ # hash.put(:a) { hash[:b] + 100 } # => Hamster::Hash[:a => 300, :b => 200]
52
+ #
53
+ # Since it is immutable, all methods which you might expect to "modify" a `Hamster::Hash`
54
+ # actually return a new hash and leave the existing one unchanged. This means that the
55
+ # `hash[key] = value` syntax used with RubyHashes *cannot* be used with `Hamster::Hash`.
56
+ #
57
+ # While a `Hamster::Hash` can iterate over its keys (or values), it does not
58
+ # guarantee any specific iteration order (unlike RubyHash). Likewise, methods like
59
+ # {#flatten} do not guarantee which order the returned key/value pairs will appear
60
+ # in.
61
+ #
62
+ # Like RubyHash, a `Hamster::Hash` can have a default block which is used when
63
+ # looking up a key which does not exist in the hash. Unlike RubyHash, the default
64
+ # block will only be passed the missing key, not the hash itself:
65
+ #
66
+ # hash = Hamster::Hash.new { |n| n * 10 }
67
+ # hash[5] # => 50
68
+ #
69
+ # A default block can only be set when creating a `Hamster::Hash` with `Hamster::Hash.new` or
70
+ # {Hamster.hash Hamster.hash}, not with {Hamster::Hash.[] Hamster::Hash[]}. Default blocks
71
+ # do not survive marshalling and unmarshalling.
72
+ #
13
73
  class Hash
14
74
  extend Forwardable
15
75
  include Immutable
76
+ include Enumerable
16
77
 
17
78
  class << self
18
- alias :alloc :new
19
-
20
- def new(pairs = nil, &block)
21
- if pairs.nil? && block.nil?
22
- empty
23
- elsif pairs.empty?
24
- alloc(EmptyTrie, block)
25
- else
26
- alloc(Trie[pairs], block)
27
- end
79
+ # Create a new `Hash` populated with the given key/value pairs.
80
+ #
81
+ # @return [Hash]
82
+ def [](pairs = nil)
83
+ (pairs.nil? || pairs.empty?) ? empty : new(pairs)
28
84
  end
29
85
 
86
+ # Return an empty `Hash`. If used on a subclass, returns an empty instance
87
+ # of that class.
88
+ #
89
+ # @return [Hash]
30
90
  def empty
31
- @empty ||= self.alloc
91
+ @empty ||= self.new
92
+ end
93
+
94
+ # "Raw" allocation of a new `Hash`. Used internally to create a new
95
+ # instance quickly after obtaining a modified {Trie}.
96
+ #
97
+ # @return [Hash]
98
+ # @private
99
+ def alloc(trie = EmptyTrie, block = nil)
100
+ obj = allocate
101
+ obj.instance_variable_set(:@trie, trie)
102
+ obj.instance_variable_set(:@default, block)
103
+ obj
32
104
  end
33
105
  end
34
106
 
35
- def initialize(trie = EmptyTrie, block = nil)
36
- @trie = trie
107
+ def initialize(pairs = nil, &block)
108
+ @trie = pairs ? Trie[pairs] : EmptyTrie
37
109
  @default = block
38
110
  end
39
111
 
112
+ # Return the default block if there is one. Otherwise, return `nil`.
113
+ #
114
+ # @return [Proc]
115
+ def default_proc
116
+ @default
117
+ end
118
+
119
+ # Return the number of key/value pairs in this `Hash`.
120
+ #
121
+ # @return [Integer]
40
122
  def size
41
123
  @trie.size
42
124
  end
43
125
  def_delegator :self, :size, :length
44
126
 
127
+ # Return `true` if this `Hash` contains no key/value pairs.
128
+ #
129
+ # @return [Boolean]
45
130
  def empty?
46
131
  @trie.empty?
47
132
  end
48
133
  def_delegator :self, :empty?, :null?
49
134
 
135
+ # Return `true` if the given key object is present in this `Hash`. More precisely,
136
+ # return `true` if a key with the same `#hash` code, and which is also `#eql?`
137
+ # to the given key object is present.
138
+ #
139
+ # @param key [Object] The key to check for
140
+ # @return [Boolean]
50
141
  def key?(key)
51
142
  @trie.key?(key)
52
143
  end
@@ -54,142 +145,394 @@ module Hamster
54
145
  def_delegator :self, :key?, :include?
55
146
  def_delegator :self, :key?, :member?
56
147
 
148
+ # Return `true` if this `Hash` has one or more keys which map to the provided value.
149
+ #
150
+ # @param value [Object] The value to check for
151
+ # @return [Boolean]
152
+ def value?(value)
153
+ each { |k,v| return true if value == v }
154
+ false
155
+ end
156
+ def_delegator :self, :value?, :has_value?
157
+
158
+ # Retrieve the value corresponding to the provided key object. If not found, and
159
+ # this `Hash` has a default block, the default block is called to provide the
160
+ # value.
161
+ #
162
+ # @param key [Object] The key to look up
163
+ # @return [Object]
57
164
  def get(key)
58
165
  entry = @trie.get(key)
59
166
  if entry
60
- entry.value
167
+ entry[1]
61
168
  elsif @default
62
169
  @default.call(key)
63
170
  end
64
171
  end
65
172
  def_delegator :self, :get, :[]
66
173
 
174
+ # Retrieve the value corresponding to the given key object, or use the provided
175
+ # default value or block, or otherwise raise a `KeyError`.
176
+ #
177
+ # @overload fetch(key)
178
+ # Retrieve the value corresponding to the given key, or raise a `KeyError`
179
+ # if it is not found.
180
+ # @param key [Object] The key to look up
181
+ # @overload fetch(key) { |key| ... }
182
+ # Retrieve the value corresponding to the given key, or call the optional
183
+ # code block (with the missing key) and get its return value.
184
+ # @yield [key] The key which was not found
185
+ # @yieldreturn [Object] Object to return since the key was not found
186
+ # @param key [Object] The key to look up
187
+ # @overload fetch(key, default)
188
+ # Retrieve the value corresponding to the given key, or else return
189
+ # the provided `default` value.
190
+ # @param key [Object] The key to look up
191
+ # @param default [Object] Object to return if the key is not found
192
+ #
193
+ # @return [Object]
67
194
  def fetch(key, default = Undefined)
68
195
  entry = @trie.get(key)
69
196
  if entry
70
- entry.value
197
+ entry[1]
198
+ elsif block_given?
199
+ yield(key)
71
200
  elsif default != Undefined
72
201
  default
73
- elsif block_given?
74
- yield
75
202
  else
76
203
  raise KeyError, "key not found: #{key.inspect}"
77
204
  end
78
205
  end
79
206
 
80
- def put(key, value = Undefined)
81
- return put(key, yield(get(key))) if value.equal?(Undefined)
82
- transform { @trie = @trie.put(key, value) }
207
+ # Return a new `Hash` with the existing key/value associations, plus an association
208
+ # between the provided key and value. If an equivalent key is already present, its
209
+ # associated value will be replaced with the provided one.
210
+ #
211
+ # If the `value` argument is missing, but an optional code block is provided,
212
+ # it will be passed the existing value (or `nil` if there is none) and what it
213
+ # returns will replace the existing value. This is useful for "transforming"
214
+ # the value associated with a certain key.
215
+ #
216
+ # Avoid mutating objects which are used as keys. `String`s are an exception --
217
+ # unfrozen `String`s which are used as keys are internally duplicated and
218
+ # frozen.
219
+ #
220
+ # @param key [Object] The key to store
221
+ # @param value [Object] The value to associate it with
222
+ # @yield [value] The previously stored value
223
+ # @yieldreturn [Object] The new value to store
224
+ # @return [Hash]
225
+ def put(key, value = yield(get(key)))
226
+ self.class.alloc(@trie.put(key, value), @default)
83
227
  end
84
228
 
85
- def delete(key)
86
- trie = @trie.delete(key)
87
- transform_unless(trie.equal?(@trie)) { @trie = trie }
229
+ # Return a new `Hash` with the existing key/value associations, plus an association
230
+ # between the provided key and value. If an equivalent key is already present, its
231
+ # associated value will be replaced with the provided one.
232
+ #
233
+ # Avoid mutating objects which are used as keys. `String`s are an exception --
234
+ # unfrozen `String`s which are used as keys are internally duplicated and
235
+ # frozen.
236
+ #
237
+ # @param key [Object] The key to store
238
+ # @param value [Object] The value to associate it with
239
+ # @return [Hash]
240
+ def store(key, value)
241
+ self.class.alloc(@trie.put(key, value), @default)
88
242
  end
89
243
 
90
- def each
91
- return self unless block_given?
92
- @trie.each { |entry| yield(entry.key, entry.value) }
244
+ # Return a new `Hash` with the association for `key` removed. If `key` is not
245
+ # present, return `self`.
246
+ #
247
+ # @param key [Object] The key to remove
248
+ # @return [Hash]
249
+ def delete(key)
250
+ derive_new_hash(@trie.delete(key))
93
251
  end
94
- def_delegator :self, :each, :foreach
95
252
 
96
- def map
97
- return self unless block_given?
98
- return self if empty?
99
- transform { @trie = @trie.reduce(EmptyTrie) { |trie, entry| trie.put(*yield(entry.key, entry.value)) } }
253
+ # Call the block once for each key/value pair in this `Hash`, passing the key/value
254
+ # pair as parameters. No specific iteration order is guaranteed (but the order will
255
+ # be stable for any particular `Hash`.)
256
+ #
257
+ # @return [self]
258
+ def each(&block)
259
+ return to_enum if not block_given?
260
+ @trie.each(&block)
261
+ self
100
262
  end
101
- def_delegator :self, :map, :collect
102
-
103
- def reduce(memoization)
104
- return memoization unless block_given?
105
- @trie.reduce(memoization) { |memo, entry| yield(memo, entry.key, entry.value) }
263
+ def_delegator :self, :each, :each_pair
264
+
265
+ # Call the block once for each key/value pair in this `Hash`, passing the key/value
266
+ # pair as parameters. Iteration order will be the opposite of {#each}.
267
+ #
268
+ # @return [self]
269
+ def reverse_each(&block)
270
+ return enum_for(:reverse_each) if not block_given?
271
+ @trie.reverse_each(&block)
272
+ self
106
273
  end
107
- def_delegator :self, :reduce, :inject
108
- def_delegator :self, :reduce, :fold
109
- def_delegator :self, :reduce, :foldr
110
274
 
111
- def filter
112
- return self unless block_given?
113
- trie = @trie.filter { |entry| yield(entry.key, entry.value) }
114
- return self.class.empty if trie.empty?
115
- transform_unless(trie.equal?(@trie)) { @trie = trie }
275
+ # Call the block once for each key/value pair in this `Hash`, passing the key as a
276
+ # parameter.
277
+ #
278
+ # @return [self]
279
+ def each_key
280
+ return enum_for(:each_key) if not block_given?
281
+ @trie.each { |k,v| yield k }
282
+ self
116
283
  end
117
- def_delegator :self, :filter, :select
118
- def_delegator :self, :filter, :find_all
119
284
 
120
- def remove
121
- return self unless block_given?
122
- filter { |key, value| !yield(key, value) }
285
+ # Call the block once for each key/value pair in this `Hash`, passing the value as a
286
+ # parameter.
287
+ #
288
+ # @return [self]
289
+ def each_value
290
+ return enum_for(:each_value) if not block_given?
291
+ @trie.each { |k,v| yield v }
292
+ self
123
293
  end
124
- def_delegator :self, :remove, :reject
125
- def_delegator :self, :remove, :delete_if
126
294
 
127
- def any?
128
- return !empty? unless block_given?
129
- each { |key, value| return true if yield(key, value) }
130
- false
295
+ # Call the block once for each key/value pair in this `Hash`, passing the key/value
296
+ # pair as parameters. The block should return a `[key, value]` array each time.
297
+ # All the returned `[key, value]` arrays will be gathered into a new `Hash`.
298
+ #
299
+ # @return [Hash]
300
+ def map
301
+ return enum_for(:map) unless block_given?
302
+ return self if empty?
303
+ self.class.new(super, &@default)
131
304
  end
132
- def_delegator :self, :any?, :exist?
133
- def_delegator :self, :any?, :exists?
305
+ def_delegator :self, :map, :collect
134
306
 
135
- def all?
136
- each { |key, value| return false unless yield(key, value) } if block_given?
137
- true
138
- end
139
- def_delegator :self, :all?, :forall?
307
+ def_delegator :self, :reduce, :foldr
140
308
 
141
- def none?
142
- return empty? unless block_given?
143
- each { |key, value| return false if yield(key, value) }
144
- true
309
+ # Return a new `Hash` with all the key/value pairs for which the block returns true.
310
+ #
311
+ # @return [Hash]
312
+ def filter(&block)
313
+ return enum_for(:filter) unless block_given?
314
+ derive_new_hash(@trie.filter(&block))
145
315
  end
146
316
 
317
+ # Yield `[key, value]` pairs until one is found for which the block returns true.
318
+ # Return that `[key, value]` pair. If the block never returns true, return `nil`.
319
+ #
320
+ # @return [Array]
147
321
  def find
148
- return nil unless block_given?
149
- each { |key, value| return Tuple.new(key, value) if yield(key, value) }
322
+ return enum_for(:find) unless block_given?
323
+ each { |entry| return entry if yield entry }
150
324
  nil
151
325
  end
152
326
  def_delegator :self, :find, :detect
153
327
 
328
+ def_delegator :self, :max, :maximum
329
+ def_delegator :self, :min, :minimum
330
+
331
+ # Return a new `Hash` containing all the key/value pairs from this `Hash` and
332
+ # `other`. If no block is provided, the value for entries with colliding keys
333
+ # will be that from `other`. Otherwie, the value for each duplicate key is
334
+ # determined by called the block with the key, its value in this `Hash`, and
335
+ # its value in `other`.
336
+ #
337
+ # `other` can be a `Hamster::Hash`, a built-in Ruby `Hash`, or any `Enumerable`
338
+ # object which yields `[key, value]` pairs.
339
+ #
340
+ # @param other [Enumerable] The collection to merge with
341
+ # @yieldparam key [Object] The key which was present in both collections
342
+ # @yieldparam my_value [Object] The associated value from this `Hash`
343
+ # @yieldparam other_value [Object] The associated value from the other collection
344
+ # @yieldreturn [Object] The value to associate this key with in the new `Hash`
345
+ # @return [Hash]
154
346
  def merge(other)
155
- transform do
156
- other.each { |key, value| @trie = @trie.put(key, value) }
347
+ trie = if block_given?
348
+ other.reduce(@trie) do |trie, (key, value)|
349
+ if entry = trie.get(key)
350
+ trie.put(key, yield(key, entry[1], value))
351
+ else
352
+ trie.put(key, value)
353
+ end
354
+ end
355
+ else
356
+ other.reduce(@trie) { |trie, (key, value)| trie.put(key, value) }
157
357
  end
358
+
359
+ derive_new_hash(trie)
158
360
  end
159
361
  def_delegator :self, :merge, :+
160
362
 
363
+ # Return a {Vector} which contains all the `[key, value]` pairs in this `Hash`
364
+ # as 2-element Arrays, either in their natural sorted order as determined by
365
+ # `#<=>`, or if an optional block is supplied, by using the block as a comparator.
366
+ # See `Enumerable#sort`.
367
+ #
368
+ # @return [Vector]
369
+ def sort
370
+ Vector.new(super)
371
+ end
372
+
373
+ # Return a {Vector} which contains all the `[key, value]` pairs in this `Hash`
374
+ # as 2-element Arrays. The order which the pairs will appear in is determined by
375
+ # passing each pair to the code block to obtain a sort key object, and comparing
376
+ # the sort keys using `#<=>`.
377
+ # See `Enumerable#sort_by`.
378
+ #
379
+ # @return [Vector]
380
+ def sort_by
381
+ Vector.new(super)
382
+ end
383
+
384
+ # Return a new `Hash` with the associations for all of the given `keys` removed.
385
+ #
386
+ # @param keys [Array] The keys to remove
387
+ # @return [Hash]
161
388
  def except(*keys)
162
389
  keys.reduce(self) { |hash, key| hash.delete(key) }
163
390
  end
164
391
 
392
+ # Return a new `Hash` with only the associations for the `wanted` keys retained.
393
+ # If any of the `wanted` keys are not present in this `Hash`, they will not be present
394
+ # in the returned `Hash` either.
395
+ #
396
+ # @param wanted [Array] The keys to retain
397
+ # @return [Hash]
165
398
  def slice(*wanted)
166
- except(*keys - wanted)
399
+ trie = Trie.new(0)
400
+ wanted.each { |key| trie.put!(key, get(key)) if key?(key) }
401
+ self.class.alloc(trie, @default)
402
+ end
403
+
404
+ # Return a {Vector} of the values which correspond to the `wanted` keys.
405
+ # If any of the `wanted` keys are not present in this `Hash`, they will be skipped.
406
+ #
407
+ # @param wanted [Array] The keys to retrieve
408
+ # @return [Vector]
409
+ def values_at(*wanted)
410
+ array = []
411
+ wanted.each { |key| array << get(key) if key?(key) }
412
+ Vector.new(array.freeze)
167
413
  end
168
414
 
415
+ # Return a new {Set} populated with the keys from this `Hash`.
416
+ #
417
+ # @return [Set]
169
418
  def keys
170
- Hamster::Set.alloc(@trie)
419
+ Set.alloc(@trie)
171
420
  end
172
421
 
422
+ # Return a new {Vector} populated with the values from this `Hash`.
423
+ #
424
+ # @return [Vector]
173
425
  def values
174
- reduce(Hamster.list) { |values, key, value| values.cons(value) }
426
+ Vector.new(each_value.to_a.freeze)
427
+ end
428
+
429
+ # Return a new `Hash` created by using our keys as values, and values as keys.
430
+ # If there are multiple values which are equivalent (as determined by `#hash` and
431
+ # `#eql?`), only one out of each group of equivalent values will be retained.
432
+ #
433
+ # @return [Hash]
434
+ def invert
435
+ pairs = []
436
+ each { |k,v| pairs << [v, k] }
437
+ self.class.new(pairs, &@default)
438
+ end
439
+
440
+ # Return a new {Vector} which is a one-dimensional flattening of this `Hash`.
441
+ # If `level` is 1, all the `[key, value]` pairs in the hash will be concatenated
442
+ # into one {Vector}. If `level` is greater than 1, keys or values which are
443
+ # themselves `Array`s or {Vector}s will be recursively flattened into the output
444
+ # {Vector}. The depth to which that flattening will be recursively applied is
445
+ # determined by `level`.
446
+ #
447
+ # As a special case, if `level` is 0, each `[key, value]` pair will be a
448
+ # separate element in the returned {Vector}.
449
+ #
450
+ # @param level [Integer] The number of times to recursively flatten the `[key, value]` pairs in this `Hash`.
451
+ # @return [Vector]
452
+ def flatten(level = 1)
453
+ return Vector.new(self) if level == 0
454
+ array = []
455
+ each { |k,v| array << k; array << v }
456
+ array.flatten!(level-1) if level > 1
457
+ Vector.new(array.freeze)
458
+ end
459
+
460
+ # Searches through the `Hash`, comparing `obj` with each key (using `#==`).
461
+ # When a matching key is found, return the `[key, value]` pair as an array.
462
+ # Return `nil` if no match is found.
463
+ #
464
+ # @param obj [Object] The key to search for (using #==)
465
+ # @return [Array]
466
+ def assoc(obj)
467
+ each { |entry| return entry if obj == entry[0] }
468
+ nil
469
+ end
470
+
471
+ # Searches through the `Hash`, comparing `obj` with each value (using `#==`).
472
+ # When a matching value is found, return the `[key, value]` pair as an array.
473
+ # Return `nil` if no match is found.
474
+ #
475
+ # @param obj [Object] The value to search for (using #==)
476
+ # @return [Array]
477
+ def rassoc(obj)
478
+ each { |entry| return entry if obj == entry[1] }
479
+ nil
480
+ end
481
+
482
+ # Searches through the `Hash`, comparing `value` with each value (using `#==`).
483
+ # When a matching value is found, return its associated key object.
484
+ # Return `nil` if no match is found.
485
+ #
486
+ # @param value [Object] The value to search for (using #==)
487
+ # @return [Object]
488
+ def key(value)
489
+ each { |entry| return entry[0] if value == entry[1] }
490
+ nil
491
+ end
492
+
493
+ # Return a randomly chosen `[key, value]` pair from this `Hash`. If the hash is empty,
494
+ # return `nil`.
495
+ #
496
+ # @return [Array]
497
+ def sample
498
+ @trie.at(rand(size))
175
499
  end
176
500
 
501
+ # Return an empty `Hash` instance, of the same class as this one. Useful if you
502
+ # have multiple subclasses of `Hash` and want to treat them polymorphically.
503
+ # Maintains the default block, if there is one.
504
+ #
505
+ # @return [Hash]
177
506
  def clear
178
- self.class.empty
507
+ if @default
508
+ self.class.alloc(EmptyTrie, @default)
509
+ else
510
+ self.class.empty
511
+ end
179
512
  end
180
513
 
181
- # Value-and-type equality
514
+ # Return true if `other` has the same type and contents as this `Hash`.
515
+ #
516
+ # @param other [Object] The collection to compare with
517
+ # @return [Boolean]
182
518
  def eql?(other)
519
+ return true if other.equal?(self)
183
520
  instance_of?(other.class) && @trie.eql?(other.instance_variable_get(:@trie))
184
521
  end
185
522
 
186
- # Value equality, will do type coercion
523
+ # Return true if `other` has the same contents as this `Hash`. Will convert
524
+ # `other` to a Ruby `Hash` using `#to_hash` if necessary.
525
+ #
526
+ # @param other [Object] The object to compare with
527
+ # @return [Boolean]
187
528
  def ==(other)
188
529
  self.eql?(other) || (other.respond_to?(:to_hash) && to_hash.eql?(other.to_hash))
189
530
  end
190
531
 
532
+ # See `Object#hash`.
533
+ # @return [Integer]
191
534
  def hash
192
- keys.sort.reduce(0) do |hash, key|
535
+ keys.to_a.sort.reduce(0) do |hash, key|
193
536
  (hash << 32) - hash + key.hash + get(key).hash
194
537
  end
195
538
  end
@@ -198,10 +541,48 @@ module Hamster
198
541
  def_delegator :self, :dup, :nub
199
542
  def_delegator :self, :dup, :remove_duplicates
200
543
 
544
+ # Return the contents of this `Hash` as a programmer-readable `String`. If all the
545
+ # keys and values are serializable as Ruby literal strings, the returned string can
546
+ # be passed to `eval` to reconstitute an equivalent `Hash`. However, the default
547
+ # block (if there is one) will be lost when doing this.
548
+ #
549
+ # @return [String]
201
550
  def inspect
202
- "{#{reduce([]) { |memo, key, value| memo << "#{key.inspect} => #{value.inspect}" }.join(", ")}}"
551
+ result = "#{self.class}["
552
+ i = 0
553
+ each do |key, val|
554
+ result << ', ' if i > 0
555
+ result << key.inspect << ' => ' << val.inspect
556
+ i += 1
557
+ end
558
+ result << "]"
203
559
  end
204
560
 
561
+ # Allows this `Hash` to be printed at the `pry` console, or using `pp` (from the
562
+ # Ruby standard library), in a way which takes the amount of horizontal space on
563
+ # the screen into account, and which indents nested structures to make them easier
564
+ # to read.
565
+ #
566
+ # @private
567
+ def pretty_print(pp)
568
+ pp.group(1, "#{self.class}[", "]") do
569
+ pp.breakable ''
570
+ pp.seplist(self, nil) do |key, val|
571
+ pp.group do
572
+ key.pretty_print(pp)
573
+ pp.text ' => '
574
+ pp.group(1) do
575
+ pp.breakable ''
576
+ val.pretty_print(pp)
577
+ end
578
+ end
579
+ end
580
+ end
581
+ end
582
+
583
+ # Convert this `Hamster::Hash` to an instance of Ruby's built-in `Hash`.
584
+ #
585
+ # @return [::Hash]
205
586
  def to_hash
206
587
  output = {}
207
588
  each do |key, value|
@@ -209,17 +590,42 @@ module Hamster
209
590
  end
210
591
  output
211
592
  end
593
+ def_delegator :self, :to_hash, :to_h
212
594
 
595
+ # @return [::Hash]
596
+ # @private
213
597
  def marshal_dump
214
598
  to_hash
215
599
  end
216
600
 
601
+ # @private
217
602
  def marshal_load(dictionary)
218
- @trie = dictionary.reduce EmptyTrie do |trie, key_value|
219
- trie.put(key_value.first, key_value.last)
603
+ @trie = Trie[dictionary]
604
+ end
605
+
606
+ private
607
+
608
+ # Return a new `Hash` which is derived from this one, using a modified {Trie}.
609
+ # The new `Hash` will retain the existing default block, if there is one.
610
+ #
611
+ def derive_new_hash(trie)
612
+ if trie.equal?(@trie)
613
+ self
614
+ elsif trie.empty?
615
+ if @default
616
+ self.class.alloc(EmptyTrie, @default)
617
+ else
618
+ self.class.empty
619
+ end
620
+ else
621
+ self.class.alloc(trie, @default)
220
622
  end
221
623
  end
222
624
  end
223
625
 
626
+ # The canonical empty `Hash`. Returned by `Hamster.hash` and `Hash[]` when
627
+ # invoked with no arguments; also returned by `Hash.empty`. Prefer using this
628
+ # one rather than creating many empty hashes using `Hash.new`.
629
+ #
224
630
  EmptyHash = Hamster::Hash.empty
225
631
  end