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
@@ -1,11 +1,7 @@
1
- require "forwardable"
2
1
  require "hamster/immutable"
3
2
  require "hamster/enumerable"
4
3
 
5
4
  module Hamster
6
- def self.sorted_set(*items, &block)
7
- (items.empty? && block.nil?) ? EmptySortedSet : SortedSet.new(items, &block)
8
- end
9
5
 
10
6
  # A `SortedSet` is a collection of ordered values with no duplicates. Unlike a
11
7
  # {Vector}, in which items can appear in any arbitrary order, a `SortedSet` always
@@ -21,20 +17,17 @@ module Hamster
21
17
  # `SortedSet`. This is unlike {Set}, which can store items of any type, as long
22
18
  # as they all support `#hash` and `#eql?`.
23
19
  #
24
- # A `SortedSet` can be created in any of the following ways:
20
+ # A `SortedSet` can be created in either of the following ways:
25
21
  #
26
- # Hamster.sorted_set('Tom', 'Dick', 'Harry')
27
22
  # Hamster::SortedSet.new([1, 2, 3]) # any Enumerable can be used to initialize
28
23
  # Hamster::SortedSet['A', 'B', 'C', 'D']
29
24
  #
30
25
  # Or if you want to use a custom ordering:
31
26
  #
32
- # Hamster.sorted_set('Tom', 'Dick', 'Harry') { |a, b| a.reverse <=> b.reverse }
33
- # Hamster.sorted_set('Tom', 'Dick', 'Harry') { |str| str.reverse }
34
27
  # Hamster::SortedSet.new([1,2,3]) { |a, b| -a <=> -b }
35
28
  # Hamster::SortedSet.new([1, 2, 3]) { |num| -num }
36
29
  #
37
- # As you can see, `SortedSet` can use a 2-parameter block which returns 0, 1, or -1
30
+ # `SortedSet` can use a 2-parameter block which returns 0, 1, or -1
38
31
  # as a comparator (like `Array#sort`), *or* use a 1-parameter block to derive sort
39
32
  # keys (like `Array#sort_by`) which will be compared using `#<=>`.
40
33
  #
@@ -45,19 +38,18 @@ module Hamster
45
38
  # `SortedSet` supports the same basic set-theoretic operations as {Set}, including
46
39
  # {#union}, {#intersection}, {#difference}, and {#exclusion}, as well as {#subset?},
47
40
  # {#superset?}, and so on. Unlike {Set}, it does not define comparison operators like
48
- # {#>} or {#<} as aliases for the superset/subset predicates. Instead, these comparison
41
+ # `#>` or `#<` as aliases for the superset/subset predicates. Instead, these comparison
49
42
  # operators do a item-by-item comparison between the `SortedSet` and another sequential
50
43
  # collection. (See `Array#<=>` for details.)
51
44
  #
52
45
  # Additionally, since `SortedSet`s are ordered, they also support indexed retrieval
53
- # of items (or slices of items) using {#at} or {#[]}. Like {Vector} (or `Array`),
46
+ # of items using {#at} or {#[]}. Like {Vector},
54
47
  # negative indices count back from the end of the `SortedSet`.
55
48
  #
56
49
  # Getting the {#max} or {#min} item from a `SortedSet`, as defined by its comparator,
57
- # is very efficient.
50
+ # is a constant time operation.
58
51
  #
59
52
  class SortedSet
60
- extend Forwardable
61
53
  include Immutable
62
54
  include Enumerable
63
55
 
@@ -75,7 +67,7 @@ module Hamster
75
67
  #
76
68
  # @return [SortedSet]
77
69
  def empty
78
- @empty ||= self.alloc(EmptyAVLNode, lambda { |a,b| a <=> b })
70
+ @empty ||= self.alloc(PlainAVLNode::EmptyNode)
79
71
  end
80
72
 
81
73
  # "Raw" allocation of a new `SortedSet`. Used internally to create a new
@@ -83,10 +75,9 @@ module Hamster
83
75
  #
84
76
  # @return [Set]
85
77
  # @private
86
- def alloc(node, comparator)
78
+ def alloc(node)
87
79
  result = allocate
88
80
  result.instance_variable_set(:@node, node)
89
- result.instance_variable_set(:@comparator, comparator)
90
81
  result
91
82
  end
92
83
  end
@@ -94,16 +85,17 @@ module Hamster
94
85
  def initialize(items=[], &block)
95
86
  items = items.to_a
96
87
  if block
97
- @comparator = if block.arity == 1
98
- lambda { |a,b| block.call(a) <=> block.call(b) }
88
+ if block.arity == 1 || block.arity == -1
89
+ comparator = lambda { |a,b| block.call(a) <=> block.call(b) }
90
+ items = items.sort_by(&block)
99
91
  else
100
- block
92
+ comparator = block
93
+ items = items.sort(&block)
101
94
  end
102
- items = items.sort(&@comparator)
95
+ @node = AVLNode.from_items(items, comparator)
103
96
  else
104
- items = items.sort
97
+ @node = PlainAVLNode.from_items(items.sort)
105
98
  end
106
- @node = AVLNode.from_items(items, 0, items.size-1)
107
99
  end
108
100
 
109
101
  # Return `true` if this `SortedSet` contains no items.
@@ -112,33 +104,45 @@ module Hamster
112
104
  def empty?
113
105
  @node.empty?
114
106
  end
115
- def_delegator :self, :empty?, :null?
116
107
 
117
108
  # Return the number of items in this `SortedSet`.
118
109
  #
110
+ # @example
111
+ # Hamster::SortedSet["A", "B", "C"].size # => 3
112
+ #
119
113
  # @return [Integer]
120
114
  def size
121
115
  @node.size
122
116
  end
123
- def_delegator :self, :size, :length
117
+ alias :length :size
124
118
 
125
119
  # Return a new `SortedSet` with `item` added. If `item` is already in the set,
126
120
  # return `self`.
127
121
  #
122
+ # @example
123
+ # Hamster::SortedSet["Dog", "Lion"].add("Elephant")
124
+ # # => Hamster::SortedSet["Dog", "Elephant", "Lion"]
125
+ #
128
126
  # @param item [Object] The object to add
129
127
  # @return [SortedSet]
130
128
  def add(item)
131
- return self if include?(item)
132
- node = @node.insert(item, @comparator)
133
- self.class.alloc(node, @comparator)
129
+ catch :present do
130
+ node = @node.insert(item)
131
+ return self.class.alloc(node)
132
+ end
133
+ self
134
134
  end
135
- def_delegator :self, :add, :<<
136
- def_delegator :self, :add, :conj
137
- def_delegator :self, :add, :conjoin
135
+ alias :<< :add
138
136
 
139
137
  # If `item` is not a member of this `SortedSet`, return a new `SortedSet` with
140
138
  # `item` added. Otherwise, return `false`.
141
139
  #
140
+ # @example
141
+ # Hamster::SortedSet["Dog", "Lion"].add?("Elephant")
142
+ # # => Hamster::SortedSet["Dog", "Elephant", "Lion"]
143
+ # Hamster::SortedSet["Dog", "Lion"].add?("Lion")
144
+ # # => false
145
+ #
142
146
  # @param item [Object] The object to add
143
147
  # @return [SortedSet, false]
144
148
  def add?(item)
@@ -148,21 +152,33 @@ module Hamster
148
152
  # Return a new `SortedSet` with `item` removed. If `item` is not a member of the set,
149
153
  # return `self`.
150
154
  #
155
+ # @example
156
+ # Hamster::SortedSet["A", "B", "C"].delete("B")
157
+ # # => Hamster::SortedSet["A", "C"]
158
+ #
151
159
  # @param item [Object] The object to remove
152
160
  # @return [SortedSet]
153
161
  def delete(item)
154
- return self if not include?(item)
155
- node = @node.delete(item, @comparator)
156
- if node.empty?
157
- self.class.empty
158
- else
159
- self.class.alloc(node, @comparator)
162
+ catch :not_present do
163
+ node = @node.delete(item)
164
+ if node.empty? && node.natural_order?
165
+ return self.class.empty
166
+ else
167
+ return self.class.alloc(node)
168
+ end
160
169
  end
