hamster 1.0.1.pre.rc3 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (358) hide show
  1. checksums.yaml +4 -4
  2. data/lib/hamster.rb +2 -0
  3. data/lib/hamster/associable.rb +49 -0
  4. data/lib/hamster/core_ext/enumerable.rb +3 -13
  5. data/lib/hamster/core_ext/io.rb +1 -1
  6. data/lib/hamster/core_ext/struct.rb +9 -0
  7. data/lib/hamster/deque.rb +57 -38
  8. data/lib/hamster/enumerable.rb +14 -41
  9. data/lib/hamster/experimental/mutable_queue.rb +5 -8
  10. data/lib/hamster/experimental/mutable_set.rb +6 -7
  11. data/lib/hamster/hash.rb +301 -110
  12. data/lib/hamster/immutable.rb +1 -1
  13. data/lib/hamster/list.rb +479 -194
  14. data/lib/hamster/mutable_hash.rb +6 -7
  15. data/lib/hamster/nested.rb +78 -0
  16. data/lib/hamster/read_copy_update.rb +1 -1
  17. data/lib/hamster/set.rb +198 -88
  18. data/lib/hamster/sorted_set.rb +706 -261
  19. data/lib/hamster/trie.rb +134 -15
  20. data/lib/hamster/vector.rb +571 -140
  21. data/lib/hamster/version.rb +3 -1
  22. data/spec/lib/hamster/associable/associable_spec.rb +150 -0
  23. data/spec/lib/hamster/core_ext/array_spec.rb +1 -1
  24. data/spec/lib/hamster/core_ext/enumerable_spec.rb +2 -2
  25. data/spec/lib/hamster/core_ext/io_spec.rb +1 -1
  26. data/spec/lib/hamster/deque/clear_spec.rb +3 -3
  27. data/spec/lib/hamster/deque/construction_spec.rb +8 -8
  28. data/spec/lib/hamster/deque/copying_spec.rb +1 -1
  29. data/spec/lib/hamster/deque/dequeue_spec.rb +12 -4
  30. data/spec/lib/hamster/deque/empty_spec.rb +14 -16
  31. data/spec/lib/hamster/deque/enqueue_spec.rb +4 -4
  32. data/spec/lib/hamster/deque/first_spec.rb +18 -0
  33. data/spec/lib/hamster/deque/inspect_spec.rb +1 -1
  34. data/spec/lib/hamster/deque/last_spec.rb +9 -11
  35. data/spec/lib/hamster/deque/marshal_spec.rb +6 -6
  36. data/spec/lib/hamster/deque/new_spec.rb +5 -5
  37. data/spec/lib/hamster/deque/pop_spec.rb +15 -3
  38. data/spec/lib/hamster/deque/pretty_print_spec.rb +24 -0
  39. data/spec/lib/hamster/deque/push_spec.rb +37 -0
  40. data/spec/lib/hamster/deque/shift_spec.rb +30 -0
  41. data/spec/lib/hamster/deque/size_spec.rb +1 -1
  42. data/spec/lib/hamster/deque/to_a_spec.rb +2 -2
  43. data/spec/lib/hamster/deque/to_ary_spec.rb +1 -1
  44. data/spec/lib/hamster/deque/to_list_spec.rb +3 -3
  45. data/spec/lib/hamster/deque/unshift_spec.rb +8 -3
  46. data/spec/lib/hamster/experimental/mutable_set/add_qm_spec.rb +3 -3
  47. data/spec/lib/hamster/experimental/mutable_set/add_spec.rb +3 -3
  48. data/spec/lib/hamster/experimental/mutable_set/delete_qm_spec.rb +3 -3
  49. data/spec/lib/hamster/experimental/mutable_set/delete_spec.rb +3 -3
  50. data/spec/lib/hamster/hash/all_spec.rb +32 -34
  51. data/spec/lib/hamster/hash/any_spec.rb +34 -36
  52. data/spec/lib/hamster/hash/assoc_spec.rb +3 -3
  53. data/spec/lib/hamster/hash/clear_spec.rb +4 -4
  54. data/spec/lib/hamster/hash/construction_spec.rb +8 -8
  55. data/spec/lib/hamster/hash/copying_spec.rb +1 -1
  56. data/spec/lib/hamster/hash/default_proc_spec.rb +3 -3
  57. data/spec/lib/hamster/hash/delete_spec.rb +4 -4
  58. data/spec/lib/hamster/hash/each_spec.rb +3 -3
  59. data/spec/lib/hamster/hash/each_with_index_spec.rb +1 -1
  60. data/spec/lib/hamster/hash/empty_spec.rb +13 -15
  61. data/spec/lib/hamster/hash/eql_spec.rb +4 -4
  62. data/spec/lib/hamster/hash/except_spec.rb +7 -7
  63. data/spec/lib/hamster/hash/fetch_spec.rb +10 -10
  64. data/spec/lib/hamster/hash/find_spec.rb +2 -2
  65. data/spec/lib/hamster/hash/flat_map_spec.rb +4 -4
  66. data/spec/lib/hamster/hash/flatten_spec.rb +13 -13
  67. data/spec/lib/hamster/hash/get_spec.rb +7 -7
  68. data/spec/lib/hamster/hash/has_key_spec.rb +3 -3
  69. data/spec/lib/hamster/hash/has_value_spec.rb +4 -4
  70. data/spec/lib/hamster/hash/hash_spec.rb +5 -5
  71. data/spec/lib/hamster/hash/inspect_spec.rb +2 -2
  72. data/spec/lib/hamster/hash/invert_spec.rb +6 -6
  73. data/spec/lib/hamster/hash/key_spec.rb +2 -2
  74. data/spec/lib/hamster/hash/keys_spec.rb +2 -2
  75. data/spec/lib/hamster/hash/map_spec.rb +4 -4
  76. data/spec/lib/hamster/hash/marshal_spec.rb +2 -2
  77. data/spec/lib/hamster/hash/merge_spec.rb +62 -56
  78. data/spec/lib/hamster/hash/min_max_spec.rb +9 -13
  79. data/spec/lib/hamster/hash/new_spec.rb +6 -6
  80. data/spec/lib/hamster/hash/none_spec.rb +3 -3
  81. data/spec/lib/hamster/hash/partition_spec.rb +2 -2
  82. data/spec/lib/hamster/hash/put_spec.rb +29 -7
  83. data/spec/lib/hamster/hash/reduce_spec.rb +4 -4
  84. data/spec/lib/hamster/hash/{remove_spec.rb → reject_spec.rb} +7 -7
  85. data/spec/lib/hamster/hash/reverse_each_spec.rb +1 -1
  86. data/spec/lib/hamster/hash/{filter_spec.rb → select_spec.rb} +6 -6
  87. data/spec/lib/hamster/hash/size_spec.rb +3 -3
  88. data/spec/lib/hamster/hash/slice_spec.rb +4 -4
  89. data/spec/lib/hamster/hash/sort_spec.rb +2 -2
  90. data/spec/lib/hamster/hash/store_spec.rb +29 -7
  91. data/spec/lib/hamster/hash/take_spec.rb +2 -2
  92. data/spec/lib/hamster/hash/to_a_spec.rb +1 -1
  93. data/spec/lib/hamster/hash/to_hash_spec.rb +4 -4
  94. data/spec/lib/hamster/hash/values_at_spec.rb +3 -3
  95. data/spec/lib/hamster/hash/values_spec.rb +2 -2
  96. data/spec/lib/hamster/immutable/new_spec.rb +14 -0
  97. data/spec/lib/hamster/list/add_spec.rb +16 -10
  98. data/spec/lib/hamster/list/all_spec.rb +33 -35
  99. data/spec/lib/hamster/list/any_spec.rb +29 -31
  100. data/spec/lib/hamster/list/append_spec.rb +6 -6
  101. data/spec/lib/hamster/list/at_spec.rb +1 -1
  102. data/spec/lib/hamster/list/break_spec.rb +4 -4
  103. data/spec/lib/hamster/list/cadr_spec.rb +9 -9
  104. data/spec/lib/hamster/list/chunk_spec.rb +5 -5
  105. data/spec/lib/hamster/list/clear_spec.rb +3 -3
  106. data/spec/lib/hamster/list/combination_spec.rb +3 -3
  107. data/spec/lib/hamster/list/compact_spec.rb +3 -3
  108. data/spec/lib/hamster/list/compare_spec.rb +3 -3
  109. data/spec/lib/hamster/list/cons_spec.rb +15 -17
  110. data/spec/lib/hamster/list/construction_spec.rb +20 -27
  111. data/spec/lib/hamster/list/copying_spec.rb +1 -1
  112. data/spec/lib/hamster/list/count_spec.rb +1 -1
  113. data/spec/lib/hamster/list/cycle_spec.rb +4 -4
  114. data/spec/lib/hamster/list/delete_at_spec.rb +4 -4
  115. data/spec/lib/hamster/list/drop_spec.rb +3 -3
  116. data/spec/lib/hamster/list/drop_while_spec.rb +3 -3
  117. data/spec/lib/hamster/list/each_slice_spec.rb +5 -5
  118. data/spec/lib/hamster/list/each_spec.rb +26 -28
  119. data/spec/lib/hamster/list/each_with_index_spec.rb +1 -1
  120. data/spec/lib/hamster/list/empty_spec.rb +13 -15
  121. data/spec/lib/hamster/list/eql_spec.rb +21 -21
  122. data/spec/lib/hamster/list/fill_spec.rb +8 -8
  123. data/spec/lib/hamster/list/find_all_spec.rb +3 -3
  124. data/spec/lib/hamster/list/find_index_spec.rb +1 -1
  125. data/spec/lib/hamster/list/find_spec.rb +1 -1
  126. data/spec/lib/hamster/list/flat_map_spec.rb +2 -2
  127. data/spec/lib/hamster/list/flatten_spec.rb +5 -5
  128. data/spec/lib/hamster/list/grep_spec.rb +4 -4
  129. data/spec/lib/hamster/list/group_by_spec.rb +6 -6
  130. data/spec/lib/hamster/list/hash_spec.rb +2 -2
  131. data/spec/lib/hamster/list/head_spec.rb +1 -1
  132. data/spec/lib/hamster/list/include_spec.rb +2 -2
  133. data/spec/lib/hamster/list/index_spec.rb +38 -0
  134. data/spec/lib/hamster/list/indices_spec.rb +62 -0
  135. data/spec/lib/hamster/list/init_spec.rb +3 -3
  136. data/spec/lib/hamster/list/inits_spec.rb +3 -3
  137. data/spec/lib/hamster/list/insert_spec.rb +1 -1
  138. data/spec/lib/hamster/list/inspect_spec.rb +1 -1
  139. data/spec/lib/hamster/list/intersperse_spec.rb +3 -3
  140. data/spec/lib/hamster/list/join_spec.rb +5 -5
  141. data/spec/lib/hamster/list/last_spec.rb +1 -1
  142. data/spec/lib/hamster/list/ltlt_spec.rb +20 -0
  143. data/spec/lib/hamster/list/map_spec.rb +4 -4
  144. data/spec/lib/hamster/list/maximum_spec.rb +24 -26
  145. data/spec/lib/hamster/list/merge_by_spec.rb +10 -10
  146. data/spec/lib/hamster/list/merge_spec.rb +10 -10
  147. data/spec/lib/hamster/list/minimum_spec.rb +24 -26
  148. data/spec/lib/hamster/list/multithreading_spec.rb +6 -6
  149. data/spec/lib/hamster/list/none_spec.rb +5 -5
  150. data/spec/lib/hamster/list/one_spec.rb +5 -5
  151. data/spec/lib/hamster/list/partition_spec.rb +8 -8
  152. data/spec/lib/hamster/list/permutation_spec.rb +8 -8
  153. data/spec/lib/hamster/list/pop_spec.rb +3 -3
  154. data/spec/lib/hamster/list/product_spec.rb +1 -1
  155. data/spec/lib/hamster/list/reduce_spec.rb +5 -48
  156. data/spec/lib/hamster/list/{remove_spec.rb → reject_spec.rb} +4 -4
  157. data/spec/lib/hamster/list/reverse_spec.rb +3 -3
  158. data/spec/lib/hamster/list/rotate_spec.rb +7 -7
  159. data/spec/lib/hamster/list/sample_spec.rb +1 -1
  160. data/spec/lib/hamster/list/select_spec.rb +3 -3
  161. data/spec/lib/hamster/list/size_spec.rb +1 -1
  162. data/spec/lib/hamster/list/slice_spec.rb +123 -123
  163. data/spec/lib/hamster/list/sorting_spec.rb +5 -5
  164. data/spec/lib/hamster/list/span_spec.rb +5 -5
  165. data/spec/lib/hamster/list/split_at_spec.rb +4 -4
  166. data/spec/lib/hamster/list/subsequences_spec.rb +1 -1
  167. data/spec/lib/hamster/list/sum_spec.rb +1 -1
  168. data/spec/lib/hamster/list/tail_spec.rb +4 -4
  169. data/spec/lib/hamster/list/tails_spec.rb +3 -3
  170. data/spec/lib/hamster/list/take_spec.rb +3 -3
  171. data/spec/lib/hamster/list/take_while_spec.rb +4 -4
  172. data/spec/lib/hamster/list/to_a_spec.rb +2 -2
  173. data/spec/lib/hamster/list/to_ary_spec.rb +1 -1
  174. data/spec/lib/hamster/list/to_list_spec.rb +1 -1
  175. data/spec/lib/hamster/list/to_set_spec.rb +1 -1
  176. data/spec/lib/hamster/list/union_spec.rb +4 -4
  177. data/spec/lib/hamster/list/uniq_spec.rb +23 -19
  178. data/spec/lib/hamster/list/zip_spec.rb +5 -5
  179. data/spec/lib/hamster/nested/construction_spec.rb +103 -0
  180. data/spec/lib/hamster/set/add_spec.rb +13 -11
  181. data/spec/lib/hamster/set/all_spec.rb +32 -34
  182. data/spec/lib/hamster/set/any_spec.rb +32 -34
  183. data/spec/lib/hamster/set/clear_spec.rb +3 -3
  184. data/spec/lib/hamster/set/compact_spec.rb +3 -3
  185. data/spec/lib/hamster/set/construction_spec.rb +3 -3
  186. data/spec/lib/hamster/set/copying_spec.rb +1 -1
  187. data/spec/lib/hamster/set/count_spec.rb +1 -1
  188. data/spec/lib/hamster/set/delete_spec.rb +8 -8
  189. data/spec/lib/hamster/set/difference_spec.rb +8 -8
  190. data/spec/lib/hamster/set/disjoint_spec.rb +1 -1
  191. data/spec/lib/hamster/set/each_spec.rb +2 -2
  192. data/spec/lib/hamster/set/empty_spec.rb +15 -17
  193. data/spec/lib/hamster/set/eqeq_spec.rb +3 -3
  194. data/spec/lib/hamster/set/eql_spec.rb +3 -3
  195. data/spec/lib/hamster/set/exclusion_spec.rb +7 -7
  196. data/spec/lib/hamster/set/find_spec.rb +2 -2
  197. data/spec/lib/hamster/set/first_spec.rb +29 -0
  198. data/spec/lib/hamster/set/flatten_spec.rb +9 -9
  199. data/spec/lib/hamster/set/grep_spec.rb +1 -1
  200. data/spec/lib/hamster/set/group_by_spec.rb +12 -12
  201. data/spec/lib/hamster/set/hash_spec.rb +3 -3
  202. data/spec/lib/hamster/set/include_spec.rb +8 -8
  203. data/spec/lib/hamster/set/inspect_spec.rb +2 -2
  204. data/spec/lib/hamster/set/intersect_spec.rb +1 -1
  205. data/spec/lib/hamster/set/intersection_spec.rb +13 -13
  206. data/spec/lib/hamster/set/join_spec.rb +6 -6
  207. data/spec/lib/hamster/set/map_spec.rb +7 -7
  208. data/spec/lib/hamster/set/marshal_spec.rb +2 -2
  209. data/spec/lib/hamster/set/maximum_spec.rb +22 -24
  210. data/spec/lib/hamster/set/minimum_spec.rb +22 -24
  211. data/spec/lib/hamster/set/new_spec.rb +5 -5
  212. data/spec/lib/hamster/set/none_spec.rb +5 -5
  213. data/spec/lib/hamster/set/one_spec.rb +6 -6
  214. data/spec/lib/hamster/set/partition_spec.rb +5 -5
  215. data/spec/lib/hamster/set/product_spec.rb +2 -2
  216. data/spec/lib/hamster/set/reduce_spec.rb +5 -5
  217. data/spec/lib/hamster/set/{remove_spec.rb → reject_spec.rb} +6 -6
  218. data/spec/lib/hamster/set/reverse_each_spec.rb +1 -1
  219. data/spec/lib/hamster/set/sample_spec.rb +1 -1
  220. data/spec/lib/hamster/set/{filter_spec.rb → select_spec.rb} +11 -11
  221. data/spec/lib/hamster/set/size_spec.rb +1 -1
  222. data/spec/lib/hamster/set/sorting_spec.rb +16 -5
  223. data/spec/lib/hamster/set/subset_spec.rb +2 -2
  224. data/spec/lib/hamster/set/sum_spec.rb +2 -2
  225. data/spec/lib/hamster/set/superset_spec.rb +2 -2
  226. data/spec/lib/hamster/set/to_a_spec.rb +2 -2
  227. data/spec/lib/hamster/set/to_list_spec.rb +2 -2
  228. data/spec/lib/hamster/set/to_set_spec.rb +1 -1
  229. data/spec/lib/hamster/set/union_spec.rb +23 -14
  230. data/spec/lib/hamster/sorted_set/above_spec.rb +11 -11
  231. data/spec/lib/hamster/sorted_set/add_spec.rb +8 -8
  232. data/spec/lib/hamster/sorted_set/at_spec.rb +1 -1
  233. data/spec/lib/hamster/sorted_set/below_spec.rb +11 -11
  234. data/spec/lib/hamster/sorted_set/between_spec.rb +11 -11
  235. data/spec/lib/hamster/sorted_set/clear_spec.rb +11 -2
  236. data/spec/lib/hamster/sorted_set/copying_spec.rb +21 -0
  237. data/spec/lib/hamster/sorted_set/delete_at_spec.rb +4 -4
  238. data/spec/lib/hamster/sorted_set/delete_spec.rb +21 -12
  239. data/spec/lib/hamster/sorted_set/difference_spec.rb +2 -2
  240. data/spec/lib/hamster/sorted_set/disjoint_spec.rb +1 -1
  241. data/spec/lib/hamster/sorted_set/drop_spec.rb +30 -3
  242. data/spec/lib/hamster/sorted_set/drop_while_spec.rb +4 -4
  243. data/spec/lib/hamster/sorted_set/each_spec.rb +16 -18
  244. data/spec/lib/hamster/sorted_set/empty_spec.rb +12 -14
  245. data/spec/lib/hamster/sorted_set/eql_spec.rb +5 -5
  246. data/spec/lib/hamster/sorted_set/exclusion_spec.rb +1 -1
  247. data/spec/lib/hamster/sorted_set/fetch_spec.rb +1 -1
  248. data/spec/lib/hamster/sorted_set/find_index_spec.rb +10 -2
  249. data/spec/lib/hamster/sorted_set/first_spec.rb +10 -12
  250. data/spec/lib/hamster/sorted_set/from_spec.rb +11 -11
  251. data/spec/lib/hamster/sorted_set/group_by_spec.rb +10 -10
  252. data/spec/lib/hamster/sorted_set/include_spec.rb +2 -2
  253. data/spec/lib/hamster/sorted_set/inspect_spec.rb +1 -1
  254. data/spec/lib/hamster/sorted_set/intersect_spec.rb +1 -1
  255. data/spec/lib/hamster/sorted_set/intersection_spec.rb +3 -3
  256. data/spec/lib/hamster/sorted_set/last_spec.rb +1 -1
  257. data/spec/lib/hamster/sorted_set/map_spec.rb +13 -5
  258. data/spec/lib/hamster/sorted_set/marshal_spec.rb +3 -3
  259. data/spec/lib/hamster/sorted_set/maximum_spec.rb +37 -0
  260. data/spec/lib/hamster/sorted_set/minimum_spec.rb +11 -13
  261. data/spec/lib/hamster/sorted_set/new_spec.rb +23 -3
  262. data/spec/lib/hamster/sorted_set/reverse_each_spec.rb +2 -2
  263. data/spec/lib/hamster/sorted_set/{filter_spec.rb → select_spec.rb} +10 -10
  264. data/spec/lib/hamster/sorted_set/size_spec.rb +1 -1
  265. data/spec/lib/hamster/sorted_set/slice_spec.rb +158 -142
  266. data/spec/lib/hamster/sorted_set/sorting_spec.rb +3 -3
  267. data/spec/lib/hamster/sorted_set/subset_spec.rb +2 -2
  268. data/spec/lib/hamster/sorted_set/superset_spec.rb +2 -2
  269. data/spec/lib/hamster/sorted_set/take_spec.rb +32 -3
  270. data/spec/lib/hamster/sorted_set/take_while_spec.rb +4 -4
  271. data/spec/lib/hamster/sorted_set/to_set_spec.rb +1 -1
  272. data/spec/lib/hamster/sorted_set/union_spec.rb +2 -2
  273. data/spec/lib/hamster/sorted_set/up_to_spec.rb +12 -11
  274. data/spec/lib/hamster/sorted_set/values_at_spec.rb +6 -6
  275. data/spec/lib/hamster/vector/add_spec.rb +3 -3
  276. data/spec/lib/hamster/vector/any_spec.rb +1 -1
  277. data/spec/lib/hamster/vector/assoc_spec.rb +11 -1
  278. data/spec/lib/hamster/vector/bsearch_spec.rb +10 -2
  279. data/spec/lib/hamster/vector/clear_spec.rb +3 -3
  280. data/spec/lib/hamster/vector/combination_spec.rb +4 -4
  281. data/spec/lib/hamster/vector/compact_spec.rb +2 -2
  282. data/spec/lib/hamster/vector/compare_spec.rb +3 -3
  283. data/spec/lib/hamster/vector/concat_spec.rb +2 -2
  284. data/spec/lib/hamster/vector/copying_spec.rb +1 -1
  285. data/spec/lib/hamster/vector/delete_at_spec.rb +8 -8
  286. data/spec/lib/hamster/vector/delete_spec.rb +2 -2
  287. data/spec/lib/hamster/vector/drop_spec.rb +10 -3
  288. data/spec/lib/hamster/vector/drop_while_spec.rb +5 -5
  289. data/spec/lib/hamster/vector/each_index_spec.rb +2 -2
  290. data/spec/lib/hamster/vector/each_spec.rb +27 -29
  291. data/spec/lib/hamster/vector/each_with_index_spec.rb +2 -2
  292. data/spec/lib/hamster/vector/empty_spec.rb +11 -13
  293. data/spec/lib/hamster/vector/eql_spec.rb +6 -6
  294. data/spec/lib/hamster/vector/fetch_spec.rb +1 -1
  295. data/spec/lib/hamster/vector/fill_spec.rb +9 -9
  296. data/spec/lib/hamster/vector/first_spec.rb +10 -12
  297. data/spec/lib/hamster/vector/flat_map_spec.rb +51 -0
  298. data/spec/lib/hamster/vector/flatten_spec.rb +15 -0
  299. data/spec/lib/hamster/vector/get_spec.rb +4 -4
  300. data/spec/lib/hamster/vector/group_by_spec.rb +12 -12
  301. data/spec/lib/hamster/vector/include_spec.rb +2 -2
  302. data/spec/lib/hamster/vector/insert_spec.rb +2 -2
  303. data/spec/lib/hamster/vector/inspect_spec.rb +1 -1
  304. data/spec/lib/hamster/vector/join_spec.rb +5 -5
  305. data/spec/lib/hamster/vector/last_spec.rb +1 -1
  306. data/spec/lib/hamster/vector/length_spec.rb +1 -1
  307. data/spec/lib/hamster/vector/ltlt_spec.rb +2 -2
  308. data/spec/lib/hamster/vector/map_spec.rb +5 -5
  309. data/spec/lib/hamster/vector/marshal_spec.rb +2 -2
  310. data/spec/lib/hamster/vector/maximum_spec.rb +20 -22
  311. data/spec/lib/hamster/vector/minimum_spec.rb +20 -22
  312. data/spec/lib/hamster/vector/multiply_spec.rb +4 -4
  313. data/spec/lib/hamster/vector/partition_spec.rb +5 -5
  314. data/spec/lib/hamster/vector/permutation_spec.rb +4 -4
  315. data/spec/lib/hamster/vector/pop_spec.rb +3 -3
  316. data/spec/lib/hamster/vector/product_spec.rb +10 -10
  317. data/spec/lib/hamster/vector/put_spec.rb +175 -0
  318. data/spec/lib/hamster/vector/reduce_spec.rb +5 -57
  319. data/spec/lib/hamster/vector/{remove_spec.rb → reject_spec.rb} +4 -4
  320. data/spec/lib/hamster/vector/repeated_combination_spec.rb +4 -4
  321. data/spec/lib/hamster/vector/repeated_permutation_spec.rb +6 -6
  322. data/spec/lib/hamster/vector/reverse_each_spec.rb +1 -1
  323. data/spec/lib/hamster/vector/reverse_spec.rb +1 -1
  324. data/spec/lib/hamster/vector/rindex_spec.rb +1 -1
  325. data/spec/lib/hamster/vector/rotate_spec.rb +9 -9
  326. data/spec/lib/hamster/vector/sample_spec.rb +1 -1
  327. data/spec/lib/hamster/vector/{filter_spec.rb → select_spec.rb} +8 -8
  328. data/spec/lib/hamster/vector/set_spec.rb +12 -141
  329. data/spec/lib/hamster/vector/shift_spec.rb +3 -3
  330. data/spec/lib/hamster/vector/shuffle_spec.rb +2 -2
  331. data/spec/lib/hamster/vector/slice_spec.rb +137 -137
  332. data/spec/lib/hamster/vector/sorting_spec.rb +5 -5
  333. data/spec/lib/hamster/vector/sum_spec.rb +1 -1
  334. data/spec/lib/hamster/vector/take_spec.rb +17 -3
  335. data/spec/lib/hamster/vector/take_while_spec.rb +4 -4
  336. data/spec/lib/hamster/vector/to_a_spec.rb +1 -1
  337. data/spec/lib/hamster/vector/to_ary_spec.rb +1 -1
  338. data/spec/lib/hamster/vector/to_list_spec.rb +2 -1
  339. data/spec/lib/hamster/vector/to_set_spec.rb +1 -1
  340. data/spec/lib/hamster/vector/uniq_spec.rb +27 -6
  341. data/spec/lib/hamster/vector/unshift_spec.rb +3 -3
  342. data/spec/lib/hamster/vector/values_at_spec.rb +6 -6
  343. data/spec/lib/hamster/vector/zip_spec.rb +2 -2
  344. data/spec/lib/load_spec.rb +42 -0
  345. data/spec/spec_helper.rb +25 -0
  346. metadata +85 -48
  347. data/spec/lib/hamster/deque/head_spec.rb +0 -20
  348. data/spec/lib/hamster/hash/uniq_spec.rb +0 -14
  349. data/spec/lib/hamster/list/elem_index_spec.rb +0 -36
  350. data/spec/lib/hamster/list/elem_indices_spec.rb +0 -31
  351. data/spec/lib/hamster/list/filter_spec.rb +0 -71
  352. data/spec/lib/hamster/list/find_indices_spec.rb +0 -37
  353. data/spec/lib/hamster/set/foreach_spec.rb +0 -40
  354. data/spec/lib/hamster/set/head_spec.rb +0 -31
  355. data/spec/lib/hamster/set/uniq_spec.rb +0 -14
  356. data/spec/lib/hamster/sorted_set/construction_spec.rb +0 -29
  357. data/spec/lib/hamster/vector/exist_spec.rb +0 -70
  358. data/spec/lib/hamster/vector/exists_spec.rb +0 -70
