hamster 1.0.1.pre.rc3 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (358) hide show
  1. checksums.yaml +4 -4
  2. data/lib/hamster.rb +2 -0
  3. data/lib/hamster/associable.rb +49 -0
  4. data/lib/hamster/core_ext/enumerable.rb +3 -13
  5. data/lib/hamster/core_ext/io.rb +1 -1
  6. data/lib/hamster/core_ext/struct.rb +9 -0
  7. data/lib/hamster/deque.rb +57 -38
  8. data/lib/hamster/enumerable.rb +14 -41
  9. data/lib/hamster/experimental/mutable_queue.rb +5 -8
  10. data/lib/hamster/experimental/mutable_set.rb +6 -7
  11. data/lib/hamster/hash.rb +301 -110
  12. data/lib/hamster/immutable.rb +1 -1
  13. data/lib/hamster/list.rb +479 -194
  14. data/lib/hamster/mutable_hash.rb +6 -7
  15. data/lib/hamster/nested.rb +78 -0
  16. data/lib/hamster/read_copy_update.rb +1 -1
  17. data/lib/hamster/set.rb +198 -88
  18. data/lib/hamster/sorted_set.rb +706 -261
  19. data/lib/hamster/trie.rb +134 -15
  20. data/lib/hamster/vector.rb +571 -140
  21. data/lib/hamster/version.rb +3 -1
  22. data/spec/lib/hamster/associable/associable_spec.rb +150 -0
  23. data/spec/lib/hamster/core_ext/array_spec.rb +1 -1
  24. data/spec/lib/hamster/core_ext/enumerable_spec.rb +2 -2
  25. data/spec/lib/hamster/core_ext/io_spec.rb +1 -1
  26. data/spec/lib/hamster/deque/clear_spec.rb +3 -3
  27. data/spec/lib/hamster/deque/construction_spec.rb +8 -8
  28. data/spec/lib/hamster/deque/copying_spec.rb +1 -1
  29. data/spec/lib/hamster/deque/dequeue_spec.rb +12 -4
  30. data/spec/lib/hamster/deque/empty_spec.rb +14 -16
  31. data/spec/lib/hamster/deque/enqueue_spec.rb +4 -4
  32. data/spec/lib/hamster/deque/first_spec.rb +18 -0
  33. data/spec/lib/hamster/deque/inspect_spec.rb +1 -1
  34. data/spec/lib/hamster/deque/last_spec.rb +9 -11
  35. data/spec/lib/hamster/deque/marshal_spec.rb +6 -6
  36. data/spec/lib/hamster/deque/new_spec.rb +5 -5
  37. data/spec/lib/hamster/deque/pop_spec.rb +15 -3
  38. data/spec/lib/hamster/deque/pretty_print_spec.rb +24 -0
  39. data/spec/lib/hamster/deque/push_spec.rb +37 -0
  40. data/spec/lib/hamster/deque/shift_spec.rb +30 -0
  41. data/spec/lib/hamster/deque/size_spec.rb +1 -1
  42. data/spec/lib/hamster/deque/to_a_spec.rb +2 -2
  43. data/spec/lib/hamster/deque/to_ary_spec.rb +1 -1
  44. data/spec/lib/hamster/deque/to_list_spec.rb +3 -3
  45. data/spec/lib/hamster/deque/unshift_spec.rb +8 -3
  46. data/spec/lib/hamster/experimental/mutable_set/add_qm_spec.rb +3 -3
  47. data/spec/lib/hamster/experimental/mutable_set/add_spec.rb +3 -3
  48. data/spec/lib/hamster/experimental/mutable_set/delete_qm_spec.rb +3 -3
  49. data/spec/lib/hamster/experimental/mutable_set/delete_spec.rb +3 -3
  50. data/spec/lib/hamster/hash/all_spec.rb +32 -34
  51. data/spec/lib/hamster/hash/any_spec.rb +34 -36
  52. data/spec/lib/hamster/hash/assoc_spec.rb +3 -3
  53. data/spec/lib/hamster/hash/clear_spec.rb +4 -4
  54. data/spec/lib/hamster/hash/construction_spec.rb +8 -8
  55. data/spec/lib/hamster/hash/copying_spec.rb +1 -1
  56. data/spec/lib/hamster/hash/default_proc_spec.rb +3 -3
  57. data/spec/lib/hamster/hash/delete_spec.rb +4 -4
  58. data/spec/lib/hamster/hash/each_spec.rb +3 -3
  59. data/spec/lib/hamster/hash/each_with_index_spec.rb +1 -1
  60. data/spec/lib/hamster/hash/empty_spec.rb +13 -15
  61. data/spec/lib/hamster/hash/eql_spec.rb +4 -4
  62. data/spec/lib/hamster/hash/except_spec.rb +7 -7
  63. data/spec/lib/hamster/hash/fetch_spec.rb +10 -10
  64. data/spec/lib/hamster/hash/find_spec.rb +2 -2
  65. data/spec/lib/hamster/hash/flat_map_spec.rb +4 -4
  66. data/spec/lib/hamster/hash/flatten_spec.rb +13 -13
  67. data/spec/lib/hamster/hash/get_spec.rb +7 -7
  68. data/spec/lib/hamster/hash/has_key_spec.rb +3 -3
  69. data/spec/lib/hamster/hash/has_value_spec.rb +4 -4
  70. data/spec/lib/hamster/hash/hash_spec.rb +5 -5
  71. data/spec/lib/hamster/hash/inspect_spec.rb +2 -2
  72. data/spec/lib/hamster/hash/invert_spec.rb +6 -6
  73. data/spec/lib/hamster/hash/key_spec.rb +2 -2
  74. data/spec/lib/hamster/hash/keys_spec.rb +2 -2
  75. data/spec/lib/hamster/hash/map_spec.rb +4 -4
  76. data/spec/lib/hamster/hash/marshal_spec.rb +2 -2
  77. data/spec/lib/hamster/hash/merge_spec.rb +62 -56
  78. data/spec/lib/hamster/hash/min_max_spec.rb +9 -13
  79. data/spec/lib/hamster/hash/new_spec.rb +6 -6
  80. data/spec/lib/hamster/hash/none_spec.rb +3 -3
  81. data/spec/lib/hamster/hash/partition_spec.rb +2 -2
  82. data/spec/lib/hamster/hash/put_spec.rb +29 -7
  83. data/spec/lib/hamster/hash/reduce_spec.rb +4 -4
  84. data/spec/lib/hamster/hash/{remove_spec.rb → reject_spec.rb} +7 -7
  85. data/spec/lib/hamster/hash/reverse_each_spec.rb +1 -1
  86. data/spec/lib/hamster/hash/{filter_spec.rb → select_spec.rb} +6 -6
  87. data/spec/lib/hamster/hash/size_spec.rb +3 -3
  88. data/spec/lib/hamster/hash/slice_spec.rb +4 -4
  89. data/spec/lib/hamster/hash/sort_spec.rb +2 -2
  90. data/spec/lib/hamster/hash/store_spec.rb +29 -7
  91. data/spec/lib/hamster/hash/take_spec.rb +2 -2
  92. data/spec/lib/hamster/hash/to_a_spec.rb +1 -1
  93. data/spec/lib/hamster/hash/to_hash_spec.rb +4 -4
  94. data/spec/lib/hamster/hash/values_at_spec.rb +3 -3
  95. data/spec/lib/hamster/hash/values_spec.rb +2 -2
  96. data/spec/lib/hamster/immutable/new_spec.rb +14 -0
  97. data/spec/lib/hamster/list/add_spec.rb +16 -10
  98. data/spec/lib/hamster/list/all_spec.rb +33 -35
  99. data/spec/lib/hamster/list/any_spec.rb +29 -31
  100. data/spec/lib/hamster/list/append_spec.rb +6 -6
  101. data/spec/lib/hamster/list/at_spec.rb +1 -1
  102. data/spec/lib/hamster/list/break_spec.rb +4 -4
  103. data/spec/lib/hamster/list/cadr_spec.rb +9 -9
  104. data/spec/lib/hamster/list/chunk_spec.rb +5 -5
  105. data/spec/lib/hamster/list/clear_spec.rb +3 -3
  106. data/spec/lib/hamster/list/combination_spec.rb +3 -3
  107. data/spec/lib/hamster/list/compact_spec.rb +3 -3
  108. data/spec/lib/hamster/list/compare_spec.rb +3 -3
  109. data/spec/lib/hamster/list/cons_spec.rb +15 -17
  110. data/spec/lib/hamster/list/construction_spec.rb +20 -27
  111. data/spec/lib/hamster/list/copying_spec.rb +1 -1
  112. data/spec/lib/hamster/list/count_spec.rb +1 -1
  113. data/spec/lib/hamster/list/cycle_spec.rb +4 -4
  114. data/spec/lib/hamster/list/delete_at_spec.rb +4 -4
  115. data/spec/lib/hamster/list/drop_spec.rb +3 -3
  116. data/spec/lib/hamster/list/drop_while_spec.rb +3 -3
  117. data/spec/lib/hamster/list/each_slice_spec.rb +5 -5
  118. data/spec/lib/hamster/list/each_spec.rb +26 -28
  119. data/spec/lib/hamster/list/each_with_index_spec.rb +1 -1
  120. data/spec/lib/hamster/list/empty_spec.rb +13 -15
  121. data/spec/lib/hamster/list/eql_spec.rb +21 -21
  122. data/spec/lib/hamster/list/fill_spec.rb +8 -8
  123. data/spec/lib/hamster/list/find_all_spec.rb +3 -3
  124. data/spec/lib/hamster/list/find_index_spec.rb +1 -1
  125. data/spec/lib/hamster/list/find_spec.rb +1 -1
  126. data/spec/lib/hamster/list/flat_map_spec.rb +2 -2
  127. data/spec/lib/hamster/list/flatten_spec.rb +5 -5
  128. data/spec/lib/hamster/list/grep_spec.rb +4 -4
  129. data/spec/lib/hamster/list/group_by_spec.rb +6 -6
  130. data/spec/lib/hamster/list/hash_spec.rb +2 -2
  131. data/spec/lib/hamster/list/head_spec.rb +1 -1
  132. data/spec/lib/hamster/list/include_spec.rb +2 -2
  133. data/spec/lib/hamster/list/index_spec.rb +38 -0
  134. data/spec/lib/hamster/list/indices_spec.rb +62 -0
  135. data/spec/lib/hamster/list/init_spec.rb +3 -3
  136. data/spec/lib/hamster/list/inits_spec.rb +3 -3
  137. data/spec/lib/hamster/list/insert_spec.rb +1 -1
  138. data/spec/lib/hamster/list/inspect_spec.rb +1 -1
  139. data/spec/lib/hamster/list/intersperse_spec.rb +3 -3
  140. data/spec/lib/hamster/list/join_spec.rb +5 -5
  141. data/spec/lib/hamster/list/last_spec.rb +1 -1
  142. data/spec/lib/hamster/list/ltlt_spec.rb +20 -0
  143. data/spec/lib/hamster/list/map_spec.rb +4 -4
  144. data/spec/lib/hamster/list/maximum_spec.rb +24 -26
  145. data/spec/lib/hamster/list/merge_by_spec.rb +10 -10
  146. data/spec/lib/hamster/list/merge_spec.rb +10 -10
  147. data/spec/lib/hamster/list/minimum_spec.rb +24 -26
  148. data/spec/lib/hamster/list/multithreading_spec.rb +6 -6
  149. data/spec/lib/hamster/list/none_spec.rb +5 -5
  150. data/spec/lib/hamster/list/one_spec.rb +5 -5
  151. data/spec/lib/hamster/list/partition_spec.rb +8 -8
  152. data/spec/lib/hamster/list/permutation_spec.rb +8 -8
  153. data/spec/lib/hamster/list/pop_spec.rb +3 -3
  154. data/spec/lib/hamster/list/product_spec.rb +1 -1
  155. data/spec/lib/hamster/list/reduce_spec.rb +5 -48
  156. data/spec/lib/hamster/list/{remove_spec.rb → reject_spec.rb} +4 -4
  157. data/spec/lib/hamster/list/reverse_spec.rb +3 -3
  158. data/spec/lib/hamster/list/rotate_spec.rb +7 -7
  159. data/spec/lib/hamster/list/sample_spec.rb +1 -1
  160. data/spec/lib/hamster/list/select_spec.rb +3 -3
  161. data/spec/lib/hamster/list/size_spec.rb +1 -1
  162. data/spec/lib/hamster/list/slice_spec.rb +123 -123
  163. data/spec/lib/hamster/list/sorting_spec.rb +5 -5
  164. data/spec/lib/hamster/list/span_spec.rb +5 -5
  165. data/spec/lib/hamster/list/split_at_spec.rb +4 -4
  166. data/spec/lib/hamster/list/subsequences_spec.rb +1 -1
  167. data/spec/lib/hamster/list/sum_spec.rb +1 -1
  168. data/spec/lib/hamster/list/tail_spec.rb +4 -4
  169. data/spec/lib/hamster/list/tails_spec.rb +3 -3
  170. data/spec/lib/hamster/list/take_spec.rb +3 -3
  171. data/spec/lib/hamster/list/take_while_spec.rb +4 -4
  172. data/spec/lib/hamster/list/to_a_spec.rb +2 -2
  173. data/spec/lib/hamster/list/to_ary_spec.rb +1 -1
  174. data/spec/lib/hamster/list/to_list_spec.rb +1 -1
  175. data/spec/lib/hamster/list/to_set_spec.rb +1 -1
  176. data/spec/lib/hamster/list/union_spec.rb +4 -4
  177. data/spec/lib/hamster/list/uniq_spec.rb +23 -19
  178. data/spec/lib/hamster/list/zip_spec.rb +5 -5
  179. data/spec/lib/hamster/nested/construction_spec.rb +103 -0
  180. data/spec/lib/hamster/set/add_spec.rb +13 -11
  181. data/spec/lib/hamster/set/all_spec.rb +32 -34
  182. data/spec/lib/hamster/set/any_spec.rb +32 -34
  183. data/spec/lib/hamster/set/clear_spec.rb +3 -3
  184. data/spec/lib/hamster/set/compact_spec.rb +3 -3
  185. data/spec/lib/hamster/set/construction_spec.rb +3 -3
  186. data/spec/lib/hamster/set/copying_spec.rb +1 -1
  187. data/spec/lib/hamster/set/count_spec.rb +1 -1
  188. data/spec/lib/hamster/set/delete_spec.rb +8 -8
  189. data/spec/lib/hamster/set/difference_spec.rb +8 -8
  190. data/spec/lib/hamster/set/disjoint_spec.rb +1 -1
  191. data/spec/lib/hamster/set/each_spec.rb +2 -2
  192. data/spec/lib/hamster/set/empty_spec.rb +15 -17
  193. data/spec/lib/hamster/set/eqeq_spec.rb +3 -3
  194. data/spec/lib/hamster/set/eql_spec.rb +3 -3
  195. data/spec/lib/hamster/set/exclusion_spec.rb +7 -7
  196. data/spec/lib/hamster/set/find_spec.rb +2 -2
  197. data/spec/lib/hamster/set/first_spec.rb +29 -0
  198. data/spec/lib/hamster/set/flatten_spec.rb +9 -9
  199. data/spec/lib/hamster/set/grep_spec.rb +1 -1
  200. data/spec/lib/hamster/set/group_by_spec.rb +12 -12
  201. data/spec/lib/hamster/set/hash_spec.rb +3 -3
  202. data/spec/lib/hamster/set/include_spec.rb +8 -8
  203. data/spec/lib/hamster/set/inspect_spec.rb +2 -2
  204. data/spec/lib/hamster/set/intersect_spec.rb +1 -1
  205. data/spec/lib/hamster/set/intersection_spec.rb +13 -13
  206. data/spec/lib/hamster/set/join_spec.rb +6 -6
  207. data/spec/lib/hamster/set/map_spec.rb +7 -7
  208. data/spec/lib/hamster/set/marshal_spec.rb +2 -2
  209. data/spec/lib/hamster/set/maximum_spec.rb +22 -24
  210. data/spec/lib/hamster/set/minimum_spec.rb +22 -24
  211. data/spec/lib/hamster/set/new_spec.rb +5 -5
  212. data/spec/lib/hamster/set/none_spec.rb +5 -5
  213. data/spec/lib/hamster/set/one_spec.rb +6 -6
  214. data/spec/lib/hamster/set/partition_spec.rb +5 -5
  215. data/spec/lib/hamster/set/product_spec.rb +2 -2
  216. data/spec/lib/hamster/set/reduce_spec.rb +5 -5
  217. data/spec/lib/hamster/set/{remove_spec.rb → reject_spec.rb} +6 -6
  218. data/spec/lib/hamster/set/reverse_each_spec.rb +1 -1
  219. data/spec/lib/hamster/set/sample_spec.rb +1 -1
  220. data/spec/lib/hamster/set/{filter_spec.rb → select_spec.rb} +11 -11
  221. data/spec/lib/hamster/set/size_spec.rb +1 -1
  222. data/spec/lib/hamster/set/sorting_spec.rb +16 -5
  223. data/spec/lib/hamster/set/subset_spec.rb +2 -2
  224. data/spec/lib/hamster/set/sum_spec.rb +2 -2
  225. data/spec/lib/hamster/set/superset_spec.rb +2 -2
  226. data/spec/lib/hamster/set/to_a_spec.rb +2 -2
  227. data/spec/lib/hamster/set/to_list_spec.rb +2 -2
  228. data/spec/lib/hamster/set/to_set_spec.rb +1 -1
  229. data/spec/lib/hamster/set/union_spec.rb +23 -14
  230. data/spec/lib/hamster/sorted_set/above_spec.rb +11 -11
  231. data/spec/lib/hamster/sorted_set/add_spec.rb +8 -8
  232. data/spec/lib/hamster/sorted_set/at_spec.rb +1 -1
  233. data/spec/lib/hamster/sorted_set/below_spec.rb +11 -11
  234. data/spec/lib/hamster/sorted_set/between_spec.rb +11 -11
  235. data/spec/lib/hamster/sorted_set/clear_spec.rb +11 -2
  236. data/spec/lib/hamster/sorted_set/copying_spec.rb +21 -0
  237. data/spec/lib/hamster/sorted_set/delete_at_spec.rb +4 -4
  238. data/spec/lib/hamster/sorted_set/delete_spec.rb +21 -12
  239. data/spec/lib/hamster/sorted_set/difference_spec.rb +2 -2
  240. data/spec/lib/hamster/sorted_set/disjoint_spec.rb +1 -1
  241. data/spec/lib/hamster/sorted_set/drop_spec.rb +30 -3
  242. data/spec/lib/hamster/sorted_set/drop_while_spec.rb +4 -4
  243. data/spec/lib/hamster/sorted_set/each_spec.rb +16 -18
  244. data/spec/lib/hamster/sorted_set/empty_spec.rb +12 -14
  245. data/spec/lib/hamster/sorted_set/eql_spec.rb +5 -5
  246. data/spec/lib/hamster/sorted_set/exclusion_spec.rb +1 -1
  247. data/spec/lib/hamster/sorted_set/fetch_spec.rb +1 -1
  248. data/spec/lib/hamster/sorted_set/find_index_spec.rb +10 -2
  249. data/spec/lib/hamster/sorted_set/first_spec.rb +10 -12
  250. data/spec/lib/hamster/sorted_set/from_spec.rb +11 -11
  251. data/spec/lib/hamster/sorted_set/group_by_spec.rb +10 -10
  252. data/spec/lib/hamster/sorted_set/include_spec.rb +2 -2
  253. data/spec/lib/hamster/sorted_set/inspect_spec.rb +1 -1
  254. data/spec/lib/hamster/sorted_set/intersect_spec.rb +1 -1
  255. data/spec/lib/hamster/sorted_set/intersection_spec.rb +3 -3
  256. data/spec/lib/hamster/sorted_set/last_spec.rb +1 -1
  257. data/spec/lib/hamster/sorted_set/map_spec.rb +13 -5
  258. data/spec/lib/hamster/sorted_set/marshal_spec.rb +3 -3
  259. data/spec/lib/hamster/sorted_set/maximum_spec.rb +37 -0
  260. data/spec/lib/hamster/sorted_set/minimum_spec.rb +11 -13
  261. data/spec/lib/hamster/sorted_set/new_spec.rb +23 -3
  262. data/spec/lib/hamster/sorted_set/reverse_each_spec.rb +2 -2
  263. data/spec/lib/hamster/sorted_set/{filter_spec.rb → select_spec.rb} +10 -10
  264. data/spec/lib/hamster/sorted_set/size_spec.rb +1 -1
  265. data/spec/lib/hamster/sorted_set/slice_spec.rb +158 -142
  266. data/spec/lib/hamster/sorted_set/sorting_spec.rb +3 -3
  267. data/spec/lib/hamster/sorted_set/subset_spec.rb +2 -2
  268. data/spec/lib/hamster/sorted_set/superset_spec.rb +2 -2
  269. data/spec/lib/hamster/sorted_set/take_spec.rb +32 -3
  270. data/spec/lib/hamster/sorted_set/take_while_spec.rb +4 -4
  271. data/spec/lib/hamster/sorted_set/to_set_spec.rb +1 -1
  272. data/spec/lib/hamster/sorted_set/union_spec.rb +2 -2
  273. data/spec/lib/hamster/sorted_set/up_to_spec.rb +12 -11
  274. data/spec/lib/hamster/sorted_set/values_at_spec.rb +6 -6
  275. data/spec/lib/hamster/vector/add_spec.rb +3 -3
  276. data/spec/lib/hamster/vector/any_spec.rb +1 -1
  277. data/spec/lib/hamster/vector/assoc_spec.rb +11 -1
  278. data/spec/lib/hamster/vector/bsearch_spec.rb +10 -2
  279. data/spec/lib/hamster/vector/clear_spec.rb +3 -3
  280. data/spec/lib/hamster/vector/combination_spec.rb +4 -4
  281. data/spec/lib/hamster/vector/compact_spec.rb +2 -2
  282. data/spec/lib/hamster/vector/compare_spec.rb +3 -3
  283. data/spec/lib/hamster/vector/concat_spec.rb +2 -2
  284. data/spec/lib/hamster/vector/copying_spec.rb +1 -1
  285. data/spec/lib/hamster/vector/delete_at_spec.rb +8 -8
  286. data/spec/lib/hamster/vector/delete_spec.rb +2 -2
  287. data/spec/lib/hamster/vector/drop_spec.rb +10 -3
  288. data/spec/lib/hamster/vector/drop_while_spec.rb +5 -5
  289. data/spec/lib/hamster/vector/each_index_spec.rb +2 -2
  290. data/spec/lib/hamster/vector/each_spec.rb +27 -29
  291. data/spec/lib/hamster/vector/each_with_index_spec.rb +2 -2
  292. data/spec/lib/hamster/vector/empty_spec.rb +11 -13
  293. data/spec/lib/hamster/vector/eql_spec.rb +6 -6
  294. data/spec/lib/hamster/vector/fetch_spec.rb +1 -1
  295. data/spec/lib/hamster/vector/fill_spec.rb +9 -9
  296. data/spec/lib/hamster/vector/first_spec.rb +10 -12
  297. data/spec/lib/hamster/vector/flat_map_spec.rb +51 -0
  298. data/spec/lib/hamster/vector/flatten_spec.rb +15 -0
  299. data/spec/lib/hamster/vector/get_spec.rb +4 -4
  300. data/spec/lib/hamster/vector/group_by_spec.rb +12 -12
  301. data/spec/lib/hamster/vector/include_spec.rb +2 -2
  302. data/spec/lib/hamster/vector/insert_spec.rb +2 -2
  303. data/spec/lib/hamster/vector/inspect_spec.rb +1 -1
  304. data/spec/lib/hamster/vector/join_spec.rb +5 -5
  305. data/spec/lib/hamster/vector/last_spec.rb +1 -1
  306. data/spec/lib/hamster/vector/length_spec.rb +1 -1
  307. data/spec/lib/hamster/vector/ltlt_spec.rb +2 -2
  308. data/spec/lib/hamster/vector/map_spec.rb +5 -5
  309. data/spec/lib/hamster/vector/marshal_spec.rb +2 -2
  310. data/spec/lib/hamster/vector/maximum_spec.rb +20 -22
  311. data/spec/lib/hamster/vector/minimum_spec.rb +20 -22
  312. data/spec/lib/hamster/vector/multiply_spec.rb +4 -4
  313. data/spec/lib/hamster/vector/partition_spec.rb +5 -5
  314. data/spec/lib/hamster/vector/permutation_spec.rb +4 -4
  315. data/spec/lib/hamster/vector/pop_spec.rb +3 -3
  316. data/spec/lib/hamster/vector/product_spec.rb +10 -10
  317. data/spec/lib/hamster/vector/put_spec.rb +175 -0
  318. data/spec/lib/hamster/vector/reduce_spec.rb +5 -57
  319. data/spec/lib/hamster/vector/{remove_spec.rb → reject_spec.rb} +4 -4
  320. data/spec/lib/hamster/vector/repeated_combination_spec.rb +4 -4
  321. data/spec/lib/hamster/vector/repeated_permutation_spec.rb +6 -6
  322. data/spec/lib/hamster/vector/reverse_each_spec.rb +1 -1
  323. data/spec/lib/hamster/vector/reverse_spec.rb +1 -1
  324. data/spec/lib/hamster/vector/rindex_spec.rb +1 -1
  325. data/spec/lib/hamster/vector/rotate_spec.rb +9 -9
  326. data/spec/lib/hamster/vector/sample_spec.rb +1 -1
  327. data/spec/lib/hamster/vector/{filter_spec.rb → select_spec.rb} +8 -8
  328. data/spec/lib/hamster/vector/set_spec.rb +12 -141
  329. data/spec/lib/hamster/vector/shift_spec.rb +3 -3
  330. data/spec/lib/hamster/vector/shuffle_spec.rb +2 -2
  331. data/spec/lib/hamster/vector/slice_spec.rb +137 -137
  332. data/spec/lib/hamster/vector/sorting_spec.rb +5 -5
  333. data/spec/lib/hamster/vector/sum_spec.rb +1 -1
  334. data/spec/lib/hamster/vector/take_spec.rb +17 -3
  335. data/spec/lib/hamster/vector/take_while_spec.rb +4 -4
  336. data/spec/lib/hamster/vector/to_a_spec.rb +1 -1
  337. data/spec/lib/hamster/vector/to_ary_spec.rb +1 -1
  338. data/spec/lib/hamster/vector/to_list_spec.rb +2 -1
  339. data/spec/lib/hamster/vector/to_set_spec.rb +1 -1
  340. data/spec/lib/hamster/vector/uniq_spec.rb +27 -6
  341. data/spec/lib/hamster/vector/unshift_spec.rb +3 -3
  342. data/spec/lib/hamster/vector/values_at_spec.rb +6 -6
  343. data/spec/lib/hamster/vector/zip_spec.rb +2 -2
  344. data/spec/lib/load_spec.rb +42 -0
  345. data/spec/spec_helper.rb +25 -0
  346. metadata +85 -48
  347. data/spec/lib/hamster/deque/head_spec.rb +0 -20
  348. data/spec/lib/hamster/hash/uniq_spec.rb +0 -14
  349. data/spec/lib/hamster/list/elem_index_spec.rb +0 -36
  350. data/spec/lib/hamster/list/elem_indices_spec.rb +0 -31
  351. data/spec/lib/hamster/list/filter_spec.rb +0 -71
  352. data/spec/lib/hamster/list/find_indices_spec.rb +0 -37
  353. data/spec/lib/hamster/set/foreach_spec.rb +0 -40
  354. data/spec/lib/hamster/set/head_spec.rb +0 -31
  355. data/spec/lib/hamster/set/uniq_spec.rb +0 -14
  356. data/spec/lib/hamster/sorted_set/construction_spec.rb +0 -29
  357. data/spec/lib/hamster/vector/exist_spec.rb +0 -70
  358. data/spec/lib/hamster/vector/exists_spec.rb +0 -70
@@ -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