170
+ self
161
171
  end
162
172
 
163
173
  # If `item` is a member of this `SortedSet`, return a new `SortedSet` with
164
174
  # `item` removed. Otherwise, return `false`.
165
175
  #
176
+ # @example
177
+ # Hamster::SortedSet["A", "B", "C"].delete?("B")
178
+ # # => Hamster::SortedSet["A", "C"]
179
+ # Hamster::SortedSet["A", "B", "C"].delete?("Z")
180
+ # # => false
181
+ #
166
182
  # @param item [Object] The object to remove
167
183
  # @return [SortedSet, false]
168
184
  def delete?(item)
@@ -172,6 +188,10 @@ module Hamster
172
188
  # Return a new `SortedSet` with the item at `index` removed. If the given `index`
173
189
  # does not exist (if it is too high or too low), return `self`.
174
190
  #
191
+ # @example
192
+ # Hamster::SortedSet["A", "B", "C", "D"].delete_at(2)
193
+ # # => Hamster::SortedSet["A", "B", "D"]
194
+ #
175
195
  # @param index [Integer] The index to remove
176
196
  # @return [SortedSet]
177
197
  def delete_at(index)
@@ -181,6 +201,12 @@ module Hamster
181
201
  # Retrieve the item at `index`. If there is none (either the provided index
182
202
  # is too high or too low), return `nil`.
183
203
  #
204
+ # @example
205
+ # s = Hamster::SortedSet["A", "B", "C", "D", "E", "F"]
206
+ # s.at(2) # => "C"
207
+ # s.at(-2) # => "E"
208
+ # s.at(6) # => nil
209
+ #
184
210
  # @param index [Integer] The index to retrieve
185
211
  # @return [Object]
186
212
  def at(index)
@@ -189,24 +215,43 @@ module Hamster
189
215
  @node.at(index)
190
216
  end
191
217
 
192
- # Retrieve the value at `index`, or use the provided default value or block,
193
- # or otherwise raise an `IndexError`.
218
+ # Retrieve the value at `index` with optional default.
194
219
  #
195
220
  # @overload fetch(index)
196
- # Retrieve the value at the given index, or raise an `IndexError` if it is
197
- # not found.
221
+ # Retrieve the value at the given index, or raise an `IndexError` if not
222
+ # found.
223
+ #
198
224
  # @param index [Integer] The index to look up
225
+ # @raise [IndexError] if index does not exist
226
+ # @example
227
+ # v = Hamster::SortedSet["A", "B", "C", "D"]
228
+ # v.fetch(2) # => "C"
229
+ # v.fetch(-1) # => "D"
230
+ # v.fetch(4) # => IndexError: index 4 outside of vector bounds
231
+ #
199
232
  # @overload fetch(index) { |index| ... }
200
- # Retrieve the value at the given index, or call the optional
201
- # code block (with the non-existent index) and get its return value.
202
- # @yield [index] The index which does not exist
203
- # @yieldreturn [Object] Object to return instead
233
+ # Retrieve the value at the given index, or return the result of yielding
234
+ # the block if not found.
235
+ #
236
+ # @yield Once if the index is not found.
237
+ # @yieldparam [Integer] index The index which does not exist
238
+ # @yieldreturn [Object] Default value to return
204
239
  # @param index [Integer] The index to look up
240
+ # @example
241
+ # v = Hamster::SortedSet["A", "B", "C", "D"]
242
+ # v.fetch(2) { |i| i * i } # => "C"
243
+ # v.fetch(4) { |i| i * i } # => 16
244
+ #
205
245
  # @overload fetch(index, default)
206
- # Retrieve the value at the given index, or else return the provided
207
- # `default` value.
246
+ # Retrieve the value at the given index, or return the provided `default`
247
+ # value if not found.
248
+ #
208
249
  # @param index [Integer] The index to look up
209
250
  # @param default [Object] Object to return if the key is not found
251
+ # @example
252
+ # v = Hamster::SortedSet["A", "B", "C", "D"]
253
+ # v.fetch(2, "Z") # => "C"
254
+ # v.fetch(4, "Z") # => "Z"
210
255
  #
211
256
  # @return [Object]
212
257
  def fetch(index, default = (missing_default = true))
@@ -221,22 +266,47 @@ module Hamster
221
266
  end
222
267
  end
223
268
 
224
- # Element reference. Return the item at a specific index, or a specified,
225
- # contiguous range of items (as a new `SortedSet`).
269
+ # Return specific objects from the `Vector`. All overloads return `nil` if
270
+ # the starting index is out of range.
271
+ #
272
+ # @overload set.slice(index)
273
+ # Returns a single object at the given `index`. If `index` is negative,
274
+ # count backwards from the end.
275
+ #
276
+ # @param index [Integer] The index to retrieve. May be negative.
277
+ # @return [Object]
278
+ # @example
279
+ # s = Hamster::SortedSet["A", "B", "C", "D", "E", "F"]
280
+ # s[2] # => "C"
281
+ # s[-1] # => "F"
282
+ # s[6] # => nil
283
+ #
284
+ # @overload set.slice(index, length)
285
+ # Return a subset starting at `index` and continuing for `length`
286
+ # elements or until the end of the `SortedSet`, whichever occurs first.
226
287
  #
227
- # @overload set[index]
228
- # Return the item at `index`.
229
- # @param index [Integer] The index to retrieve.
230
- # @overload set[start, length]
231
- # Return a subset starting at index `start` and continuing for `length` elements.
232
- # @param start [Integer] The index to start retrieving items from.
288
+ # @param start [Integer] The index to start retrieving items from. May be
289
+ # negative.
233
290
  # @param length [Integer] The number of items to retrieve.
234
- # @overload set[range]
235
- # Return a subset specified by the given `range` of indices.
236
- # @param range [Range] The range of indices to retrieve.
291
+ # @return [SortedSet]
292
+ # @example
293
+ # s = Hamster::SortedSet["A", "B", "C", "D", "E", "F"]
294
+ # s[2, 3] # => Hamster::SortedSet["C", "D", "E"]
295
+ # s[-2, 3] # => Hamster::SortedSet["E", "F"]
296
+ # s[20, 1] # => nil
237
297
  #
238
- # @return [Object]
239
- def [](arg, length = (missing_length = true))
298
+ # @overload set.slice(index..end)
299
+ # Return a subset starting at `index` and continuing to index
300
+ # `end` or the end of the `SortedSet`, whichever occurs first.
301
+ #
302
+ # @param range [Range] The range of indices to retrieve.
303
+ # @return [SortedSet]
304
+ # @example
305
+ # s = Hamster::SortedSet["A", "B", "C", "D", "E", "F"]
306
+ # s[2..3] # => Hamster::SortedSet["C", "D"]
307
+ # s[-2..100] # => Hamster::SortedSet["E", "F"]
308
+ # s[20..21] # => nil
309
+ def slice(arg, length = (missing_length = true))
240
310
  if missing_length
241
311
  if arg.is_a?(Range)
242
312
  from, to = arg.begin, arg.end
@@ -254,11 +324,15 @@ module Hamster
254
324
  subsequence(arg, length)
255
325
  end
256
326
  end
257
- def_delegator :self, :[], :slice
327
+ alias :[] :slice
258
328
 
259
329
  # Return a new `SortedSet` with only the elements at the given `indices`.
260
330
  # If any of the `indices` do not exist, they will be skipped.
261
331
  #
332
+ # @example
333
+ # s = Hamster::SortedSet["A", "B", "C", "D", "E", "F"]
334
+ # s.values_at(2, 4, 5) # => Hamster::SortedSet["C", "E", "F"]
335
+ #
262
336
  # @param indices [Array] The indices to retrieve and gather into a new `SortedSet`
263
337
  # @return [SortedSet]
264
338
  def values_at(*indices)
@@ -267,9 +341,19 @@ module Hamster
267
341
  end
268
342
 
269
343
  # Call the given block once for each item in the set, passing each
270
- # item from first to last successively to the block.
344
+ # item from first to last successively to the block. If no block is
345
+ # provided, returns an `Enumerator`.
271
346
  #