@@ -29,7 +29,15 @@ module Hamster
29
29
 
30
30
  # Calls <tt>block</tt> once for each entry in the trie, passing the key-value pair as parameters.
31
31
  def each(&block)
32
- @entries.each { |entry| yield(entry) if entry }
32
+ # TODO: Using block.call here is slower than using yield by 5-10%, but
33
+ # the latter segfaults on ruby 2.2 and above. Once that is fixed and
34
+ # broken versions are sufficiently old, we should revert back to yield
35
+ # with a warning that the broken versions are unsupported.
36
+ #
37
+ # For more context:
38
+ # * https://bugs.ruby-lang.org/issues/11451
39
+ # * https://github.com/hamstergem/hamster/issues/189
40
+ @entries.each { |entry| block.call(entry) if entry }
33
41
  @children.each do |child|
34
42
  child.each(&block) if child
35
43
  end
@@ -49,11 +57,15 @@ module Hamster
49
57
  memo
50
58
  end
51
59
 
52
- def filter
53
- reduce(self) { |trie, entry| yield(entry) ? trie : trie.delete(entry[0]) }
60
+ def select
61
+ keys_to_delete = []
62
+ each { |entry| keys_to_delete << entry[0] unless yield(entry) }
63
+ bulk_delete(keys_to_delete)
54
64
  end
