immutable-ruby 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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