272
- # @return [self]
347
+ # @example
348
+ # Hamster::SortedSet["A", "B", "C"].each { |e| puts "Element: #{e}" }
349
+ #
350
+ # Element: A
351
+ # Element: B
352
+ # Element: C
353
+ # # => Hamster::SortedSet["A", "B", "C"]
354
+ #
355
+ # @yield [item]
356
+ # @return [self, Enumerator]
273
357
  def each(&block)
274
358
  return @node.to_enum if not block_given?
275
359
  @node.each(&block)
@@ -280,6 +364,14 @@ module Hamster
280
364
  # item starting from the last, and counting back to the first, successively to
281
365
  # the block.
282
366
  #
367
+ # @example
368
+ # Hamster::SortedSet["A", "B", "C"].reverse_each { |e| puts "Element: #{e}" }
369
+ #
370
+ # Element: C
371
+ # Element: B
372
+ # Element: A
373
+ # # => Hamster::SortedSet["A", "B", "C"]
374
+ #
283
375
  # @return [self]
284
376
  def reverse_each(&block)
285
377
  return @node.enum_for(:reverse_each) if not block_given?
@@ -288,80 +380,146 @@ module Hamster
288
380
  end
289
381
 
290
382
  # Return the "lowest" element in this set, as determined by its sort order.
383
+ # Or, if a block is provided, use the block as a comparator to find the
384
+ # "lowest" element. (See `Enumerable#min`.)
385
+ #
386
+ # @example
387
+ # Hamster::SortedSet["A", "B", "C"].min # => "A"
388
+ #
291
389
  # @return [Object]
390
+ # @yield [a, b] Any number of times with different pairs of elements.
292
391
  def min
392
+ block_given? ? super : @node.min
393
+ end
394
+
395
+ # Return the "lowest" element in this set, as determined by its sort order.
396
+ # @return [Object]
397
+ def first
293
398
  @node.min
294
399
  end
295
- alias :first :min
296
- def_delegator :self, :first, :head
297
400
 
298
401
  # Return the "highest" element in this set, as determined by its sort order.
402
+ # Or, if a block is provided, use the block as a comparator to find the
403
+ # "highest" element. (See `Enumerable#max`.)
404
+ #
405
+ # @example
406
+ # Hamster::SortedSet["A", "B", "C"].max # => "C"
407
+ #
408
+ # @yield [a, b] Any number of times with different pairs of elements.
299
409
  # @return [Object]
300
410
  def max
411
+ block_given? ? super : @node.max
412
+ end
413
+
414
+ # Return the "highest" element in this set, as determined by its sort order.
415
+ # @return [Object]
416
+ def last
301
417
  @node.max
302
418
  end
303
- alias :last :max
304
419
 
305
420
  # Return a new `SortedSet` containing all elements for which the given block returns
306
421
  # true.
307
422
  #
423
+ # @example
424
+ # Hamster::SortedSet["Bird", "Cow", "Elephant"].select { |e| e.size >= 4 }
425
+ # # => Hamster::SortedSet["Bird", "Elephant"]
426
+ #
308
427
  # @return [SortedSet]
309
- def filter
310
- return enum_for(:filter) unless block_given?
311
- reduce(self) { |set, item| yield(item) ? set : set.delete(item) }
428
+ # @yield [item] Once for each item.
429
+ def select
430
+ return enum_for(:select) unless block_given?
431
+ items_to_delete = []
432
+ each { |item| items_to_delete << item unless yield(item) }
433
+ derive_new_sorted_set(@node.bulk_delete(items_to_delete))
312
434
  end
435
+ alias :find_all :select
436
+ alias :keep_if :select
313
437
 
314
438
  # Invoke the given block once for each item in the set, and return a new
315
- # `SortedSet` containing the values returned by the block.
439
+ # `SortedSet` containing the values returned by the block. If no block is
440
+ # given, returns an `Enumerator`.
316
441
  #
317
- # @return [SortedSet]
442
+ # @example
443
+ # Hamster::SortedSet[1, 2, 3].map { |e| -(e * e) }
444
+ # # => Hamster::SortedSet[-9, -4, -1]
445
+ #
446
+ # @return [SortedSet, Enumerator]
447
+ # @yield [item] Once for each item.
318
448
  def map
319
449
  return enum_for(:map) if not block_given?
320
450
  return self if empty?
321
- self.class.new(super, &@comparator)
451
+ self.class.alloc(@node.from_items(super))
322
452
  end
323
- def_delegator :self, :map, :collect
453
+ alias :collect :map
324
454
 
325
455
  # Return `true` if the given item is present in this `SortedSet`. More precisely,
326
456
  # return `true` if an object which compares as "equal" using this set's
327
457
  # comparator is present.
328
458
  #
459
+ # @example
460
+ # Hamster::SortedSet["A", "B", "C"].include?("B") # => true
461
+ #
329
462
  # @param item [Object] The object to check for
330
463
  # @return [Boolean]
331
464
  def include?(item)
332
- @node.include?(item, @comparator)
465
+ @node.include?(item)
333
466
  end
334
- def_delegator :self, :include?, :member?
467
+ alias :member? :include?
335
468
 
336
- # Return a new `SortedSet` with the same items, but a sort order determined by
337
- # the given block.
469
+ # Return a new `SortedSet` with the same items, but a sort order determined
470
+ # by the given block.
471
+ #
472
+ # @example
473
+ # Hamster::SortedSet["Bird", "Cow", "Elephant"].sort { |a, b| a.size <=> b.size }
474
+ # # => Hamster::SortedSet["Cow", "Bird", "Elephant"]
475
+ # Hamster::SortedSet["Bird", "Cow", "Elephant"].sort_by { |e| e.size }
476
+ # # => Hamster::SortedSet["Cow", "Bird", "Elephant"]
338
477
  #
339
478
  # @return [SortedSet]
340
479
  def sort(&block)
341
- block ||= lambda { |a,b| a <=> b }
342
- self.class.new(self.to_a, &block)
480
+ if block
481
+ self.class.new(self.to_a, &block)
482
+ else
483
+ self.class.new(self.to_a.sort)
484
+ end
343
485
  end
344
486
  alias :sort_by :sort
345
487
 
346
- # Return the index of the first object in this set which is equal to
347
- # `obj`. Rather than using `#==`, we use `#<=>` (or our comparator block) for
348
- # comparisons. This means we can find the index in O(log N) time, rather than O(N).
488
+ # Find the index of a given object or an element that satisfies the given
489
+ # block.
349
490
  #
350
- # @param obj [Object] The object to search for
351
- # @return [Integer]
491
+ # @overload find_index(obj)
492
+ # Return the index of the first object in this set which is equal to
493
+ # `obj`. Rather than using `#==`, we use `#<=>` (or our comparator block)
494
+ # for comparisons. This means we can find the index in `O(log N)` time,
495
+ # rather than `O(N)`.
496
+ # @param obj [Object] The object to search for
497
+ # @example
498
+ # s = Hamster::SortedSet[2, 4, 6, 8, 10]
499
+ # s.find_index(8) # => 3
500
+ # @overload find_index
501
+ # Return the index of the first object in this sorted set for which the
502
+ # block returns to true. This takes `O(N)` time.
503
+ # @yield [element] An element in the sorted set
504
+ # @yieldreturn [Boolean] True if this is element matches
505
+ # @example
506
+ # s = Hamster::SortedSet[2, 4, 6, 8, 10]
507
+ # s.find_index { |e| e > 7 } # => 3
508
+ #
509
+ # @return [Integer] The index of the object, or `nil` if not found.
352
510
  def find_index(obj = (missing_obj = true), &block)
353
511
  if !missing_obj
354
512
  # Enumerable provides a default implementation, but this is more efficient
355
513
  node = @node
356
514
  index = node.left.size
357
515
  while !node.empty?
358
- direction = node.direction(obj, @comparator)
516
+ direction = node.direction(obj)
359
517
  if direction > 0
360
518
  node = node.right
361
- index += node.left.size
519
+ index += (node.left.size + 1)
362
520
  elsif direction < 0