55
65
 
56
- # Returns a copy of <tt>self</tt> with the given value associated with the key.
66
+ # @return [Trie] A copy of `self` with the given value associated with the
67
+ # key (or `self` if no modification was needed because an identical
68
+ # key-value pair wes already stored
57
69
  def put(key, value)
58
70
  index = index_for(key)
59
71
  entry = @entries[index]
@@ -64,22 +76,81 @@ module Hamster
64
76
  entries[index] = [key, value].freeze
65
77
  Trie.new(@significant_bits, @size + 1, entries, @children)
66
78
  elsif entry[0].eql?(key)
67
- entries = @entries.dup
68
- key = key.dup.freeze if key.is_a?(String) && !key.frozen?
69
- entries[index] = [key, value].freeze
70
- Trie.new(@significant_bits, @size, entries, @children)
79
+ if entry[1].equal?(value)
80
+ self
81
+ else
82
+ entries = @entries.dup
83
+ key = key.dup.freeze if key.is_a?(String) && !key.frozen?
84
+ entries[index] = [key, value].freeze
85
+ Trie.new(@significant_bits, @size, entries, @children)
86
+ end
71
87
  else
72
- children = @children.dup
73
- child = children[index]
74
- child_size = child ? child.size : 0
88
+ child = @children[index]
75
89
  if child
76
- children[index] = child.put(key, value)
90
+ new_child = child.put(key, value)
91
+ if new_child.equal?(child)
92
+ self
93
+ else
94
+ children = @children.dup
95
+ children[index] = new_child
96
+ new_self_size = @size + (new_child.size - child.size)
97
+ Trie.new(@significant_bits, new_self_size, @entries, children)
98
+ end
77
99
  else
100
+ children = @children.dup
78
101
  children[index] = Trie.new(@significant_bits + 5).put!(key, value)
102
+ Trie.new(@significant_bits, @size + 1, @entries, children)
79
103
  end
80
- new_child_size = children[index].size
81
- new_self_size = @size + (new_child_size - child_size)
82
- Trie.new(@significant_bits, new_self_size, @entries, children)
104
+ end
105
+ end
106
+
107
+ # Put multiple elements into a Trie. This is more efficient than several
108
+ # calls to `#put`.
109
+ #
110
+ # @param key_value_pairs Enumerable of pairs (`[key, value]`)
111
+ # @return [Trie] A copy of `self` after associated the given keys and
112
+ # values (or `self` if no modifications where needed).
113
+ def bulk_put(key_value_pairs)
114
+ new_entries = nil
115
+ new_children = nil
116
+ new_size = @size
117
+
118
+ key_value_pairs.each do |key, value|
119
+ index = index_for(key)
120
+ entry = (new_entries || @entries)[index]
121
+
122
+ if !entry
123
+ new_entries ||= @entries.dup
124
+ key = key.dup.freeze if key.is_a?(String) && !key.frozen?
125
+ new_entries[index] = [key, value].freeze
126
+ new_size += 1
127
+ elsif entry[0].eql?(key)
128
+ if !entry[1].equal?(value)
129
+ new_entries ||= @entries.dup
130
+ key = key.dup.freeze if key.is_a?(String) && !key.frozen?
131
+ new_entries[index] = [key, value].freeze
132
+ end
133
+ else
134
+ child = (new_children || @children)[index]
135
+ if child
136
+ new_child = child.put(key, value)
137
+ if !new_child.equal?(child)
138
+ new_children ||= @children.dup
139
+ new_children[index] = new_child
140
+ new_size += new_child.size - child.size
141
+ end
142
+ else
143
+ new_children ||= @children.dup
144
+ new_children[index] = Trie.new(@significant_bits + 5).put!(key, value)
145
+ new_size += 1
146
+ end
147
+ end
148
+ end
149
+
150
+ if new_entries || new_children
151
+ Trie.new(@significant_bits, new_size, new_entries || @entries, new_children || @children)
152
+ else
153
+ self
83
154
  end
