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
@@ -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