363
521
  node = node.left
364
- index -= node.right.size
522
+ index -= (node.right.size + 1)
365
523
  else
366
524
  return index
367
525
  end
@@ -371,40 +529,70 @@ module Hamster
371
529
  super(&block)
372
530
  end
373
531
  end
374
- def_delegator :self, :find_index, :index
532
+ alias :index :find_index
375
533
 
376
534
  # Drop the first `n` elements and return the rest in a new `SortedSet`.
535
+ #
536
+ # @example
537
+ # Hamster::SortedSet["A", "B", "C", "D", "E", "F"].drop(2)
538
+ # # => Hamster::SortedSet["C", "D", "E", "F"]
539
+ #
377
540
  # @param n [Integer] The number of elements to remove
378
541
  # @return [SortedSet]
379
542
  def drop(n)
380
- self.class.new(super)
543
+ derive_new_sorted_set(@node.drop(n))
381
544
  end
382
545
 
383
546
  # Return only the first `n` elements in a new `SortedSet`.
547
+ #
548
+ # @example
549
+ # Hamster::SortedSet["A", "B", "C", "D", "E", "F"].take(4)
550
+ # # => Hamster::SortedSet["A", "B", "C", "D"]
551
+ #
384
552
  # @param n [Integer] The number of elements to retain
385
553
  # @return [SortedSet]
386
554
  def take(n)
387
- self.class.new(super)
555
+ derive_new_sorted_set(@node.take(n))
388
556
  end
389
557
 
390
558
  # Drop elements up to, but not including, the first element for which the
391
559
  # block returns `nil` or `false`. Gather the remaining elements into a new
392
560
  # `SortedSet`. If no block is given, an `Enumerator` is returned instead.
393
561
  #
562
+ # @example
563
+ # Hamster::SortedSet[2, 4, 6, 7, 8, 9].drop_while { |e| e.even? }
564
+ # # => Hamster::SortedSet[7, 8, 9]
565
+ #
566
+ # @yield [item]
394
567
  # @return [SortedSet, Enumerator]
395
568
  def drop_while
396
569
  return enum_for(:drop_while) if not block_given?
397
- self.class.new(super)
570
+ n = 0
571
+ each do |item|
572
+ break unless yield item
573
+ n += 1
574
+ end
575
+ drop(n)
398
576
  end
399
577
 
400
578
  # Gather elements up to, but not including, the first element for which the
401
579
  # block returns `nil` or `false`, and return them in a new `SortedSet`. If no block
402
580
  # is given, an `Enumerator` is returned instead.
403
581
  #
582
+ # @example
583
+ # Hamster::SortedSet[2, 4, 6, 7, 8, 9].take_while { |e| e.even? }
584
+ # # => Hamster::SortedSet[2, 4, 6]
585
+ #
404
586
  # @return [SortedSet, Enumerator]
587
+ # @yield [item]
405
588
  def take_while
406
589
  return enum_for(:take_while) if not block_given?
407
- self.class.new(super)
590
+ n = 0
591
+ each do |item|
592
+ break unless yield item
593
+ n += 1
594
+ end
595
+ take(n)
408
596
  end
409
597
 
410
598
  # Return a new `SortedSet` which contains all the members of both this set and `other`.
@@ -417,11 +605,11 @@ module Hamster
417
605
  # @param other [Enumerable] The collection to merge with
418
606
  # @return [SortedSet]
419
607
  def union(other)
420
- self.class.alloc(@node.bulk_insert(other, @comparator), @comparator)
608
+ self.class.alloc(@node.bulk_insert(other))
421
609
  end
422
- def_delegator :self, :union, :|
423
- def_delegator :self, :union, :+
424
- def_delegator :self, :union, :merge
610
+ alias :| :union
611
+ alias :+ :union
612
+ alias :merge :union
425
613
 
426
614
  # Return a new `SortedSet` which contains all the items which are members of both
427
615
  # this set and `other`. `other` can be any `Enumerable` object.
@@ -433,10 +621,9 @@ module Hamster
433
621
  # @param other [Enumerable] The collection to intersect with
434
622
  # @return [SortedSet]
435
623
  def intersection(other)
436
- self.class.alloc(@node.keep_only(other, @comparator), @comparator)
624
+ self.class.alloc(@node.keep_only(other))
437
625
  end
438
- def_delegator :self, :intersection, :intersect
439
- def_delegator :self, :intersection, :&
626
+ alias :& :intersection
440
627
 
441
628
  # Return a new `SortedSet` with all the items in `other` removed. `other` can be
442
629
  # any `Enumerable` object.
@@ -448,11 +635,10 @@ module Hamster
448
635
  # @param other [Enumerable] The collection to subtract from this set
449
636
  # @return [SortedSet]
450
637
  def difference(other)
451
- self.class.alloc(@node.bulk_delete(other, @comparator), @comparator)
638
+ self.class.alloc(@node.bulk_delete(other))
452
639
  end
453
- def_delegator :self, :difference, :diff
454
- def_delegator :self, :difference, :subtract
455
- def_delegator :self, :difference, :-
640
+ alias :subtract :difference
641
+ alias :- :difference
456
642
 
457
643
  # Return a new `SortedSet` with all the items which are members of this
458
644
  # set or of `other`, but not both. `other` can be any `Enumerable` object.
@@ -466,10 +652,13 @@ module Hamster
466
652
  def exclusion(other)
467
653
  ((self | other) - (self & other))
468
654
  end
469
- def_delegator :self, :exclusion, :^
655
+ alias :^ :exclusion
470
656
 
471
657
  # Return `true` if all items in this set are also in `other`.
472
658
  #
659
+ # @example
660
+ # Hamster::SortedSet[2, 3].subset?(Hamster::SortedSet[1, 2, 3]) # => true
661
+ #
473
662
  # @param other [Enumerable]
474
663
  # @return [Boolean]
475
664
  def subset?(other)
@@ -479,6 +668,9 @@ module Hamster
479
668
 
480
669
  # Return `true` if all items in `other` are also in this set.
481
670
  #
671
+ # @example
672
+ # Hamster::SortedSet[1, 2, 3].superset?(Hamster::SortedSet[2, 3]) # => true
673
+ #
482
674
  # @param other [Enumerable]
483
675
  # @return [Boolean]
484
676
  def superset?(other)
@@ -488,6 +680,10 @@ module Hamster
488
680
  # Returns `true` if `other` contains all the items in this set, plus at least
489
681
  # one item which is not in this set.
490
682
  #
683
+ # @example
684
+ # Hamster::SortedSet[2, 3].proper_subset?(Hamster::SortedSet[1, 2, 3]) # => true
685
+ # Hamster::SortedSet[1, 2, 3].proper_subset?(Hamster::SortedSet[1, 2, 3]) # => false
686
+ #
491
687
  # @param other [Enumerable]
492
688
  # @return [Boolean]
493
689
  def proper_subset?(other)
@@ -498,6 +694,10 @@ module Hamster
498
694
  # Returns `true` if this set contains all the items in `other`, plus at least
499
695
  # one item which is not in `other`.
500
696
  #
697
+ # @example
698
+ # Hamster::SortedSet[1, 2, 3].proper_superset?(Hamster::SortedSet[2, 3]) # => true
699
+ # Hamster::SortedSet[1, 2, 3].proper_superset?(Hamster::SortedSet[1, 2, 3]) # => false
700
+ #
501
701
  # @param other [Enumerable]
502
702
  # @return [Boolean]
503
703
  def proper_superset?(other)
@@ -506,6 +706,9 @@ module Hamster
506
706
 
507
707
  # Return `true` if this set and `other` do not share any items.
508
708
  #
709
+ # @example
710
+ # Hamster::SortedSet[1, 2].disjoint?(Hamster::SortedSet[3, 4]) # => true
711
+ #
509
712
  # @param other [Enumerable]
510
713
  # @return [Boolean]
511
714
  def disjoint?(other)
@@ -519,80 +722,185 @@ module Hamster
519
722
 
520
723
  # Return `true` if this set and `other` have at least one item in common.
521
724
  #