84
155
  end
85
156
 
@@ -125,6 +196,54 @@ module Hamster
125
196
  find_and_delete(key) || Trie.new(@significant_bits)
126
197
  end
127
198
 
199
+ # Delete multiple elements from a Trie. This is more efficient than
200
+ # several calls to `#delete`.
201
+ #
202
+ # @param keys [Enumerable] The keys to delete
203
+ # @return [Trie]
204
+ def bulk_delete(keys)
205
+ new_entries = nil
206
+ new_children = nil
207
+ new_size = @size
208
+
209
+ keys.each do |key|
210
+ index = index_for(key)
211
+ entry = (new_entries || @entries)[index]
212
+ if !entry
213
+ next
214
+ elsif entry[0].eql?(key)
215
+ new_entries ||= @entries.dup
216
+ child = (new_children || @children)[index]
217
+ if child
218
+ # Bring up the first entry from the child into entries
219
+ new_children ||= @children.dup
220
+ new_children[index] = child.delete_at do |entry|
221
+ new_entries[index] = entry
222
+ end
223
+ else
224
+ new_entries[index] = nil
225
+ end
226
+ new_size -= 1
227
+ else
228
+ child = (new_children || @children)[index]
229
+ if child
230
+ copy = child.find_and_delete(key)
231
+ unless copy.equal?(child)
232
+ new_children ||= @children.dup
233
+ new_children[index] = copy
234
+ new_size -= (child.size - copy_size(copy))
235
+ end
236
+ end
237
+ end
238
+ end
239
+
240
+ if new_entries || new_children
241
+ Trie.new(@significant_bits, new_size, new_entries || @entries, new_children || @children)
242
+ else
243
+ self
244
+ end
245
+ end
246
+
128
247
  def include?(key, value)
129
248
  entry = get(key)
130
249
  entry && value.eql?(entry[1])
@@ -1,31 +1,27 @@
1
- require "forwardable"
2
1
  require "hamster/immutable"
3
2
  require "hamster/enumerable"
3
+ require "hamster/hash"
4
+ require "hamster/associable"
4
5
 
5
6
  module Hamster
6
- def self.vector(*items)
7
- items.empty? ? EmptyVector : Vector.new(items.freeze)
8
- end
9
-
10
- # A `Vector` is an ordered, integer-indexed collection of objects. Like `Array`,
11
- # `Vector` indexing starts at 0. Also like `Array`, negative indexes count back
12
- # from the end of the `Vector`.
7
+ # A `Vector` is an ordered, integer-indexed collection of objects. Like
8
+ # Ruby's `Array`, `Vector` indexing starts at zero and negative indexes count
9
+ # back from the end.
13
10
  #
14
- # `Vector`'s interface is modeled after that of `Array`, minus all the methods
15
- # which do destructive updates. Some methods which modify `Array`s destructively
16
- # (like {#insert} or {#delete_at}) are included, but they return new `Vectors`
17
- # and leave the existing one unchanged.
11
+ # `Vector` has a similar interface to `Array`. The main difference is methods
12
+ # that would destructively update an `Array` (such as {#insert} or
13
+ # {#delete_at}) instead return new `Vectors` and leave the existing one
14
+ # unchanged.
18
15
  #
19
- # = Creating New Vectors
16
+ # ### Creating New Vectors
20
17
  #
21
- # Hamster.vector('a', 'b', 'c')
22
18
  # Hamster::Vector.new([:first, :second, :third])
23
19
  # Hamster::Vector[1, 2, 3, 4, 5]
24
20
  #
25
- # = Retrieving Items from Vectors
21
+ # ### Retrieving Items from Vectors
22
+ #
23
+ # vector = Hamster::Vector[1, 2, 3, 4, 5]
26
24
  #
27
- # require 'hamster/vector'
28
- # vector = Hamster.vector(1, 2, 3, 4, 5)
29
25
  # vector[0] # => 1
30
26
  # vector[-1] # => 5
31
27
  # vector[0,3] # => Hamster::Vector[1, 2, 3]
@@ -33,21 +29,17 @@ module Hamster
33
29
  # vector.first # => 1
34
30
  # vector.last # => 5
35
31
  #
36
- # = Creating Modified Vectors
32
+ # ### Creating Modified Vectors
37
33
  #
38
34
  # vector.add(6) # => Hamster::Vector[1, 2, 3, 4, 5, 6]
39
35
  # vector.insert(1, :a, :b) # => Hamster::Vector[1, :a, :b, 2, 3, 4, 5]
40
36
  # vector.delete_at(2) # => Hamster::Vector[1, 2, 4, 5]
41
37
  # vector + [6, 7] # => Hamster::Vector[1, 2, 3, 4, 5, 6, 7]
42
38
  #
43
- # Other `Array`-like methods like {#select}, {#map}, {#shuffle}, {#uniq}, {#reverse},
44
- # {#rotate}, {#flatten}, {#sort}, {#sort_by}, {#take}, {#drop}, {#take_while},
45
- # {#drop_while}, {#fill}, {#product}, and {#transpose} are also supported.
46
- #
47
39
  class Vector
48
- extend Forwardable
49
40
  include Immutable
50
41
  include Enumerable
42
+ include Associable
51
43
 
52
44
  # @private
53
45
  BLOCK_SIZE = 32
@@ -59,7 +51,7 @@ module Hamster
59
51
  # Return the number of items in this `Vector`
60
52
  # @return [Integer]
61
53
  attr_reader :size
62
- def_delegator :self, :size, :length
54
+ alias :length :size
63
55
 
64
56
  class << self
65
57
  # Create a new `Vector` populated with the given items.
@@ -111,18 +103,22 @@ module Hamster
111
103
  def empty?
112
104
  @size == 0
113
105
  end
114
- def_delegator :self, :empty?, :null?
115
106
 
116
107
  # Return the first item in the `Vector`. If the vector is empty, return `nil`.
117
108
  #
109
+ # @example
110
+ # Hamster::Vector["A", "B", "C"].first # => "A"
111
+ #
118
112
  # @return [Object]
119
113
  def first
120
114
  get(0)
121
115
  end
122
- def_delegator :self, :first, :head
123
116
 
124
117
  # Return the last item in the `Vector`. If the vector is empty, return `nil`.
125
118
  #
119
+ # @example
120
+ # Hamster::Vector["A", "B", "C"].last # => "C"
121
+ #
126
122
  # @return [Object]
127
123
  def last
128
124
  get(-1)
@@ -130,33 +126,88 @@ module Hamster
130
126
 
131
127
  # Return a new `Vector` with `item` added after the last occupied position.
132
128
  #
129
+ # @example
130
+ # Hamster::Vector[1, 2].add(99) # => Hamster::Vector[1, 2, 99]
131
+ #
133
132
  # @param item [Object] The object to insert at the end of the vector
134
133
  # @return [Vector]
135
134
  def add(item)
136
135
  update_root(@size, item)
137
136
  end
138
- def_delegator :self, :add, :<<
139
- def_delegator :self, :add, :conj
140
- def_delegator :self, :add, :conjoin
141
- def_delegator :self, :add, :push
137
+ alias :<< :add
138
+ alias :push :add
142
139
 
143
- # Return a new `Vector` with the item at `index` replaced by `item`. If the
144
- # `item` argument is missing, but an optional code block is provided, it will
145
- # be passed the existing item and what the block returns will replace it.
140
+ # Return a new `Vector` with a new value at the given `index`. If `index`
141
+ # is greater than the length of the vector, the returned vector will be
142
+ # padded with `nil`s to the correct size.
143
+ #
144
+ # @overload put(index, item)
145
+ # Return a new `Vector` with the item at `index` replaced by `item`.
146
146
  #
147
- # @param index [Integer] The index to update
148
- # @param item [Object] The object to insert into that position
147
+ # @param item [Object] The object to insert into that position
148
+ # @example
149
+ # Hamster::Vector[1, 2, 3, 4].put(2, 99)
150
+ # # => Hamster::Vector[1, 2, 99, 4]
151
+ # Hamster::Vector[1, 2, 3, 4].put(-1, 99)
152
+ # # => Hamster::Vector[1, 2, 3, 99]
153
+ # Hamster::Vector[].put(2, 99)
154
+ # # => Hamster::Vector[nil, nil, 99]
155
+ #
156
+ # @overload put(index)
157
+ # Return a new `Vector` with the item at `index` replaced by the return
158
+ # value of the block.
159
+ #
160
+ # @yield (existing) Once with the existing value at the given `index`.
161
+ # @example
162
+ # Hamster::Vector[1, 2, 3, 4].put(2) { |v| v * 10 }
163
+ # # => Hamster::Vector[1, 2, 30, 4]
164
+ #
165
+ # @param index [Integer] The index to update. May be negative.
149
166
  # @return [Vector]
150
- def set(index, item = yield(get(index)))
151
- raise IndexError if @size == 0
167
+ def put(index, item = yield(get(index)))
168
+ raise IndexError, "index #{index} outside of vector bounds" if index < -@size
152
169
  index += @size if index < 0
153
- raise IndexError if index > @size || index < 0
154
- update_root(index, item)
170
+ if index > @size
171
+ suffix = Array.new(index - @size, nil)
172
+ suffix << item
173
+ replace_suffix(@size, suffix)
174
+ else
175
+ update_root(index, item)
176
+ end
155
177
  end
178
+ alias :set :put
179
+
180
+ # Return a new `Vector` with a deeply nested value modified to the result
181
+ # of the given code block. When traversing the nested `Vector`s and
182
+ # `Hash`es, non-existing keys are created with empty `Hash` values.
183
+ #
184
+ # The code block receives the existing value of the deeply nested key (or
185
+ # `nil` if it doesn't exist). This is useful for "transforming" the value
186
+ # associated with a certain key.
187
+ #
188
+ # Note that the original `Vector` and sub-`Vector`s and sub-`Hash`es are
189
+ # left unmodified; new data structure copies are created along the path
190
+ # wherever needed.
191
+ #
192
+ # @example
193
+ # v = Hamster::Vector[123, 456, 789, Hamster::Hash["a" => Hamster::Vector[5, 6, 7]]]
194
+ # v.update_in(3, "a", 1) { |value| value + 9 }
195
+ # # => Hamster::Vector[123, 456, 789, Hamster::Hash["a" => Hamster::Vector[5, 15, 7]]]
196
+ #
197
+ # @param key_path [Object(s)] List of keys which form the path to the key to be modified
198
+ # @yield [value] The previously stored value
199
+ # @yieldreturn [Object] The new value to store
200
+ # @return [Vector]
156
201
 
