immutable-ruby 0.0.1

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