725
+ # @example
726
+ # Hamster::SortedSet[1, 2].intersect?(Hamster::SortedSet[2, 3]) # => true
727
+ #
522
728
  # @param other [Enumerable]
523
729
  # @return [Boolean]
524
730
  def intersect?(other)
525
731
  !disjoint?(other)
526
732
  end
527
733
 
528
- def_delegator :self, :group_by, :group
529
- def_delegator :self, :group_by, :classify
734
+ alias :group :group_by
735
+ alias :classify :group_by
530
736
 
531
- # With a block, yield all the items which are "higher" than `item` (as defined
532
- # by the set's comparator). Otherwise, return them as a new `SortedSet`.
737
+ # Select elements greater than a value.
738
+ #
739
+ # @overload above(item)
740
+ # Return a new `SortedSet` containing all items greater than `item`.
741
+ # @return [SortedSet]
742
+ # @example
743
+ # s = Hamster::SortedSet[2, 4, 6, 8, 10]
744
+ # s.above(6)
745
+ # # => Hamster::SortedSet[8, 10]
746
+ #
747
+ # @overload above(item)
748
+ # @yield [item] Once for each item greater than `item`, in order from
749
+ # lowest to highest.
750
+ # @return [nil]
751
+ # @example
752
+ # s = Hamster::SortedSet[2, 4, 6, 8, 10]
753
+ # s.above(6) { |e| puts "Element: #{e}" }
754
+ #
755
+ # Element: 8
756
+ # Element: 10
757
+ # # => nil
533
758
  #
534
759
  # @param item [Object]
535
760
  def above(item, &block)
536
761
  if block_given?
537
- @node.each_greater(item, @comparator, false, &block)
762
+ @node.each_greater(item, false, &block)
538
763
  else
539
- self.class.alloc(@node.suffix(item, @comparator, false), @comparator)
764
+ self.class.alloc(@node.suffix(item, false))
540
765
  end
541
766
  end
542
767
 
543
- # With a block, yield all the items which are "higher" than `item` (as defined
544
- # by the set's comparator). Otherwise, return them as a new `SortedSet`.
768
+ # Select elements less than a value.
769
+ #
770
+ # @overload below(item)
771
+ # Return a new `SortedSet` containing all items less than `item`.
772
+ # @return [SortedSet]
773
+ # @example
774
+ # s = Hamster::SortedSet[2, 4, 6, 8, 10]
775
+ # s.below(6)
776
+ # # => Hamster::SortedSet[2, 4]
777
+ #
778
+ # @overload below(item)
779
+ # @yield [item] Once for each item less than `item`, in order from lowest
780
+ # to highest.
781
+ # @return [nil]
782
+ # @example
783
+ # s = Hamster::SortedSet[2, 4, 6, 8, 10]
784
+ # s.below(6) { |e| puts "Element: #{e}" }
785
+ #
786
+ # Element: 2
787
+ # Element: 4
788
+ # # => nil
545
789
  #
546
790
  # @param item [Object]
547
791
  def below(item, &block)
548
792
  if block_given?
549
- @node.each_less(item, @comparator, false, &block)
793
+ @node.each_less(item, false, &block)
550
794
  else
551
- self.class.alloc(@node.prefix(item, @comparator, false), @comparator)
795
+ self.class.alloc(@node.prefix(item, false))
552
796
  end
553
797
  end
554
798
 
555
- # With a block, yield all the items which are "higher" or equal to `item`
556
- # (as determined by the set's comparator). Otherwise, return them as a new
557
- # `SortedSet`.
799
+ # Select elements greater than or equal to a value.
800
+ #
801
+ # @overload from(item)
802
+ # Return a new `SortedSet` containing all items greater than or equal `item`.
803
+ # @return [SortedSet]
804
+ # @example
805
+ # s = Hamster::SortedSet[2, 4, 6, 8, 10]
806
+ # s.from(6)
807
+ # # => Hamster::SortedSet[6, 8, 10]
808
+ #
809
+ # @overload from(item)
810
+ # @yield [item] Once for each item greater than or equal to `item`, in
811
+ # order from lowest to highest.
812
+ # @return [nil]
813
+ # @example
814
+ # s = Hamster::SortedSet[2, 4, 6, 8, 10]
815
+ # s.from(6) { |e| puts "Element: #{e}" }
816
+ #
817
+ # Element: 6
818
+ # Element: 8
819
+ # Element: 10
820
+ # # => nil
558
821
  #
559
822
  # @param item [Object]
560
823
  def from(item, &block)
561
824
  if block_given?
562
- @node.each_greater(item, @comparator, true, &block)
825
+ @node.each_greater(item, true, &block)
563
826
  else
564
- self.class.alloc(@node.suffix(item, @comparator, true), @comparator)
827
+ self.class.alloc(@node.suffix(item, true))
565
828
  end
566
829
  end
567
830
 
568
- # With a block, yield all the items which are "lower" than `item` (as defined
569
- # by the set's comparator). Otherwise, return them as a new `SortedSet`.
831
+ # Select elements less than or equal to a value.
832
+ #
833
+ # @overload up_to(item)
834
+ # Return a new `SortedSet` containing all items less than or equal to
835
+ # `item`.
836
+ #
837
+ # @return [SortedSet]
838
+ # @example
839
+ # s = Hamster::SortedSet[2, 4, 6, 8, 10]
840
+ # s.upto(6)
841
+ # # => Hamster::SortedSet[2, 4, 6]
842
+ #
843
+ # @overload up_to(item)
844
+ # @yield [item] Once for each item less than or equal to `item`, in order
845
+ # from lowest to highest.
846
+ # @return [nil]
847
+ # @example
848
+ # s = Hamster::SortedSet[2, 4, 6, 8, 10]
849
+ # s.up_to(6) { |e| puts "Element: #{e}" }
850
+ #
851
+ # Element: 2
852
+ # Element: 4
853
+ # Element: 6
854
+ # # => nil
570
855
  #
571
856
  # @param item [Object]
572
857
  def up_to(item, &block)
573
858
  if block_given?
574
- @node.each_less(item, @comparator, true, &block)
859
+ @node.each_less(item, true, &block)
575
860
  else
576
- self.class.alloc(@node.prefix(item, @comparator, true), @comparator)
861
+ self.class.alloc(@node.prefix(item, true))
577
862
  end
578
863
  end
579
864
 
580
- # With a block, yield all the items which are equal or higher than `from` and
581
- # equal or less than `to` (as determined by the set's comparator). Otherwise,
582
- # return the specified range of items as a new `SortedSet`.
865
+ # Select elements between two values.
866
+ #
867
+ # @overload between(from, to)
868
+ # Return a new `SortedSet` containing all items less than or equal to
869
+ # `to` and greater than or equal to `from`.
870
+ #
871
+ # @return [SortedSet]
872
+ # @example
873
+ # s = Hamster::SortedSet[2, 4, 6, 8, 10]
874
+ # s.between(5, 8)
875
+ # # => Hamster::SortedSet[6, 8]
876
+ #
877
+ # @overload between(item)
878
+ # @yield [item] Once for each item less than or equal to `to` and greater
879
+ # than or equal to `from`, in order from lowest to highest.
880
+ # @return [nil]
881
+ # @example
882
+ # s = Hamster::SortedSet[2, 4, 6, 8, 10]
883
+ # s.between(5, 8) { |e| puts "Element: #{e}" }
884
+ #
885
+ # Element: 6
886
+ # Element: 8
887
+ # # => nil
583
888
  #
584
889
  # @param from [Object]
585
890
  # @param to [Object]
586
891
  def between(from, to, &block)
587
892
  if block_given?
588
- @node.each_between(from, to, @comparator, &block)
893
+ @node.each_between(from, to, &block)
589
894
  else
590
- self.class.alloc(@node.between(from, to, @comparator), @comparator)
895
+ self.class.alloc(@node.between(from, to))
591
896
  end
592
897
  end
593
898
 
594
899
  # Return a randomly chosen item from this set. If the set is empty, return `nil`.
595
900
  #
901
+ # @example
902
+ # Hamster::SortedSet[1, 2, 3, 4, 5].sample # => 2
903
+ #
596
904
  # @return [Object]