157
202
  # Retrieve the item at `index`. If there is none (either the provided index
158
203
  # is too high or too low), return `nil`.
159
204
  #
205
+ # @example
206
+ # v = Hamster::Vector["A", "B", "C", "D"]
207
+ # v.get(2) # => "C"
208
+ # v.get(-1) # => "D"
209
+ # v.get(4) # => nil
210
+ #
160
211
  # @param index [Integer] The index to retrieve
161
212
  # @return [Object]
162
213
  def get(index)
@@ -165,26 +216,45 @@ module Hamster
165
216
  return nil if index >= @size || index < 0
166
217
  leaf_node_for(@root, @levels * BITS_PER_LEVEL, index)[index & INDEX_MASK]
167
218
  end
168
- def_delegator :self, :get, :at
219
+ alias :at :get
169
220
 
170
- # Retrieve the value at `index`, or use the provided default value or block,
171
- # or otherwise raise an `IndexError`.
221
+ # Retrieve the value at `index` with optional default.
172
222
  #
173
223
  # @overload fetch(index)
174
- # Retrieve the value at the given index, or raise an `IndexError` if it is
175
- # not found.
224
+ # Retrieve the value at the given index, or raise an `IndexError` if not
225
+ # found.
226
+ #
176
227
  # @param index [Integer] The index to look up
228
+ # @raise [IndexError] if index does not exist
229
+ # @example
230
+ # v = Hamster::Vector["A", "B", "C", "D"]
231
+ # v.fetch(2) # => "C"
232
+ # v.fetch(-1) # => "D"
233
+ # v.fetch(4) # => IndexError: index 4 outside of vector bounds
234
+ #
177
235
  # @overload fetch(index) { |index| ... }
178
- # Retrieve the value at the given index, or call the optional
179
- # code block (with the non-existent index) and get its return value.
180
- # @yield [index] The index which does not exist
181
- # @yieldreturn [Object] Object to return instead
236
+ # Retrieve the value at the given index, or return the result of yielding
237
+ # the block if not found.
238
+ #
239
+ # @yield Once if the index is not found.
240
+ # @yieldparam [Integer] index The index which does not exist
241
+ # @yieldreturn [Object] Default value to return
182
242
  # @param index [Integer] The index to look up
243
+ # @example
244
+ # v = Hamster::Vector["A", "B", "C", "D"]
245
+ # v.fetch(2) { |i| i * i } # => "C"
246
+ # v.fetch(4) { |i| i * i } # => 16
247
+ #
183
248
  # @overload fetch(index, default)
184
- # Retrieve the value at the given index, or else return the provided
185
- # `default` value.
249
+ # Retrieve the value at the given index, or return the provided `default`
250
+ # value if not found.
251
+ #
186
252
  # @param index [Integer] The index to look up
187
253
  # @param default [Object] Object to return if the key is not found
254
+ # @example
255
+ # v = Hamster::Vector["A", "B", "C", "D"]
256
+ # v.fetch(2, "Z") # => "C"
257
+ # v.fetch(4, "Z") # => "Z"
188
258
  #
189
259
  # @return [Object]
190
260
  def fetch(index, default = (missing_default = true))
@@ -199,22 +269,47 @@ module Hamster
199
269
  end
200
270
  end
201
271
 
202
- # Element reference. Return the item at a specific index, or a specified,
203
- # contiguous range of items (as a new `Vector`).
272
+ # Return specific objects from the `Vector`. All overloads return `nil` if
273
+ # the starting index is out of range.
274
+ #
275
+ # @overload vector.slice(index)
276
+ # Returns a single object at the given `index`. If `index` is negative,
277
+ # count backwards from the end.
278
+ #
279
+ # @param index [Integer] The index to retrieve. May be negative.
280
+ # @return [Object]
281
+ # @example
282
+ # v = Hamster::Vector["A", "B", "C", "D", "E", "F"]
283
+ # v[2] # => "C"
284
+ # v[-1] # => "F"
285
+ # v[6] # => nil
286
+ #
287
+ # @overload vector.slice(index, length)
288
+ # Return a subvector starting at `index` and continuing for `length`
289
+ # elements or until the end of the `Vector`, whichever occurs first.
204
290
  #
205
- # @overload vector[index]
206
- # Return the item at `index`.
207
- # @param index [Integer] The index to retrieve.
208
- # @overload vector[start, length]
209
- # Return a subvector starting at index `start` and continuing for `length` elements.
210
- # @param start [Integer] The index to start retrieving items from.
291
+ # @param start [Integer] The index to start retrieving items from. May be
292
+ # negative.
211
293
  # @param length [Integer] The number of items to retrieve.
212
- # @overload vector[range]
213
- # Return a subvector specified by the given `range` of indices.
214
- # @param range [Range] The range of indices to retrieve.
294
+ # @return [Vector]
295
+ # @example
296
+ # v = Hamster::Vector["A", "B", "C", "D", "E", "F"]
297
+ # v[2, 3] # => Hamster::Vector["C", "D", "E"]
298
+ # v[-2, 3] # => Hamster::Vector["E", "F"]
299
+ # v[20, 1] # => nil
215
300
  #
216
- # @return [Object]
217
- def [](arg, length = (missing_length = true))
301
+ # @overload vector.slice(index..end)
302
+ # Return a subvector starting at `index` and continuing to index
303
+ # `end` or the end of the `Vector`, whichever occurs first.
304
+ #
305
+ # @param range [Range] The range of indices to retrieve.
306
+ # @return [Vector]
307
+ # @example
308
+ # v = Hamster::Vector["A", "B", "C", "D", "E", "F"]
309
+ # v[2..3] # => Hamster::Vector["C", "D"]
310
+ # v[-2..100] # => Hamster::Vector["E", "F"]
311
+ # v[20..21] # => nil
312
+ def slice(arg, length = (missing_length = true))
218
313
  if missing_length
219
314
  if arg.is_a?(Range)
220
315
  from, to = arg.begin, arg.end
@@ -232,13 +327,22 @@ module Hamster
232
327
  subsequence(arg, length)
233
328
  end
234
329
  end
235
- def_delegator :self, :[], :slice
330
+ alias :[] :slice
236
331
 
237
- # Return a new `Vector` with the given values inserted before the element at `index`.
332
+ # Return a new `Vector` with the given values inserted before the element
333
+ # at `index`. If `index` is greater than the current length, `nil` values
334
+ # are added to pad the `Vector` to the required size.
335
+ #
336
+ # @example
337
+ # Hamster::Vector["A", "B", "C", "D"].insert(2, "X", "Y", "Z")
338
+ # # => Hamster::Vector["A", "B", "X", "Y", "Z", "C", "D"]
339
+ # Hamster::Vector[].insert(2, "X", "Y", "Z")
340
+ # # => Hamster::Vector[nil, nil, "X", "Y", "Z"]
238
341
  #
239
342
  # @param index [Integer] The index where the new items should go
240
343
  # @param items [Array] The items to add
241
344
  # @return [Vector]
345
+ # @raise [IndexError] if index exceeds negative range.
242
346
  def insert(index, *items)
243
347
  raise IndexError if index < -@size
244
348
  index += @size if index < 0
@@ -259,6 +363,10 @@ module Hamster
259
363
  # Return a new `Vector` with the element at `index` removed. If the given `index`
260
364
  # does not exist, return `self`.
261
365
  #
366
+ # @example
367
+ # Hamster::Vector["A", "B", "C", "D"].delete_at(2)
368
+ # # => Hamster::Vector["A", "B", "D"]
369
+ #
262
370
  # @param index [Integer] The index to remove
263
371
  # @return [Vector]
264
372
  def delete_at(index)
@@ -269,40 +377,70 @@ module Hamster
269
377
  replace_suffix(index, suffix.tap { |a| a.shift })
270
378
  end
271
379
 
272
- # Return a new `Vector` with the last element removed. If empty, just return `self`.
380
+ # Return a new `Vector` with the last element removed. Return `self` if
381
+ # empty.
382
+ #
383
+ # @example
384
+ # Hamster::Vector["A", "B", "C"].pop # => Hamster::Vector["A", "B"]
385
+ #
273
386
  # @return [Vector]
274
387
  def pop
275
388
  return self if @size == 0
276
389
  replace_suffix(@size-1, [])
277
390
  end
278
391
 
279
- # Return a new `Vector` with `obj` inserted before the first element, moving
280
- # the other elements upwards.
281
- # @param obj [Object] The value to prepend
392
+ # Return a new `Vector` with `object` inserted before the first element,
393
+ # moving the other elements upwards.
394
+ #
395
+ # @example
396
+ # Hamster::Vector["A", "B"].unshift("Z")
397
+ # # => Hamster::Vector["Z", "A", "B"]
398
+ #
399
+ # @param object [Object] The value to prepend
282
400
  # @return [Vector]
283
- def unshift(obj)
284
- insert(0, obj)
401
+ def unshift(object)
402
+ insert(0, object)
285
403
  end
286
404
 
287
- # Return a new `Vector` with the first element removed. If empty, just return `self`.
405
+ # Return a new `Vector` with the first element removed. If empty, return
406
+ # `self`.
407
+ #
408
+ # @example
409
+ # Hamster::Vector["A", "B", "C"].shift # => Hamster::Vector["B", "C"]
410
+ #
288
411
  # @return [Vector]
289
412
  def shift
290
413
  delete_at(0)
291
414
  end
292
415
 
293
416
  # Call the given block once for each item in the vector, passing each
294
- # item from first to last successively to the block.
417
+ # item from first to last successively to the block. If no block is given,
418
+ # an `Enumerator` is returned instead.
295
419
  #
296
- # @return [self]
420
+ # @example
421
+ # Hamster::Vector["A", "B", "C"].each { |e| puts "Element: #{e}" }
422
+ #
423
+ # Element: A
424
+ # Element: B
425
+ # Element: C
426
+ # # => Hamster::Vector["A", "B", "C"]
427
+ #
428
+ # @return [self, Enumerator]
297
429
  def each(&block)
298
430
  return to_enum unless block_given?
299
431
  traverse_depth_first(@root, @levels, &block)
300
432
  self
301
433
  end
302
434
 
303
- # Call the given block once for each item in the vector, passing each
304
- # item starting from the last, and counting back to the first, successively to
305
- # the block.
435
+ # Call the given block once for each item in the vector, from last to
436
+ # first.
437
+ #
438
+ # @example
439
+ # Hamster::Vector["A", "B", "C"].reverse_each { |e| puts "Element: #{e}" }
440
+ #
441
+ # Element: C
442
+ # Element: B
443
+ # Element: A
306
444
  #