597
905
  def sample
598
906
  @node.at(rand(@node.size))
@@ -601,9 +909,13 @@ module Hamster
601
909
  # Return an empty `SortedSet` instance, of the same class as this one. Useful if you
602
910
  # have multiple subclasses of `SortedSet` and want to treat them polymorphically.
603
911
  #
604
- # @return [Hash]
912
+ # @return [SortedSet]
605
913
  def clear
606
- self.class.empty
914
+ if @node.natural_order?
915
+ self.class.empty
916
+ else
917
+ self.class.alloc(@node.clear)
918
+ end
607
919
  end
608
920
 
609
921
  # Return true if `other` has the same type and contents as this `SortedSet`.
@@ -628,17 +940,13 @@ module Hamster
628
940
  reduce(0) { |hash, item| (hash << 5) - hash + item.hash }
629
941
  end
630
942
 
631
- def_delegator :self, :dup, :uniq
632
- def_delegator :self, :dup, :nub
633
- def_delegator :self, :dup, :remove_duplicates
634
-
635
943
  # @return [::Array]
636
944
  # @private
637
945
  def marshal_dump
638
- if @comparator
639
- raise TypeError, "can't dump SortedSet with custom sort order"
640
- else
946
+ if @node.natural_order?
641
947
  to_a
948
+ else
949
+ raise TypeError, "can't dump SortedSet with custom sort order"
642
950
  end
643
951
  end
644
952
 
@@ -652,63 +960,104 @@ module Hamster
652
960
  def subsequence(from, length)
653
961
  return nil if from > @node.size || from < 0 || length < 0
654
962
  length = @node.size - from if @node.size < from + length
655
- return self.class.empty if length == 0
656
- self.class.alloc(@node.slice(from, length), @comparator)
963
+ if length == 0
964
+ if @node.natural_order?
965
+ return self.class.empty
966
+ else
967
+ return self.class.alloc(@node.clear)
968
+ end
969
+ end
970
+ self.class.alloc(@node.slice(from, length))
971
+ end
972
+
973
+ # Return a new `SortedSet` which is derived from this one, using a modified
974
+ # {AVLNode}. The new `SortedSet` will retain the existing comparator, if
975
+ # there is one.
976
+ def derive_new_sorted_set(node)
977
+ if node.equal?(@node)
978
+ self
979
+ elsif node.empty?
980
+ clear
981
+ else
982
+ self.class.alloc(node)
983
+ end
657
984
  end
658
985
 
659
986
  # @private
660
987
  class AVLNode
661
- def self.from_items(items, from, to) # items must be sorted
988
+ def self.from_items(items, comparator, from = 0, to = items.size-1) # items must be sorted
662
989
  size = to - from + 1
663
990
  if size >= 3
664
991
  middle = (to + from) / 2
665
- AVLNode.new(items[middle], AVLNode.from_items(items, from, middle-1), AVLNode.from_items(items, middle+1, to))
992
+ AVLNode.new(items[middle], comparator, AVLNode.from_items(items, comparator, from, middle-1), AVLNode.from_items(items, comparator, middle+1, to))
666
993
  elsif size == 2
667
- AVLNode.new(items[from], EmptyAVLNode, AVLNode.new(items[from+1], EmptyAVLNode, EmptyAVLNode))
994
+ empty = AVLNode::Empty.new(comparator)
995
+ AVLNode.new(items[from], comparator, empty, AVLNode.new(items[from+1], comparator, empty, empty))
668
996
  elsif size == 1
669
- AVLNode.new(items[from], EmptyAVLNode, EmptyAVLNode)
997
+ empty = AVLNode::Empty.new(comparator)
998
+ AVLNode.new(items[from], comparator, empty, empty)
670
999
  elsif size == 0
671
- EmptyAVLNode
1000
+ AVLNode::Empty.new(comparator)
672
1001
  end
673
1002
  end
674
1003
 
675
- def initialize(item, left, right)
676
- @item, @left, @right = item, left, right
677
- @height = ((@right.height > @left.height) ? @right.height : @left.height) + 1
678
- @size = @right.size + @left.size + 1
1004
+ def initialize(item, comparator, left, right)
1005
+ @item, @comparator, @left, @right = item, comparator, left, right
1006
+ @height = ((right.height > left.height) ? right.height : left.height) + 1
1007
+ @size = right.size + left.size + 1
679
1008
  end
680
1009
  attr_reader :item, :left, :right, :height, :size
681
1010
 
1011
+ def from_items(items)
1012
+ AVLNode.from_items(items.sort(&@comparator), @comparator)
1013
+ end
1014
+
1015
+ def natural_order?
1016
+ false
1017
+ end
1018
+
682
1019
  def empty?
683
1020
  false
684
1021
  end
685
1022
 
686
- def insert(item, comparator)
687
- dir = direction(item, comparator)
1023
+ def clear
1024
+ AVLNode::Empty.new(@comparator)
1025
+ end
1026
+
1027
+ def derive(item, left, right)
1028
+ AVLNode.new(item, @comparator, left, right)
1029
+ end
1030
+
1031
+ def insert(item)
1032
+ dir = direction(item)
688
1033
  if dir == 0
689
- self
1034
+ throw :present
690
1035
  elsif dir > 0
691
- rebalance_right(@left, @right.insert(item, comparator))
1036
+ rebalance_right(@left, @right.insert(item))
692
1037
  else
693
- rebalance_left(@left.insert(item, comparator), @right)
1038
+ rebalance_left(@left.insert(item), @right)
694
1039
  end
695
1040
  end
696
1041
 
697
- def bulk_insert(items, comparator)
1042
+ def bulk_insert(items)
698
1043
  return self if items.empty?
699
- return insert(items.first, comparator) if items.size == 1
700
-
701
- left, right = partition(items, comparator)
1044
+ if items.size == 1
1045
+ catch :present do
1046
+ return insert(items.first)
1047
+ end
1048
+ return self
1049
+ end
1050
+ left, right = partition(items)
702
1051
 
703
1052
  if right.size > left.size
704
- rebalance_right(@left.bulk_insert(left, comparator), @right.bulk_insert(right, comparator))
1053
+ rebalance_right(@left.bulk_insert(left), @right.bulk_insert(right))
705
1054
  else
706
- rebalance_left(@left.bulk_insert(left, comparator), @right.bulk_insert(right, comparator))
1055
+ rebalance_left(@left.bulk_insert(left), @right.bulk_insert(right))
707
1056
  end
708
1057
  end
709
1058
 
710
- def delete(item, comparator)
711
- dir = direction(item, comparator)
1059
+ def delete(item)
1060
+ dir = direction(item)
712
1061
  if dir == 0
713
1062
  if @right.empty?
714
1063
  return @left # replace this node with its only child
@@ -719,26 +1068,31 @@ module Hamster
719
1068
  if balance > 0
720
1069
  # tree is leaning to the left. replace with highest node on that side
721
1070
  replace_with = @left.max
722
- AVLNode.new(replace_with, @left.delete(replace_with, comparator), @right)
1071
+ derive(replace_with, @left.delete(replace_with), @right)
723
1072
  else
724
1073
  # tree is leaning to the right. replace with lowest node on that side
725
1074
  replace_with = @right.min
726
- AVLNode.new(replace_with, @left, @right.delete(replace_with, comparator))
1075
+ derive(replace_with, @left, @right.delete(replace_with))
727
1076
  end
728
1077
  elsif dir > 0
729
- rebalance_left(@left, @right.delete(item, comparator))
1078
+ rebalance_left(@left, @right.delete(item))
730
1079
  else
731
- rebalance_right(@left.delete(item, comparator), @right)
1080
+ rebalance_right(@left.delete(item), @right)
732
1081
  end
733
1082
  end
734
1083
 
735
- def bulk_delete(items, comparator)
1084
+ def bulk_delete(items)
736
1085
  return self if items.empty?
737
- return delete(items.first, comparator) if items.size == 1
1086
+ if items.size == 1
1087
+ catch :not_present do
1088
+ return delete(items.first)
1089
+ end
1090
+ return self
1091
+ end
738
1092
 