307
445
  # @return [self]
308
446
  def reverse_each(&block)
@@ -314,34 +452,65 @@ module Hamster
314
452
  # Return a new `Vector` containing all elements for which the given block returns
315
453
  # true.
316
454
  #
455
+ # @example
456
+ # Hamster::Vector["Bird", "Cow", "Elephant"].select { |e| e.size >= 4 }
457
+ # # => Hamster::Vector["Bird", "Elephant"]
458
+ #
317
459
  # @return [Vector]
318
- def filter
319
- return enum_for(:filter) unless block_given?
460
+ # @yield [element] Once for each element.
461
+ def select
462
+ return enum_for(:select) unless block_given?
320
463
  reduce(self.class.empty) { |vector, item| yield(item) ? vector.add(item) : vector }
321
464
  end
465
+ alias :find_all :select
466
+ alias :keep_if :select
322
467
 
323
468
  # Return a new `Vector` with all items which are equal to `obj` removed.
324
469
  # `#==` is used for checking equality.
325
470
  #
471
+ # @example
472
+ # Hamster::Vector["C", "B", "A", "B"].delete("B") # => Hamster::Vector["C", "A"]
473
+ #
326
474
  # @param obj [Object] The object to remove (every occurrence)
327
475
  # @return [Vector]
328
476
  def delete(obj)
329
- filter { |item| item != obj }
477
+ select { |item| item != obj }
330
478
  end
331
479
 
332
480
  # Invoke the given block once for each item in the vector, and return a new
333
- # `Vector` containing the values returned by the block.
481
+ # `Vector` containing the values returned by the block. If no block is
482
+ # provided, return an enumerator.
334
483
  #
335
- # @return [Vector]
484
+ # @example
485
+ # Hamster::Vector[3, 2, 1].map { |e| e * e } # => Hamster::Vector[9, 4, 1]
486
+ #
487
+ # @return [Vector, Enumerator]
336
488
  def map
337
489
  return enum_for(:map) if not block_given?
338
490
  return self if empty?
339
491
  self.class.new(super)
340
492
  end
341
- def_delegator :self, :map, :collect
493
+ alias :collect :map
494
+
495
+ # Return a new `Vector` with the concatenated results of running the block once
496
+ # for every element in this `Vector`.
497
+ #
498
+ # @example
499
+ # Hamster::Vector[1, 2, 3].flat_map { |x| [x, -x] }
500
+ # # => Hamster::Vector[1, -1, 2, -2, 3, -3]
501
+ #
502
+ # @return [Vector]
503
+ def flat_map
504
+ return enum_for(:flat_map) if not block_given?
505
+ return self if empty?
506
+ self.class.new(super)
507
+ end
342
508
 
343
509
  # Return a new `Vector` with the same elements as this one, but randomly permuted.
344
510
  #
511
+ # @example
512
+ # Hamster::Vector[1, 2, 3, 4].shuffle # => Hamster::Vector[4, 1, 3, 2]
513
+ #
345
514
  # @return [Vector]
346
515
  def shuffle
347
516
  self.class.new(((array = to_a).frozen? ? array.shuffle : array.shuffle!).freeze)
@@ -350,13 +519,35 @@ module Hamster
350
519
  # Return a new `Vector` with no duplicate elements, as determined by `#hash` and
351
520
  # `#eql?`. For each group of equivalent elements, only the first will be retained.
352
521
  #
522
+ # @example
523
+ # Hamster::Vector["A", "B", "C", "B"].uniq # => Hamster::Vector["A", "B", "C"]
524
+ # Hamster::Vector["a", "A", "b"].uniq(&:upcase) # => Hamster::Vector["a", "b"]
525
+ #
353
526
  # @return [Vector]
354
- def uniq
355
- self.class.new(((array = to_a).frozen? ? array.uniq : array.uniq!).freeze)
527
+ def uniq(&block)
528
+ array = self.to_a
529
+ if block_given?
530
+ if array.frozen?
531
+ self.class.new(array.uniq(&block).freeze)
532
+ elsif array.uniq!(&block) # returns nil if no changes were made
533
+ self.class.new(array.freeze)
534
+ else
535
+ self
536
+ end
537
+ elsif array.frozen?
538
+ self.class.new(array.uniq.freeze)
539
+ elsif array.uniq! # returns nil if no changes were made
540
+ self.class.new(array.freeze)
541
+ else
542
+ self
543
+ end
356
544
  end
357
545
 
358
546
  # Return a new `Vector` with the same elements as this one, but in reverse order.
359
547
  #
548
+ # @example
549
+ # Hamster::Vector["A", "B", "C"].reverse # => Hamster::Vector["C", "B", "A"]
550
+ #
360
551
  # @return [Vector]
361
552
  def reverse
362
553
  self.class.new(((array = to_a).frozen? ? array.reverse : array.reverse!).freeze)
@@ -368,6 +559,11 @@ module Hamster
368
559
  # will be moved to the end. If `count` is negative, the elements will be shifted
369
560
  # right, and those shifted past the last position will be moved to the beginning.
370
561
  #
562
+ # @example
563
+ # v = Hamster::Vector["A", "B", "C", "D", "E", "F"]
564
+ # v.rotate(2) # => Hamster::Vector["C", "D", "E", "F", "A", "B"]
565
+ # v.rotate(-1) # => Hamster::Vector["F", "A", "B", "C", "D", "E"]
566
+ #
371
567
  # @param count [Integer] The number of positions to shift items by
372
568
  # @return [Vector]
373
569
  def rotate(count = 1)
@@ -376,22 +572,40 @@ module Hamster
376
572
  end
377
573
 
378
574
  # Return a new `Vector` with all nested vectors and arrays recursively "flattened
379
- # out", that is, their elements inserted into the new `Vector` in the place where
575
+ # out". That is, their elements inserted into the new `Vector` in the place where
380
576
  # the nested array/vector originally was. If an optional `level` argument is
381
577
  # provided, the flattening will only be done recursively that number of times.
382
578
  # A `level` of 0 means not to flatten at all, 1 means to only flatten nested
383
579
  # arrays/vectors which are directly contained within this `Vector`.
384
580
  #
581
+ # @example
582
+ # v = Hamster::Vector["A", Hamster::Vector["B", "C", Hamster::Vector["D"]]]
583
+ # v.flatten(1)
584
+ # # => Hamster::Vector["A", "B", "C", Hamster::Vector["D"]]
585
+ # v.flatten
586
+ # # => Hamster::Vector["A", "B", "C", "D"]
587
+ #
385
588
  # @param level [Integer] The depth to which flattening should be applied
386
589
  # @return [Vector]
387
- def flatten(level = nil)
590
+ def flatten(level = -1)
388
591
  return self if level == 0
389
- self.class.new(((array = to_a).frozen? ? array.flatten(level) : array.flatten!(level)).freeze)
592
+ array = self.to_a
593
+ if array.frozen?
594
+ self.class.new(array.flatten(level).freeze)
595
+ elsif array.flatten!(level) # returns nil if no changes were made
596
+ self.class.new(array.freeze)
597
+ else
598
+ self
599
+ end
390
600
  end
391
601
 
392
602
  # Return a new `Vector` built by concatenating this one with `other`. `other`
393
603
  # can be any object which is convertible to an `Array` using `#to_a`.
394
604
  #
605
+ # @example
606
+ # Hamster::Vector["A", "B", "C"] + ["D", "E"]
607
+ # # => Hamster::Vector["A", "B", "C", "D", "E"]
608
+ #
395
609
  # @param other [Enumerable] The collection to concatenate onto this vector
396
610
  # @return [Vector]
397
611
  def +(other)
@@ -399,17 +613,33 @@ module Hamster
399
613
  other = other.dup if other.frozen?
400
614
  replace_suffix(@size, other)
401
615
  end
402
- def_delegator :self, :+, :concat
616
+ alias :concat :+
403
617
 
404
- # `others` should be arrays and/or vectors. The corresponding elements from this
405
- # `Vector` and each of `others` (that is, the elements with the same indices)
406
- # will be gathered into arrays.
618
+ # Combine two vectors by "zipping" them together. `others` should be arrays
619
+ # and/or vectors. The corresponding elements from this `Vector` and each of
620
+ # `others` (that is, the elements with the same indices) will be gathered
621
+ # into arrays.
622
+ #
623
+ # If `others` contains fewer elements than this vector, `nil` will be used
624
+ # for padding.
407
625
  #
408
- # If an optional block is provided, each such array will be passed successively
409
- # to the block. Otherwise, a new `Vector` of all those arrays will be returned.
626
+ # @overload zip(*others)
627
+ # Return a new vector containing the new arrays.
628
+ #
629
+ # @return [Vector]
630
+ #
631
+ # @overload zip(*others)
632
+ # @yield [pair] once for each array
633
+ # @return [nil]
634
+ #
635
+ # @example
636
+ # v1 = Hamster::Vector["A", "B", "C"]
637
+ # v2 = Hamster::Vector[1, 2]
638
+ # v1.zip(v2)
639
+ # # => Hamster::Vector[["A", 1], ["B", 2], ["C", nil]]
410
640
  #
411
641
  # @param others [Array] The arrays/vectors to zip together with this one
412
- # @return [Vector, nil]
642
+ # @return [Vector]
413
643
  def zip(*others)
414
644
  if block_given?
415
645
  super
@@ -418,20 +648,41 @@ module Hamster
418
648
  end
419
649
  end
420
650
 
421
- # Return a new `Vector` with the same items, but sorted. The sort order will
422
- # be determined by comparing items using `#<=>`, or if an optional code block
423
- # is provided, by using it as a comparator. The block should accept 2 parameters,
424
- # and should return 0, 1, or -1 if the first parameter is equal to, greater than,
425
- # or less than the second parameter (respectively).
651
+ # Return a new `Vector` with the same items, but sorted.
652
+ #
653
+ # @overload sort
654
+ # Compare elements with their natural sort key (`#<=>`).
655
+ #
656
+ # @example
657
+ # Hamster::Vector["Elephant", "Dog", "Lion"].sort
658
+ # # => Hamster::Vector["Dog", "Elephant", "Lion"]
659
+ #
660
+ # @overload sort
661
+ # Uses the block as a comparator to determine sorted order.
662
+ #
663
+ # @yield [a, b] Any number of times with different pairs of elements.
664
+ # @yieldreturn [Integer] Negative if the first element should be sorted
665
+ # lower, positive if the latter element, or 0 if
666
+ # equal.
667
+ # @example
668
+ # Hamster::Vector["Elephant", "Dog", "Lion"].sort { |a,b| a.size <=> b.size }
669
+ # # => Hamster::Vector["Dog", "Lion", "Elephant"]
426
670
  #
427
671
  # @return [Vector]