739
1093
  left, right, keep_item = [], [], true
740
1094
  items.each do |item|
741
- dir = direction(item, comparator)
1095
+ dir = direction(item)
742
1096
  if dir > 0
743
1097
  right << item
744
1098
  elsif dir < 0
@@ -748,17 +1102,17 @@ module Hamster
748
1102
  end
749
1103
  end
750
1104
 
751
- left = @left.bulk_delete(left, comparator)
752
- right = @right.bulk_delete(right, comparator)
753
- finish_removal(keep_item, left, right, comparator)
1105
+ left = @left.bulk_delete(left)
1106
+ right = @right.bulk_delete(right)
1107
+ finish_removal(keep_item, left, right)
754
1108
  end
755
1109
 
756
- def keep_only(items, comparator)
757
- return EmptyAVLNode if items.empty?
1110
+ def keep_only(items)
1111
+ return clear if items.empty?
758
1112
 
759
1113
  left, right, keep_item = [], [], false
760
1114
  items.each do |item|
761
- dir = direction(item, comparator)
1115
+ dir = direction(item)
762
1116
  if dir > 0
763
1117
  right << item
764
1118
  elsif dir < 0
@@ -768,12 +1122,12 @@ module Hamster
768
1122
  end
769
1123
  end
770
1124
 
771
- left = @left.keep_only(left, comparator)
772
- right = @right.keep_only(right, comparator)
773
- finish_removal(keep_item, left, right, comparator)
1125
+ left = @left.keep_only(left)
1126
+ right = @right.keep_only(right)
1127
+ finish_removal(keep_item, left, right)
774
1128
  end
775
1129
 
776
- def finish_removal(keep_item, left, right, comparator)
1130
+ def finish_removal(keep_item, left, right)
777
1131
  # deletion of items may have occurred on left and right sides
778
1132
  # now we may also need to delete the current item
779
1133
  if keep_item
@@ -784,74 +1138,74 @@ module Hamster
784
1138
  left
785
1139
  elsif left.height > right.height
786
1140
  replace_with = left.max
787
- AVLNode.new(replace_with, left.delete(replace_with, comparator), right)
1141
+ derive(replace_with, left.delete(replace_with), right)
788
1142
  else
789
1143
  replace_with = right.min
790
- AVLNode.new(replace_with, left, right.delete(replace_with, comparator))
1144
+ derive(replace_with, left, right.delete(replace_with))
791
1145
  end
792
1146
  end
793
1147
 
794
- def prefix(item, comparator, inclusive)
795
- dir = direction(item, comparator)
1148
+ def prefix(item, inclusive)
1149
+ dir = direction(item)
796
1150
  if dir > 0 || (inclusive && dir == 0)
797
- rebalance_left(@left, @right.prefix(item, comparator, inclusive))
1151
+ rebalance_left(@left, @right.prefix(item, inclusive))
798
1152
  else
799
- @left.prefix(item, comparator, inclusive)
1153
+ @left.prefix(item, inclusive)
800
1154
  end
801
1155
  end
802
1156
 
803
- def suffix(item, comparator, inclusive)
804
- dir = direction(item, comparator)
1157
+ def suffix(item, inclusive)
1158
+ dir = direction(item)
805
1159
  if dir < 0 || (inclusive && dir == 0)
806
- rebalance_right(@left.suffix(item, comparator, inclusive), @right)
1160
+ rebalance_right(@left.suffix(item, inclusive), @right)
807
1161
  else
808
- @right.suffix(item, comparator, inclusive)
1162
+ @right.suffix(item, inclusive)
809
1163
  end
810
1164
  end
811
1165
 
812
- def between(from, to, comparator)
813
- if direction(from, comparator) > 0 # all on the right
814
- @right.between(from, to, comparator)
815
- elsif direction(to, comparator) < 0 # all on the left
816
- @left.between(from, to, comparator)
1166
+ def between(from, to)
1167
+ if direction(from) > 0 # all on the right
1168
+ @right.between(from, to)
1169
+ elsif direction(to) < 0 # all on the left
1170
+ @left.between(from, to)
817
1171
  else
818
- left = @left.suffix(from, comparator, true)
819
- right = @right.prefix(to, comparator, true)
1172
+ left = @left.suffix(from, true)
1173
+ right = @right.prefix(to, true)
820
1174
  rebalance(left, right)
821
1175
  end
822
1176
  end
823
1177
 
824
- def each_less(item, comparator, inclusive, &block)
825
- dir = direction(item, comparator)
1178
+ def each_less(item, inclusive, &block)
1179
+ dir = direction(item)
826
1180
  if dir > 0 || (inclusive && dir == 0)
827
1181
  @left.each(&block)
828
1182
  yield @item
829
- @right.each_less(item, comparator, inclusive, &block)
1183
+ @right.each_less(item, inclusive, &block)
830
1184
  else
831
- @left.each_less(item, comparator, inclusive, &block)
1185
+ @left.each_less(item, inclusive, &block)
832
1186
  end
833
1187
  end
834
1188
 
835
- def each_greater(item, comparator, inclusive, &block)
836
- dir = direction(item, comparator)
1189
+ def each_greater(item, inclusive, &block)
1190
+ dir = direction(item)
837
1191
  if dir < 0 || (inclusive && dir == 0)
838
- @left.each_greater(item, comparator, inclusive, &block)
1192
+ @left.each_greater(item, inclusive, &block)
839
1193
  yield @item
840
1194
  @right.each(&block)
841
1195
  else
842
- @right.each_greater(item, comparator, inclusive, &block)
1196
+ @right.each_greater(item, inclusive, &block)
843
1197
  end
844
1198
  end
845
1199
 
846
- def each_between(from, to, comparator, &block)
847
- if direction(from, comparator) > 0 # all on the right
848
- @right.each_between(from, to, comparator, &block)
849
- elsif direction(to, comparator) < 0 # all on the left
850
- @left.each_between(from, to, comparator, &block)
1200
+ def each_between(from, to, &block)
1201
+ if direction(from) > 0 # all on the right
1202
+ @right.each_between(from, to, &block)
1203
+ elsif direction(to) < 0 # all on the left
1204
+ @left.each_between(from, to, &block)
851
1205
  else
852
- @left.each_greater(from, comparator, true, &block)
1206
+ @left.each_greater(from, true, &block)
853
1207
  yield @item
854
- @right.each_less(to, comparator, true, &block)
1208
+ @right.each_less(to, true, &block)
855
1209
  end
856
1210
  end
857
1211
 
@@ -867,14 +1221,40 @@ module Hamster
867
1221
  @left.reverse_each(&block)
868
1222
  end
869
1223
 
870
- def include?(item, comparator)
871
- dir = direction(item, comparator)
1224
+ def drop(n)
1225
+ if n >= @size
1226
+ clear
1227
+ elsif n <= 0
1228
+ self
1229
+ elsif @left.size >= n
1230
+ rebalance_right(@left.drop(n), @right)
1231
+ elsif @left.size + 1 == n
1232
+ @right
1233
+ else
1234
+ @right.drop(n - @left.size - 1)
1235
+ end
1236
+ end
1237
+
1238
+ def take(n)
1239
+ if n >= @size
1240
+ self
1241
+ elsif n <= 0
1242
+ clear
1243
+ elsif @left.size >= n
1244
+ @left.take(n)
1245
+ else
1246
+ rebalance_left(@left, @right.take(n - @left.size - 1))
1247
+ end
1248
+ end
1249
+
1250
+ def include?(item)
1251
+ dir = direction(item)
872
1252
  if dir == 0
873
1253
  true
874
1254
  elsif dir > 0
875
- @right.include?(item, comparator)
1255
+ @right.include?(item)
876
1256
  else
877
- @left.include?(item, comparator)
1257
+ @left.include?(item)
878
1258
  end
879
1259
  end
880
1260
 
@@ -902,7 +1282,7 @@ module Hamster
902
1282
 
903
1283
  def slice(from, length)
904
1284
  if length <= 0
905
- EmptyAVLNode
1285
+ clear
906
1286
  elsif from + length <= @left.size
907
1287
  @left.slice(from, length)