428
672
  def sort
429
673
  self.class.new(super)
430
674
  end
431
675
 
432
- # Return a new `Vector` with the same items, but sorted. The sort order will be
433
- # determined by mapping the items through the given block to obtain sort keys,
434
- # and then sorting the keys according to their natural sort order.
676
+ # Return a new `Vector` with the same items, but sorted. The sort order is
677
+ # determined by mapping the items through the given block to obtain sort
678
+ # keys, and then sorting the keys according to their natural sort order
679
+ # (`#<=>`).
680
+ #
681
+ # @yield [element] Once for each element.
682
+ # @yieldreturn a sort key object for the yielded element.
683
+ # @example
684
+ # Hamster::Vector["Elephant", "Dog", "Lion"].sort_by { |e| e.size }
685
+ # # => Hamster::Vector["Dog", "Lion", "Elephant"]
435
686
  #
436
687
  # @return [Vector]
437
688
  def sort_by
@@ -439,16 +690,31 @@ module Hamster
439
690
  end
440
691
 
441
692
  # Drop the first `n` elements and return the rest in a new `Vector`.
693
+ #
694
+ # @example
695
+ # Hamster::Vector["A", "B", "C", "D", "E", "F"].drop(2)
696
+ # # => Hamster::Vector["C", "D", "E", "F"]
697
+ #
442
698
  # @param n [Integer] The number of elements to remove
443
699
  # @return [Vector]
700
+ # @raise ArgumentError if `n` is negative.
444
701
  def drop(n)
445
- self.class.new(super)
702
+ return self if n == 0
703
+ return self.class.empty if n >= @size
704
+ raise ArgumentError, "attempt to drop negative size" if n < 0
705
+ self.class.new(flatten_suffix(@root, @levels * BITS_PER_LEVEL, n, []))
446
706
  end
447
707
 
448
708
  # Return only the first `n` elements in a new `Vector`.
709
+ #
710
+ # @example
711
+ # Hamster::Vector["A", "B", "C", "D", "E", "F"].take(4)
712
+ # # => Hamster::Vector["A", "B", "C", "D"]
713
+ #
449
714
  # @param n [Integer] The number of elements to retain
450
715
  # @return [Vector]
451
716
  def take(n)
717
+ return self if n >= @size
452
718
  self.class.new(super)
453
719
  end
454
720
 
@@ -456,6 +722,10 @@ module Hamster
456
722
  # block returns `nil` or `false`. Gather the remaining elements into a new
457
723
  # `Vector`. If no block is given, an `Enumerator` is returned instead.
458
724
  #
725
+ # @example
726
+ # Hamster::Vector[1, 3, 5, 7, 6, 4, 2].drop_while { |e| e < 5 }
727
+ # # => Hamster::Vector[5, 7, 6, 4, 2]
728
+ #
459
729
  # @return [Vector, Enumerator]
460
730
  def drop_while
461
731
  return enum_for(:drop_while) if not block_given?
@@ -466,6 +736,10 @@ module Hamster
466
736
  # block returns `nil` or `false`, and return them in a new `Vector`. If no block
467
737
  # is given, an `Enumerator` is returned instead.
468
738
  #
739
+ # @example
740
+ # Hamster::Vector[1, 3, 5, 7, 6, 4, 2].take_while { |e| e < 5 }
741
+ # # => Hamster::Vector[1, 3]
742
+ #
469
743
  # @return [Vector, Enumerator]
470
744
  def take_while
471
745
  return enum_for(:take_while) if not block_given?
@@ -475,6 +749,10 @@ module Hamster
475
749
  # Repetition. Return a new `Vector` built by concatenating `times` copies
476
750
  # of this one together.
477
751
  #
752
+ # @example
753
+ # Hamster::Vector["A", "B"] * 3
754
+ # # => Hamster::Vector["A", "B", "A", "B", "A", "B"]
755
+ #
478
756
  # @param times [Integer] The number of times to repeat the elements in this vector
479
757
  # @return [Vector]
480
758
  def *(times)
@@ -486,28 +764,53 @@ module Hamster
486
764
 
487
765
  # Replace a range of indexes with the given object.
488
766
  #
489
- # @overload fill(obj)
490
- # Return a new `Vector` of the same size, with every index set to `obj`.
491
- # @overload fill(obj, start)
492
- # Return a new `Vector` with all indexes from `start` to the end of the
493
- # vector set to `obj`.
494
- # @overload fill(obj, start, length)
495
- # Return a new `Vector` with `length` indexes, beginning from `start`,
496
- # set to `obj`.
767
+ # @overload fill(object)
768
+ # Return a new `Vector` of the same size, with every index set to
769
+ # `object`.
770
+ #
771
+ # @param [Object] object Fill value.
772
+ # @example
773
+ # Hamster::Vector["A", "B", "C", "D", "E", "F"].fill("Z")
774
+ # # => Hamster::Vector["Z", "Z", "Z", "Z", "Z", "Z"]
775
+ #
776
+ # @overload fill(object, index)
777
+ # Return a new `Vector` with all indexes from `index` to the end of the
778
+ # vector set to `object`.
779
+ #
780
+ # @param [Object] object Fill value.
781
+ # @param [Integer] index Starting index. May be negative.
782
+ # @example
783
+ # Hamster::Vector["A", "B", "C", "D", "E", "F"].fill("Z", 3)
784
+ # # => Hamster::Vector["A", "B", "C", "Z", "Z", "Z"]
785
+ #
786
+ # @overload fill(object, index, length)
787
+ # Return a new `Vector` with `length` indexes, beginning from `index`,
788
+ # set to `object`. Expands the `Vector` if `length` would extend beyond
789
+ # the current length.
790
+ #
791
+ # @param [Object] object Fill value.
792
+ # @param [Integer] index Starting index. May be negative.
793
+ # @param [Integer] length
794
+ # @example
795
+ # Hamster::Vector["A", "B", "C", "D", "E", "F"].fill("Z", 3, 2)
796
+ # # => Hamster::Vector["A", "B", "C", "Z", "Z", "F"]
797
+ # Hamster::Vector["A", "B"].fill("Z", 1, 5)
798
+ # # => Hamster::Vector["A", "Z", "Z", "Z", "Z", "Z"]
497
799
  #
498
800
  # @return [Vector]
499
- def fill(obj, index = 0, length = nil)
801
+ # @raise [IndexError] if index is out of negative range.
802
+ def fill(object, index = 0, length = nil)
500
803
  raise IndexError if index < -@size
501
804
  index += @size if index < 0
502
805
  length ||= @size - index # to the end of the array, if no length given
503
806
 
504
807
  if index < @size
505
808
  suffix = flatten_suffix(@root, @levels * BITS_PER_LEVEL, index, [])
506
- suffix.fill(obj, 0, length)
809
+ suffix.fill(object, 0, length)
507
810
  elsif index == @size
508
- suffix = Array.new(length, obj)
811
+ suffix = Array.new(length, object)
509
812
  else
510
- suffix = Array.new(index - @size, nil).concat(Array.new(length, obj))
813
+ suffix = Array.new(index - @size, nil).concat(Array.new(length, object))
511
814
  index = @size
512
815
  end
513
816
 
@@ -516,10 +819,20 @@ module Hamster
516
819
 
517
820
  # When invoked with a block, yields all combinations of length `n` of items
518
821
  # from the `Vector`, and then returns `self`. There is no guarantee about
519
- # which order the combinations will be yielded in.
822
+ # which order the combinations will be yielded.
520
823
  #
521
824
  # If no block is given, an `Enumerator` is returned instead.
522
825
  #
826
+ # @example
827
+ # v = Hamster::Vector[5, 6, 7, 8]
828
+ # v.combination(3) { |c| puts "Combination: #{c}" }
829
+ #
830
+ # Combination: [5, 6, 7]
831
+ # Combination: [5, 6, 8]
832
+ # Combination: [5, 7, 8]
833
+ # Combination: [6, 7, 8]
834
+ # #=> Hamster::Vector[5, 6, 7, 8]
835
+ #
523
836
  # @return [self, Enumerator]
524
837
  def combination(n)
525
838
  return enum_for(:combination, n) if not block_given?
@@ -557,6 +870,22 @@ module Hamster
557
870
  #
558
871
  # If no block is given, an `Enumerator` is returned instead.
559
872
  #
873
+ # @example
874
+ # v = Hamster::Vector[5, 6, 7, 8]
875
+ # v.repeated_combination(2) { |c| puts "Combination: #{c}" }
876
+ #
877
+ # Combination: [5, 5]
878
+ # Combination: [5, 6]
879
+ # Combination: [5, 7]
880
+ # Combination: [5, 8]
881
+ # Combination: [6, 6]
882
+ # Combination: [6, 7]
883
+ # Combination: [6, 8]
884
+ # Combination: [7, 7]
885
+ # Combination: [7, 8]
886
+ # Combination: [8, 8]
887
+ # # => Hamster::Vector[5, 6, 7, 8]
888
+ #
560
889
  # @return [self, Enumerator]
561
890
  def repeated_combination(n)
562
891
  return enum_for(:repeated_combination, n) if not block_given?
@@ -595,6 +924,18 @@ module Hamster
595
924
  #
596
925
  # If no block is given, an `Enumerator` is returned instead.
597
926
  #
927
+ # @example
928
+ # v = Hamster::Vector[5, 6, 7]
929
+ # v.permutation(2) { |p| puts "Permutation: #{p}" }
930
+ #
931
+ # Permutation: [5, 6]
932
+ # Permutation: [5, 7]
933
+ # Permutation: [6, 5]
934
+ # Permutation: [6, 7]
935
+ # Permutation: [7, 5]
936
+ # Permutation: [7, 6]
937
+ # # => Hamster::Vector[5, 6, 7]
938
+ #
598
939
  # @return [self, Enumerator]
599
940
  def permutation(n = @size)
600
941
  return enum_for(:permutation, n) if not block_given?
@@ -635,6 +976,21 @@ module Hamster
635
976
  #
636
977
  # If no block is given, an `Enumerator` is returned instead.
637
978
  #
979
+ # @example
980
+ # v = Hamster::Vector[5, 6, 7]
981
+ # v.repeated_permutation(2) { |p| puts "Permutation: #{p}" }
982
+ #
983
+ # Permutation: [5, 5]
984
+ # Permutation: [5, 6]
985
+ # Permutation: [5, 7]
986
+ # Permutation: [6, 5]
987
+ # Permutation: [6, 6]
988
+ # Permutation: [6, 7]
989
+ # Permutation: [7, 5]
990
+ # Permutation: [7, 6]
991
+ # Permutation: [7, 7]
992
+ # # => Hamster::Vector[5, 6, 7]
993
+ #
638
994
  # @return [self, Enumerator]
639
995
  def repeated_permutation(n = @size)
640
996
  return enum_for(:repeated_permutation, n) if not block_given?
@@ -661,17 +1017,23 @@ module Hamster
661
1017
  self
662
1018
  end
663
1019
 
664
- # With one or more vector or array arguments, return the cartesian product of
665
- # this vector's elements and those of each argument; with no arguments, return the
666
- # result of multiplying all this vector's items together.
1020
+ # Cartesian product or multiplication.
667
1021
  #
668
1022
  # @overload product(*vectors)
669
1023
  # Return a `Vector` of all combinations of elements from this `Vector` and each
670
1024
  # of the given vectors or arrays. The length of the returned `Vector` is the product
671
1025
  # of `self.size` and the size of each argument vector or array.
1026
+ # @example
1027
+ # v1 = Hamster::Vector[1, 2, 3]
1028
+ # v2 = Hamster::Vector["A", "B"]
1029
+ # v1.product(v2)
1030
+ # # => [[1, "A"], [1, "B"], [2, "A"], [2, "B"], [3, "A"], [3, "B"]]
672
1031
  # @overload product
673
1032
  # Return the result of multiplying all the items in this `Vector` together.
674
1033
  #
1034
+ # @example
1035
+ # Hamster::Vector[1, 2, 3, 4, 5].product # => 120
1036
+ #
675
1037
  # @return [Vector]
676
1038
  def product(*vectors)
677
1039
  # if no vectors passed, return "product" as in result of multiplying all items
@@ -726,7 +1088,13 @@ module Hamster
726
1088
  # calling {#zip} on the first nested vector/array with the others supplied as
727
1089
  # arguments.
728
1090
  #
1091
+ # @example
1092
+ # Hamster::Vector[["A", 10], ["B", 20], ["C", 30]].transpose
1093
+ # # => Hamster::Vector[Hamster::Vector["A", "B", "C"], Hamster::Vector[10, 20, 30]]
1094
+ #
729
1095
  # @return [Vector]
1096
+ # @raise [IndexError] if elements are not of the same size.
1097
+ # @raise [TypeError] if an element can not be implicitly converted to an array (using `#to_ary`)
730
1098
  def transpose
731
1099
  return self.class.empty if empty?
732
1100
  result = Array.new(first.size) { [] }
@@ -746,12 +1114,28 @@ module Hamster
746
1114
  self.class.new(result)
747
1115
  end
748
1116
 
749
- # By using binary search, finds a value from this `Vector` which meets the
750
- # condition defined by the provided block. Behavior is just like `Array#bsearch`.
751
- # See `Array#bsearch` for details.
1117
+ # Finds a value from this `Vector` which meets the condition defined by the
1118
+ # provided block, using a binary search. The vector must already be sorted
1119
+ # with respect to the block. See Ruby's `Array#bsearch` for details,
1120
+ # behaviour is equivalent.
752
1121
  #
753
- # @return [Object]
1122
+ # @example
1123
+ # v = Hamster::Vector[1, 3, 5, 7, 9, 11, 13]
1124
+ # # Block returns true/false for exact element match:
1125
+ # v.bsearch { |e| e > 4 } # => 5
1126
+ # # Block returns number to match an element in 4 <= e <= 7:
1127
+ # v.bsearch { |e| 1 - e / 4 } # => 7
1128
+ #
1129
+ # @yield Once for at most `log n` elements, where `n` is the size of the
1130
+ # vector. The exact elements and ordering are undefined.
1131
+ # @yieldreturn [Boolean] `true` if this element matches the criteria, `false` otherwise.
1132
+ # @yieldreturn [Integer] See `Array#bsearch` for details.
1133
+ # @yieldparam [Object] element element to be evaluated
1134
+ # @return [Object] The matched element, or `nil` if none found.
1135
+ # @raise TypeError if the block returns a non-numeric, non-boolean, non-nil
1136
+ # value.
754
1137
  def bsearch
1138
+ return enum_for(:bsearch) if not block_given?
755
1139
  low, high, result = 0, @size, nil
756
1140
  while low < high
757
1141
  mid = (low + ((high - low) >> 1))
@@ -787,6 +1171,9 @@ module Hamster
787
1171
 
788
1172
  # Return a randomly chosen item from this `Vector`. If the vector is empty, return `nil`.
789
1173
  #
1174
+ # @example
1175
+ # Hamster::Vector[1, 2, 3, 4, 5].sample # => 2
1176
+ #
790
1177
  # @return [Object]
791
1178
  def sample
792
1179
  get(rand(@size))
@@ -796,23 +1183,36 @@ module Hamster
796
1183
  # order specified by `indices`. If any of the `indices` do not exist, `nil`s will
797
1184
  # appear in their places.
798
1185
  #
1186
+ # @example
1187
+ # v = Hamster::Vector["A", "B", "C", "D", "E", "F"]
1188
+ # v.values_at(2, 4, 5) # => Hamster::Vector["C", "E", "F"]
1189
+ #
799
1190
  # @param indices [Array] The indices to retrieve and gather into a new `Vector`
800
1191
  # @return [Vector]
801
1192
  def values_at(*indices)
802
1193
  self.class.new(indices.map { |i| get(i) }.freeze)
803
1194
  end
804
1195
 
805
- # Return the index of the last element which is equal to the provided object,
806
- # or for which the provided block returns true.
1196
+ # Find the index of an element, starting from the end of the vector.
1197
+ # Returns `nil` if no element is found.
807
1198
  #
808
1199
  # @overload rindex(obj)
809
- # Return the index of the last element in this `Vector` which is `#==` to `obj`.
810
- # @overload rindex { |item| ... }
811
- # Return the index of the last element in this `Vector` for which the block
812
- # returns true. (Iteration starts from the last element, counts back, and
813
- # stops as soon as a matching element is found.)
1200
+ # Return the index of the last element which is `#==` to `obj`.
1201
+ #
1202
+ # @example
1203
+ # v = Hamster::Vector[7, 8, 9, 7, 8, 9]
1204
+ # v.rindex(8) # => 4
1205
+ #
1206
+ # @overload rindex
1207
+ # Return the index of the last element for which the block returns true.
814
1208
  #
815
- # @return [Index]
1209
+ # @yield [element] Once for each element, last to first, until the block
1210
+ # returns true.
1211
+ # @example
1212
+ # v = Hamster::Vector[7, 8, 9, 7, 8, 9]
1213
+ # v.rindex { |e| e.even? } # => 4
1214
+ #
1215
+ # @return [Integer]
816
1216
  def rindex(obj = (missing_arg = true))
817
1217
  i = @size - 1
818
1218
  if missing_arg
@@ -831,22 +1231,40 @@ module Hamster
831
1231
  # Assumes all elements are nested, indexable collections, and searches through them,
832
1232
  # comparing `obj` with the first element of each nested collection. Return the
833
1233
  # first nested collection which matches, or `nil` if none is found.
1234
+ # Behaviour is undefined when elements do not meet assumptions (i.e. are
1235
+ # not indexable collections).
1236
+ #
1237
+ # @example
1238
+ # v = Hamster::Vector[["A", 10], ["B", 20], ["C", 30]]
1239
+ # v.assoc("B") # => ["B", 20]
834
1240
  #
835
1241
  # @param obj [Object] The object to search for
836
1242
  # @return [Object]
837
1243
  def assoc(obj)
838
- each { |array| return array if obj == array[0] }
1244
+ each do |array|
1245
+ next if !array.respond_to?(:[])
1246
+ return array if obj == array[0]
1247
+ end
839
1248
  nil
840
1249
  end
841
1250
 
842
1251
  # Assumes all elements are nested, indexable collections, and searches through them,
843
- # comparing `obj` with the second element of each nested collection. Return the
844
- # first nested collection which matches, or `nil` if none is found.
1252
+ # comparing `obj` with the second element of each nested collection. Return
1253
+ # the first nested collection which matches, or `nil` if none is found.
1254
+ # Behaviour is undefined when elements do not meet assumptions (i.e. are
1255
+ # not indexable collections).
1256
+ #
1257
+ # @example
1258
+ # v = Hamster::Vector[["A", 10], ["B", 20], ["C", 30]]
1259
+ # v.rassoc(20) # => ["B", 20]
845
1260
  #
846
1261
  # @param obj [Object] The object to search for
847
1262
  # @return [Object]
848
1263
  def rassoc(obj)
849
- each { |array| return array if obj == array[1] }
1264
+ each do |array|
1265
+ next if !array.respond_to?(:[])
1266
+ return array if obj == array[1]
1267
+ end
850
1268
  nil
851
1269
  end
852
1270
 
@@ -856,11 +1274,14 @@ module Hamster
856
1274
  # @return [Array]
857
1275
  def to_a
858
1276
  if @levels == 0
1277
+ # When initializing a Vector with 32 or less items, we always make
1278
+ # sure @root is frozen, so we can return it directly here
859
1279
  @root
860
1280
  else
861
1281
  flatten_node(@root, @levels * BITS_PER_LEVEL, [])
862
1282
  end
863
1283
  end
1284
+ alias :to_ary :to_a
864
1285
 
865
1286
  # Return true if `other` has the same type and contents as this `Vector`.
866
1287
  #
@@ -915,8 +1336,12 @@ module Hamster
915
1336
  root = [root].freeze
916
1337
  levels += 1
917
1338
  end
918
- root = update_leaf_node(root, levels * BITS_PER_LEVEL, index, item)
919
- self.class.alloc(root, @size > index ? @size : index + 1, levels)
1339
+ new_root = update_leaf_node(root, levels * BITS_PER_LEVEL, index, item)
1340
+ if new_root.equal?(root)
1341
+ self
1342
+ else
1343
+ self.class.alloc(new_root, @size > index ? @size : index + 1, levels)
1344
+ end
920
1345
  end
921
1346
 
922
1347
  def update_leaf_node(node, bitshift, index, item)
@@ -925,7 +1350,12 @@ module Hamster
925
1350
  old_child = node[slot_index] || []
926
1351
  item = update_leaf_node(old_child, bitshift - BITS_PER_LEVEL, index, item)
927
1352
  end
928
- node.dup.tap { |n| n[slot_index] = item }.freeze
1353
+ existing_item = node[slot_index]
1354
+ if existing_item.equal?(item)
1355
+ node
1356
+ else
1357
+ node.dup.tap { |n| n[slot_index] = item }.freeze
1358
+ end
929
1359
  end
930
1360
 
931
1361
  def flatten_range(node, bitshift, from, to)
@@ -1082,9 +1512,10 @@ module Hamster
1082
1512
  end
1083
1513
  end
1084
1514
 
1085
- # The canonical empty `Vector`. Returned by `Hamster.vector` and `Vector[]` when
1515
+ # The canonical empty `Vector`. Returned by `Vector[]` when
1086
1516
  # invoked with no arguments; also returned by `Vector.empty`. Prefer using this
1087
1517
  # one rather than creating many empty vectors using `Vector.new`.
1088
1518
  #
1519
+ # @private
1089
1520
  EmptyVector = Hamster::Vector.empty
1090
1521
  end