908
1288
  elsif from > @left.size
@@ -914,10 +1294,10 @@ module Hamster
914
1294
  end
915
1295
  end
916
1296
 
917
- def partition(items, comparator)
1297
+ def partition(items)
918
1298
  left, right = [], []
919
1299
  items.each do |item|
920
- dir = direction(item, comparator)
1300
+ dir = direction(item)
921
1301
  if dir > 0
922
1302
  right << item
923
1303
  elsif dir < 0
@@ -941,13 +1321,13 @@ module Hamster
941
1321
  if balance >= 2
942
1322
  if left.balance > 0
943
1323
  # single right rotation
944
- AVLNode.new(left.item, left.left, AVLNode.new(@item, left.right, right))
1324
+ derive(left.item, left.left, derive(@item, left.right, right))
945
1325
  else
946
1326
  # left rotation, then right
947
- AVLNode.new(left.right.item, AVLNode.new(left.item, left.left, left.right.left), AVLNode.new(@item, left.right.right, right))
1327
+ derive(left.right.item, derive(left.item, left.left, left.right.left), derive(@item, left.right.right, right))
948
1328
  end
949
1329
  else
950
- AVLNode.new(@item, left, right)
1330
+ derive(@item, left, right)
951
1331
  end
952
1332
  end
953
1333
 
@@ -957,58 +1337,123 @@ module Hamster
957
1337
  if balance <= -2
958
1338
  if right.balance > 0
959
1339
  # right rotation, then left
960
- AVLNode.new(right.left.item, AVLNode.new(@item, left, right.left.left), AVLNode.new(right.item, right.left.right, right.right))
1340
+ derive(right.left.item, derive(@item, left, right.left.left), derive(right.item, right.left.right, right.right))
961
1341
  else
962
1342
  # single left rotation
963
- AVLNode.new(right.item, AVLNode.new(@item, left, right.left), right.right)
1343
+ derive(right.item, derive(@item, left, right.left), right.right)
964
1344
  end
965
1345
  else
966
- AVLNode.new(@item, left, right)
1346
+ derive(@item, left, right)
967
1347
  end
968
1348
  end
969
1349
 
970
- def direction(item, comparator)
971
- if comparator
972
- comparator.call(item, @item)
973
- else
974
- item <=> @item
975
- end
976
- end
977
- end
978
-
979
- EmptyAVLNode = Object.new.tap do |e|
980
- def e.left; self; end
981
- def e.right; self; end
982
- def e.height; 0; end
983
- def e.size; 0; end
984
- def e.min; nil; end
985
- def e.max; nil; end
986
- def e.each; end
987
- def e.reverse_each; end
988
- def e.at(index); nil; end
989
- def e.insert(item, comparator); AVLNode.new(item, self, self); end
990
- def e.bulk_insert(items, comparator)
991
- items = items.to_a if !items.is_a?(Array)
992
- AVLNode.from_items(items.sort(&comparator), 0, items.size-1)
993
- end
994
- def e.bulk_delete(items, comparator); self; end
995
- def e.keep_only(items, comparator); self; end
996
- def e.delete(item, comparator); self; end
997
- def e.include?(item, comparator); false; end
998
- def e.prefix(item, comparator, inclusive); self; end
999
- def e.suffix(item, comparator, inclusive); self; end
1000
- def e.between(from, to, comparator); self; end
1001
- def e.each_greater(item, comparator, inclusive); end
1002
- def e.each_less(item, comparator, inclusive); end
1003
- def e.each_between(item, comparator, inclusive); end
1004
- def e.empty?; true; end
1005
- def e.slice(from, length); self; end
1006
- end.freeze
1350
+ def direction(item)
1351
+ @comparator.call(item, @item)
1352
+ end
1353
+
1354
+ # @private
1355
+ class Empty
1356
+ def initialize(comparator); @comparator = comparator; end
1357
+ def natural_order?; false; end
1358
+ def left; self; end
1359
+ def right; self; end
1360
+ def height; 0; end
1361
+ def size; 0; end
1362
+ def min; nil; end
1363
+ def max; nil; end
1364
+ def each; end
1365
+ def reverse_each; end
1366
+ def at(index); nil; end
1367
+ def insert(item)
1368
+ AVLNode.new(item, @comparator, self, self)
1369
+ end
1370
+ def bulk_insert(items)
1371
+ items = items.to_a if !items.is_a?(Array)
1372
+ AVLNode.from_items(items.sort(&@comparator), @comparator)
1373
+ end
1374
+ def bulk_delete(items); self; end
1375
+ def keep_only(items); self; end
1376
+ def delete(item); throw :not_present; end
1377
+ def include?(item); false; end
1378
+ def prefix(item, inclusive); self; end
1379
+ def suffix(item, inclusive); self; end
1380
+ def between(from, to); self; end
1381
+ def each_greater(item, inclusive); end
1382
+ def each_less(item, inclusive); end
1383
+ def each_between(item, inclusive); end
1384
+ def drop(n); self; end
1385
+ def take(n); self; end
1386
+ def empty?; true; end
1387
+ def slice(from, length); self; end
1388
+ end
1389
+ end
1390
+
1391
+ # @private
1392
+ # AVL node which does not use a comparator function; it keeps items sorted
1393
+ # in their natural order
1394
+ class PlainAVLNode < AVLNode
1395
+ def self.from_items(items, from = 0, to = items.size-1) # items must be sorted
1396
+ size = to - from + 1
1397
+ if size >= 3
1398
+ middle = (to + from) / 2
1399
+ PlainAVLNode.new(items[middle], PlainAVLNode.from_items(items, from, middle-1), PlainAVLNode.from_items(items, middle+1, to))
1400
+ elsif size == 2
1401
+ PlainAVLNode.new(items[from], PlainAVLNode::EmptyNode, PlainAVLNode.new(items[from+1], PlainAVLNode::EmptyNode, PlainAVLNode::EmptyNode))
1402
+ elsif size == 1
1403
+ PlainAVLNode.new(items[from], PlainAVLNode::EmptyNode, PlainAVLNode::EmptyNode)
1404
+ elsif size == 0
1405
+ PlainAVLNode::EmptyNode
1406
+ end
1407
+ end
1408
+
1409
+ def initialize(item, left, right)
1410
+ @item, @left, @right = item, left, right
1411
+ @height = ((right.height > left.height) ? right.height : left.height) + 1
1412
+ @size = right.size + left.size + 1
1413
+ end
1414
+ attr_reader :item, :left, :right, :height, :size
1415
+
1416
+ def from_items(items)
1417
+ PlainAVLNode.from_items(items.sort)
1418
+ end
1419
+
1420
+ def natural_order?
1421
+ true
1422
+ end
1423
+
1424
+ def clear
1425
+ PlainAVLNode::EmptyNode
1426
+ end
1427
+
1428
+ def derive(item, left, right)
1429
+ PlainAVLNode.new(item, left, right)
1430
+ end
1431
+
1432
+ def direction(item)
1433
+ item <=> @item
1434
+ end
1435
+
1436
+ # @private
1437
+ class Empty < AVLNode::Empty
1438
+ def initialize; end
1439
+ def natural_order?; true; end
1440
+ def insert(item)
1441
+ PlainAVLNode.new(item, self, self)
1442
+ end
1443
+ def bulk_insert(items)
1444
+ items = items.to_a if !items.is_a?(Array)
1445
+ PlainAVLNode.from_items(items.sort)
1446
+ end
1447
+ end
1448
+
1449
+ EmptyNode = PlainAVLNode::Empty.new
1450
+ end
1007
1451
  end
1008
1452
 
1009
- # The canonical empty `SortedSet`. Returned by `Hamster.sorted_set` and `SortedSet[]`
1453
+ # The canonical empty `SortedSet`. Returned by `SortedSet[]`
1010
1454
  # when invoked with no arguments; also returned by `SortedSet.empty`. Prefer using
1011
1455
  # this one rather than creating many empty sorted sets using `SortedSet.new`.
1012
1456
  #
1457
+ # @private
1013
1458
  EmptySortedSet = Hamster::SortedSet.empty
1014
- end
1459
+ end