immutable-ruby 0.0.4 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (356) hide show
  1. checksums.yaml +4 -4
  2. data/lib/immutable/_core.rb +3067 -0
  3. data/lib/immutable/core_ext/enumerable.rb +1 -1
  4. data/lib/immutable/core_ext/io.rb +1 -1
  5. data/lib/immutable/core_ext.rb +2 -2
  6. data/lib/immutable/deque.rb +17 -17
  7. data/lib/immutable/enumerable.rb +10 -10
  8. data/lib/immutable/hash.rb +4 -941
  9. data/lib/immutable/list.rb +36 -36
  10. data/lib/immutable/nested.rb +8 -8
  11. data/lib/immutable/set.rb +3 -583
  12. data/lib/immutable/sorted_set.rb +29 -27
  13. data/lib/immutable/trie.rb +2 -2
  14. data/lib/immutable/vector.rb +3 -1549
  15. data/lib/immutable/version.rb +1 -1
  16. data/lib/immutable.rb +9 -9
  17. metadata +34 -696
  18. data/lib/immutable/core_ext/struct.rb +0 -9
  19. data/spec/fixtures/io_spec.txt +0 -3
  20. data/spec/lib/immutable/core_ext/array_spec.rb +0 -13
  21. data/spec/lib/immutable/core_ext/enumerable_spec.rb +0 -29
  22. data/spec/lib/immutable/core_ext/io_spec.rb +0 -28
  23. data/spec/lib/immutable/deque/clear_spec.rb +0 -33
  24. data/spec/lib/immutable/deque/construction_spec.rb +0 -29
  25. data/spec/lib/immutable/deque/copying_spec.rb +0 -19
  26. data/spec/lib/immutable/deque/dequeue_spec.rb +0 -34
  27. data/spec/lib/immutable/deque/empty_spec.rb +0 -39
  28. data/spec/lib/immutable/deque/enqueue_spec.rb +0 -27
  29. data/spec/lib/immutable/deque/first_spec.rb +0 -17
  30. data/spec/lib/immutable/deque/inspect_spec.rb +0 -23
  31. data/spec/lib/immutable/deque/last_spec.rb +0 -17
  32. data/spec/lib/immutable/deque/marshal_spec.rb +0 -33
  33. data/spec/lib/immutable/deque/new_spec.rb +0 -43
  34. data/spec/lib/immutable/deque/pop_spec.rb +0 -36
  35. data/spec/lib/immutable/deque/pretty_print_spec.rb +0 -23
  36. data/spec/lib/immutable/deque/push_spec.rb +0 -36
  37. data/spec/lib/immutable/deque/random_modification_spec.rb +0 -33
  38. data/spec/lib/immutable/deque/rotate_spec.rb +0 -68
  39. data/spec/lib/immutable/deque/shift_spec.rb +0 -29
  40. data/spec/lib/immutable/deque/size_spec.rb +0 -19
  41. data/spec/lib/immutable/deque/to_a_spec.rb +0 -26
  42. data/spec/lib/immutable/deque/to_ary_spec.rb +0 -35
  43. data/spec/lib/immutable/deque/to_list_spec.rb +0 -24
  44. data/spec/lib/immutable/deque/unshift_spec.rb +0 -30
  45. data/spec/lib/immutable/hash/all_spec.rb +0 -53
  46. data/spec/lib/immutable/hash/any_spec.rb +0 -53
  47. data/spec/lib/immutable/hash/assoc_spec.rb +0 -51
  48. data/spec/lib/immutable/hash/clear_spec.rb +0 -42
  49. data/spec/lib/immutable/hash/construction_spec.rb +0 -38
  50. data/spec/lib/immutable/hash/copying_spec.rb +0 -13
  51. data/spec/lib/immutable/hash/default_proc_spec.rb +0 -72
  52. data/spec/lib/immutable/hash/delete_spec.rb +0 -39
  53. data/spec/lib/immutable/hash/dig_spec.rb +0 -34
  54. data/spec/lib/immutable/hash/each_spec.rb +0 -77
  55. data/spec/lib/immutable/hash/each_with_index_spec.rb +0 -29
  56. data/spec/lib/immutable/hash/empty_spec.rb +0 -43
  57. data/spec/lib/immutable/hash/eql_spec.rb +0 -75
  58. data/spec/lib/immutable/hash/except_spec.rb +0 -42
  59. data/spec/lib/immutable/hash/fetch_spec.rb +0 -57
  60. data/spec/lib/immutable/hash/fetch_values_spec.rb +0 -22
  61. data/spec/lib/immutable/hash/find_spec.rb +0 -43
  62. data/spec/lib/immutable/hash/flat_map_spec.rb +0 -35
  63. data/spec/lib/immutable/hash/flatten_spec.rb +0 -98
  64. data/spec/lib/immutable/hash/get_spec.rb +0 -79
  65. data/spec/lib/immutable/hash/has_key_spec.rb +0 -31
  66. data/spec/lib/immutable/hash/has_value_spec.rb +0 -27
  67. data/spec/lib/immutable/hash/hash_spec.rb +0 -29
  68. data/spec/lib/immutable/hash/inspect_spec.rb +0 -30
  69. data/spec/lib/immutable/hash/invert_spec.rb +0 -30
  70. data/spec/lib/immutable/hash/key_spec.rb +0 -27
  71. data/spec/lib/immutable/hash/keys_spec.rb +0 -15
  72. data/spec/lib/immutable/hash/map_spec.rb +0 -45
  73. data/spec/lib/immutable/hash/marshal_spec.rb +0 -28
  74. data/spec/lib/immutable/hash/merge_spec.rb +0 -82
  75. data/spec/lib/immutable/hash/min_max_spec.rb +0 -45
  76. data/spec/lib/immutable/hash/new_spec.rb +0 -70
  77. data/spec/lib/immutable/hash/none_spec.rb +0 -48
  78. data/spec/lib/immutable/hash/partition_spec.rb +0 -35
  79. data/spec/lib/immutable/hash/pretty_print_spec.rb +0 -34
  80. data/spec/lib/immutable/hash/put_spec.rb +0 -111
  81. data/spec/lib/immutable/hash/reduce_spec.rb +0 -35
  82. data/spec/lib/immutable/hash/reject_spec.rb +0 -61
  83. data/spec/lib/immutable/hash/reverse_each_spec.rb +0 -27
  84. data/spec/lib/immutable/hash/sample_spec.rb +0 -13
  85. data/spec/lib/immutable/hash/select_spec.rb +0 -57
  86. data/spec/lib/immutable/hash/size_spec.rb +0 -51
  87. data/spec/lib/immutable/hash/slice_spec.rb +0 -44
  88. data/spec/lib/immutable/hash/sort_spec.rb +0 -26
  89. data/spec/lib/immutable/hash/store_spec.rb +0 -75
  90. data/spec/lib/immutable/hash/subset_spec.rb +0 -42
  91. data/spec/lib/immutable/hash/superset_spec.rb +0 -42
  92. data/spec/lib/immutable/hash/take_spec.rb +0 -35
  93. data/spec/lib/immutable/hash/to_a_spec.rb +0 -13
  94. data/spec/lib/immutable/hash/to_hash_spec.rb +0 -21
  95. data/spec/lib/immutable/hash/to_proc_spec.rb +0 -39
  96. data/spec/lib/immutable/hash/update_in_spec.rb +0 -79
  97. data/spec/lib/immutable/hash/values_at_spec.rb +0 -33
  98. data/spec/lib/immutable/hash/values_spec.rb +0 -23
  99. data/spec/lib/immutable/list/add_spec.rb +0 -25
  100. data/spec/lib/immutable/list/all_spec.rb +0 -57
  101. data/spec/lib/immutable/list/any_spec.rb +0 -49
  102. data/spec/lib/immutable/list/append_spec.rb +0 -38
  103. data/spec/lib/immutable/list/at_spec.rb +0 -29
  104. data/spec/lib/immutable/list/break_spec.rb +0 -69
  105. data/spec/lib/immutable/list/cadr_spec.rb +0 -38
  106. data/spec/lib/immutable/list/chunk_spec.rb +0 -28
  107. data/spec/lib/immutable/list/clear_spec.rb +0 -24
  108. data/spec/lib/immutable/list/combination_spec.rb +0 -33
  109. data/spec/lib/immutable/list/compact_spec.rb +0 -34
  110. data/spec/lib/immutable/list/compare_spec.rb +0 -30
  111. data/spec/lib/immutable/list/cons_spec.rb +0 -25
  112. data/spec/lib/immutable/list/construction_spec.rb +0 -110
  113. data/spec/lib/immutable/list/copying_spec.rb +0 -19
  114. data/spec/lib/immutable/list/count_spec.rb +0 -36
  115. data/spec/lib/immutable/list/cycle_spec.rb +0 -28
  116. data/spec/lib/immutable/list/delete_at_spec.rb +0 -18
  117. data/spec/lib/immutable/list/delete_spec.rb +0 -16
  118. data/spec/lib/immutable/list/drop_spec.rb +0 -30
  119. data/spec/lib/immutable/list/drop_while_spec.rb +0 -38
  120. data/spec/lib/immutable/list/each_slice_spec.rb +0 -51
  121. data/spec/lib/immutable/list/each_spec.rb +0 -40
  122. data/spec/lib/immutable/list/each_with_index_spec.rb +0 -28
  123. data/spec/lib/immutable/list/empty_spec.rb +0 -23
  124. data/spec/lib/immutable/list/eql_spec.rb +0 -61
  125. data/spec/lib/immutable/list/fill_spec.rb +0 -49
  126. data/spec/lib/immutable/list/find_all_spec.rb +0 -70
  127. data/spec/lib/immutable/list/find_index_spec.rb +0 -35
  128. data/spec/lib/immutable/list/find_spec.rb +0 -42
  129. data/spec/lib/immutable/list/flat_map_spec.rb +0 -51
  130. data/spec/lib/immutable/list/flatten_spec.rb +0 -30
  131. data/spec/lib/immutable/list/grep_spec.rb +0 -46
  132. data/spec/lib/immutable/list/group_by_spec.rb +0 -41
  133. data/spec/lib/immutable/list/hash_spec.rb +0 -21
  134. data/spec/lib/immutable/list/head_spec.rb +0 -19
  135. data/spec/lib/immutable/list/include_spec.rb +0 -35
  136. data/spec/lib/immutable/list/index_spec.rb +0 -37
  137. data/spec/lib/immutable/list/indices_spec.rb +0 -61
  138. data/spec/lib/immutable/list/init_spec.rb +0 -28
  139. data/spec/lib/immutable/list/inits_spec.rb +0 -28
  140. data/spec/lib/immutable/list/insert_spec.rb +0 -46
  141. data/spec/lib/immutable/list/inspect_spec.rb +0 -29
  142. data/spec/lib/immutable/list/intersperse_spec.rb +0 -28
  143. data/spec/lib/immutable/list/join_spec.rb +0 -63
  144. data/spec/lib/immutable/list/last_spec.rb +0 -23
  145. data/spec/lib/immutable/list/ltlt_spec.rb +0 -19
  146. data/spec/lib/immutable/list/map_spec.rb +0 -45
  147. data/spec/lib/immutable/list/maximum_spec.rb +0 -39
  148. data/spec/lib/immutable/list/merge_by_spec.rb +0 -51
  149. data/spec/lib/immutable/list/merge_spec.rb +0 -59
  150. data/spec/lib/immutable/list/minimum_spec.rb +0 -39
  151. data/spec/lib/immutable/list/multithreading_spec.rb +0 -47
  152. data/spec/lib/immutable/list/none_spec.rb +0 -47
  153. data/spec/lib/immutable/list/one_spec.rb +0 -49
  154. data/spec/lib/immutable/list/partition_spec.rb +0 -115
  155. data/spec/lib/immutable/list/permutation_spec.rb +0 -55
  156. data/spec/lib/immutable/list/pop_spec.rb +0 -25
  157. data/spec/lib/immutable/list/product_spec.rb +0 -23
  158. data/spec/lib/immutable/list/reduce_spec.rb +0 -53
  159. data/spec/lib/immutable/list/reject_spec.rb +0 -45
  160. data/spec/lib/immutable/list/reverse_spec.rb +0 -34
  161. data/spec/lib/immutable/list/rotate_spec.rb +0 -36
  162. data/spec/lib/immutable/list/sample_spec.rb +0 -13
  163. data/spec/lib/immutable/list/select_spec.rb +0 -70
  164. data/spec/lib/immutable/list/size_spec.rb +0 -25
  165. data/spec/lib/immutable/list/slice_spec.rb +0 -229
  166. data/spec/lib/immutable/list/sorting_spec.rb +0 -46
  167. data/spec/lib/immutable/list/span_spec.rb +0 -76
  168. data/spec/lib/immutable/list/split_at_spec.rb +0 -43
  169. data/spec/lib/immutable/list/subsequences_spec.rb +0 -23
  170. data/spec/lib/immutable/list/sum_spec.rb +0 -23
  171. data/spec/lib/immutable/list/tail_spec.rb +0 -30
  172. data/spec/lib/immutable/list/tails_spec.rb +0 -28
  173. data/spec/lib/immutable/list/take_spec.rb +0 -30
  174. data/spec/lib/immutable/list/take_while_spec.rb +0 -46
  175. data/spec/lib/immutable/list/to_a_spec.rb +0 -39
  176. data/spec/lib/immutable/list/to_ary_spec.rb +0 -41
  177. data/spec/lib/immutable/list/to_list_spec.rb +0 -19
  178. data/spec/lib/immutable/list/to_set_spec.rb +0 -17
  179. data/spec/lib/immutable/list/transpose_spec.rb +0 -19
  180. data/spec/lib/immutable/list/union_spec.rb +0 -31
  181. data/spec/lib/immutable/list/uniq_spec.rb +0 -35
  182. data/spec/lib/immutable/list/zip_spec.rb +0 -23
  183. data/spec/lib/immutable/nested/construction_spec.rb +0 -101
  184. data/spec/lib/immutable/set/add_spec.rb +0 -77
  185. data/spec/lib/immutable/set/all_spec.rb +0 -51
  186. data/spec/lib/immutable/set/any_spec.rb +0 -51
  187. data/spec/lib/immutable/set/clear_spec.rb +0 -33
  188. data/spec/lib/immutable/set/compact_spec.rb +0 -30
  189. data/spec/lib/immutable/set/construction_spec.rb +0 -18
  190. data/spec/lib/immutable/set/copying_spec.rb +0 -13
  191. data/spec/lib/immutable/set/count_spec.rb +0 -36
  192. data/spec/lib/immutable/set/delete_spec.rb +0 -71
  193. data/spec/lib/immutable/set/difference_spec.rb +0 -49
  194. data/spec/lib/immutable/set/disjoint_spec.rb +0 -25
  195. data/spec/lib/immutable/set/each_spec.rb +0 -45
  196. data/spec/lib/immutable/set/empty_spec.rb +0 -44
  197. data/spec/lib/immutable/set/eqeq_spec.rb +0 -103
  198. data/spec/lib/immutable/set/eql_spec.rb +0 -109
  199. data/spec/lib/immutable/set/exclusion_spec.rb +0 -47
  200. data/spec/lib/immutable/set/find_spec.rb +0 -35
  201. data/spec/lib/immutable/set/first_spec.rb +0 -28
  202. data/spec/lib/immutable/set/flatten_spec.rb +0 -46
  203. data/spec/lib/immutable/set/grep_spec.rb +0 -57
  204. data/spec/lib/immutable/set/grep_v_spec.rb +0 -59
  205. data/spec/lib/immutable/set/group_by_spec.rb +0 -59
  206. data/spec/lib/immutable/set/hash_spec.rb +0 -22
  207. data/spec/lib/immutable/set/include_spec.rb +0 -60
  208. data/spec/lib/immutable/set/inspect_spec.rb +0 -47
  209. data/spec/lib/immutable/set/intersect_spec.rb +0 -25
  210. data/spec/lib/immutable/set/intersection_spec.rb +0 -52
  211. data/spec/lib/immutable/set/join_spec.rb +0 -64
  212. data/spec/lib/immutable/set/map_spec.rb +0 -59
  213. data/spec/lib/immutable/set/marshal_spec.rb +0 -28
  214. data/spec/lib/immutable/set/maximum_spec.rb +0 -36
  215. data/spec/lib/immutable/set/minimum_spec.rb +0 -36
  216. data/spec/lib/immutable/set/new_spec.rb +0 -53
  217. data/spec/lib/immutable/set/none_spec.rb +0 -47
  218. data/spec/lib/immutable/set/one_spec.rb +0 -47
  219. data/spec/lib/immutable/set/partition_spec.rb +0 -52
  220. data/spec/lib/immutable/set/product_spec.rb +0 -23
  221. data/spec/lib/immutable/set/reduce_spec.rb +0 -55
  222. data/spec/lib/immutable/set/reject_spec.rb +0 -50
  223. data/spec/lib/immutable/set/reverse_each_spec.rb +0 -38
  224. data/spec/lib/immutable/set/sample_spec.rb +0 -13
  225. data/spec/lib/immutable/set/select_spec.rb +0 -73
  226. data/spec/lib/immutable/set/size_spec.rb +0 -17
  227. data/spec/lib/immutable/set/sorting_spec.rb +0 -65
  228. data/spec/lib/immutable/set/subset_spec.rb +0 -51
  229. data/spec/lib/immutable/set/sum_spec.rb +0 -23
  230. data/spec/lib/immutable/set/superset_spec.rb +0 -51
  231. data/spec/lib/immutable/set/to_a_spec.rb +0 -30
  232. data/spec/lib/immutable/set/to_list_spec.rb +0 -35
  233. data/spec/lib/immutable/set/to_set_spec.rb +0 -19
  234. data/spec/lib/immutable/set/union_spec.rb +0 -63
  235. data/spec/lib/immutable/sorted_set/above_spec.rb +0 -51
  236. data/spec/lib/immutable/sorted_set/add_spec.rb +0 -62
  237. data/spec/lib/immutable/sorted_set/at_spec.rb +0 -24
  238. data/spec/lib/immutable/sorted_set/below_spec.rb +0 -51
  239. data/spec/lib/immutable/sorted_set/between_spec.rb +0 -51
  240. data/spec/lib/immutable/sorted_set/clear_spec.rb +0 -43
  241. data/spec/lib/immutable/sorted_set/copying_spec.rb +0 -20
  242. data/spec/lib/immutable/sorted_set/delete_at_spec.rb +0 -18
  243. data/spec/lib/immutable/sorted_set/delete_spec.rb +0 -89
  244. data/spec/lib/immutable/sorted_set/difference_spec.rb +0 -22
  245. data/spec/lib/immutable/sorted_set/disjoint_spec.rb +0 -25
  246. data/spec/lib/immutable/sorted_set/drop_spec.rb +0 -55
  247. data/spec/lib/immutable/sorted_set/drop_while_spec.rb +0 -34
  248. data/spec/lib/immutable/sorted_set/each_spec.rb +0 -28
  249. data/spec/lib/immutable/sorted_set/empty_spec.rb +0 -34
  250. data/spec/lib/immutable/sorted_set/eql_spec.rb +0 -120
  251. data/spec/lib/immutable/sorted_set/exclusion_spec.rb +0 -22
  252. data/spec/lib/immutable/sorted_set/fetch_spec.rb +0 -64
  253. data/spec/lib/immutable/sorted_set/find_index_spec.rb +0 -40
  254. data/spec/lib/immutable/sorted_set/first_spec.rb +0 -18
  255. data/spec/lib/immutable/sorted_set/from_spec.rb +0 -51
  256. data/spec/lib/immutable/sorted_set/group_by_spec.rb +0 -57
  257. data/spec/lib/immutable/sorted_set/include_spec.rb +0 -23
  258. data/spec/lib/immutable/sorted_set/inspect_spec.rb +0 -37
  259. data/spec/lib/immutable/sorted_set/intersect_spec.rb +0 -25
  260. data/spec/lib/immutable/sorted_set/intersection_spec.rb +0 -28
  261. data/spec/lib/immutable/sorted_set/last_spec.rb +0 -36
  262. data/spec/lib/immutable/sorted_set/map_spec.rb +0 -51
  263. data/spec/lib/immutable/sorted_set/marshal_spec.rb +0 -36
  264. data/spec/lib/immutable/sorted_set/maximum_spec.rb +0 -36
  265. data/spec/lib/immutable/sorted_set/minimum_spec.rb +0 -19
  266. data/spec/lib/immutable/sorted_set/new_spec.rb +0 -137
  267. data/spec/lib/immutable/sorted_set/reverse_each_spec.rb +0 -28
  268. data/spec/lib/immutable/sorted_set/sample_spec.rb +0 -13
  269. data/spec/lib/immutable/sorted_set/select_spec.rb +0 -61
  270. data/spec/lib/immutable/sorted_set/size_spec.rb +0 -17
  271. data/spec/lib/immutable/sorted_set/slice_spec.rb +0 -256
  272. data/spec/lib/immutable/sorted_set/sorting_spec.rb +0 -56
  273. data/spec/lib/immutable/sorted_set/subset_spec.rb +0 -47
  274. data/spec/lib/immutable/sorted_set/superset_spec.rb +0 -47
  275. data/spec/lib/immutable/sorted_set/take_spec.rb +0 -54
  276. data/spec/lib/immutable/sorted_set/take_while_spec.rb +0 -33
  277. data/spec/lib/immutable/sorted_set/to_set_spec.rb +0 -17
  278. data/spec/lib/immutable/sorted_set/union_spec.rb +0 -58
  279. data/spec/lib/immutable/sorted_set/up_to_spec.rb +0 -52
  280. data/spec/lib/immutable/sorted_set/util_spec.rb +0 -48
  281. data/spec/lib/immutable/sorted_set/values_at_spec.rb +0 -33
  282. data/spec/lib/immutable/vector/add_spec.rb +0 -67
  283. data/spec/lib/immutable/vector/any_spec.rb +0 -69
  284. data/spec/lib/immutable/vector/assoc_spec.rb +0 -45
  285. data/spec/lib/immutable/vector/bsearch_spec.rb +0 -65
  286. data/spec/lib/immutable/vector/clear_spec.rb +0 -33
  287. data/spec/lib/immutable/vector/combination_spec.rb +0 -81
  288. data/spec/lib/immutable/vector/compact_spec.rb +0 -29
  289. data/spec/lib/immutable/vector/compare_spec.rb +0 -31
  290. data/spec/lib/immutable/vector/concat_spec.rb +0 -34
  291. data/spec/lib/immutable/vector/copying_spec.rb +0 -20
  292. data/spec/lib/immutable/vector/count_spec.rb +0 -17
  293. data/spec/lib/immutable/vector/delete_at_spec.rb +0 -53
  294. data/spec/lib/immutable/vector/delete_spec.rb +0 -30
  295. data/spec/lib/immutable/vector/dig_spec.rb +0 -30
  296. data/spec/lib/immutable/vector/drop_spec.rb +0 -41
  297. data/spec/lib/immutable/vector/drop_while_spec.rb +0 -54
  298. data/spec/lib/immutable/vector/each_index_spec.rb +0 -40
  299. data/spec/lib/immutable/vector/each_spec.rb +0 -44
  300. data/spec/lib/immutable/vector/each_with_index_spec.rb +0 -39
  301. data/spec/lib/immutable/vector/empty_spec.rb +0 -41
  302. data/spec/lib/immutable/vector/eql_spec.rb +0 -76
  303. data/spec/lib/immutable/vector/fetch_spec.rb +0 -64
  304. data/spec/lib/immutable/vector/fill_spec.rb +0 -88
  305. data/spec/lib/immutable/vector/first_spec.rb +0 -18
  306. data/spec/lib/immutable/vector/flat_map_spec.rb +0 -50
  307. data/spec/lib/immutable/vector/flatten_spec.rb +0 -58
  308. data/spec/lib/immutable/vector/get_spec.rb +0 -74
  309. data/spec/lib/immutable/vector/group_by_spec.rb +0 -57
  310. data/spec/lib/immutable/vector/include_spec.rb +0 -30
  311. data/spec/lib/immutable/vector/insert_spec.rb +0 -68
  312. data/spec/lib/immutable/vector/inspect_spec.rb +0 -49
  313. data/spec/lib/immutable/vector/join_spec.rb +0 -58
  314. data/spec/lib/immutable/vector/last_spec.rb +0 -45
  315. data/spec/lib/immutable/vector/length_spec.rb +0 -45
  316. data/spec/lib/immutable/vector/ltlt_spec.rb +0 -65
  317. data/spec/lib/immutable/vector/map_spec.rb +0 -51
  318. data/spec/lib/immutable/vector/marshal_spec.rb +0 -31
  319. data/spec/lib/immutable/vector/maximum_spec.rb +0 -33
  320. data/spec/lib/immutable/vector/minimum_spec.rb +0 -33
  321. data/spec/lib/immutable/vector/multiply_spec.rb +0 -47
  322. data/spec/lib/immutable/vector/new_spec.rb +0 -50
  323. data/spec/lib/immutable/vector/partition_spec.rb +0 -52
  324. data/spec/lib/immutable/vector/permutation_spec.rb +0 -91
  325. data/spec/lib/immutable/vector/pop_spec.rb +0 -26
  326. data/spec/lib/immutable/vector/product_spec.rb +0 -70
  327. data/spec/lib/immutable/vector/reduce_spec.rb +0 -55
  328. data/spec/lib/immutable/vector/reject_spec.rb +0 -43
  329. data/spec/lib/immutable/vector/repeated_combination_spec.rb +0 -77
  330. data/spec/lib/immutable/vector/repeated_permutation_spec.rb +0 -93
  331. data/spec/lib/immutable/vector/reverse_each_spec.rb +0 -31
  332. data/spec/lib/immutable/vector/reverse_spec.rb +0 -21
  333. data/spec/lib/immutable/vector/rindex_spec.rb +0 -36
  334. data/spec/lib/immutable/vector/rotate_spec.rb +0 -73
  335. data/spec/lib/immutable/vector/sample_spec.rb +0 -13
  336. data/spec/lib/immutable/vector/select_spec.rb +0 -63
  337. data/spec/lib/immutable/vector/set_spec.rb +0 -174
  338. data/spec/lib/immutable/vector/shift_spec.rb +0 -27
  339. data/spec/lib/immutable/vector/shuffle_spec.rb +0 -43
  340. data/spec/lib/immutable/vector/slice_spec.rb +0 -240
  341. data/spec/lib/immutable/vector/sorting_spec.rb +0 -56
  342. data/spec/lib/immutable/vector/sum_spec.rb +0 -17
  343. data/spec/lib/immutable/vector/take_spec.rb +0 -42
  344. data/spec/lib/immutable/vector/take_while_spec.rb +0 -34
  345. data/spec/lib/immutable/vector/to_a_spec.rb +0 -41
  346. data/spec/lib/immutable/vector/to_ary_spec.rb +0 -34
  347. data/spec/lib/immutable/vector/to_list_spec.rb +0 -30
  348. data/spec/lib/immutable/vector/to_set_spec.rb +0 -21
  349. data/spec/lib/immutable/vector/transpose_spec.rb +0 -48
  350. data/spec/lib/immutable/vector/uniq_spec.rb +0 -76
  351. data/spec/lib/immutable/vector/unshift_spec.rb +0 -28
  352. data/spec/lib/immutable/vector/update_in_spec.rb +0 -82
  353. data/spec/lib/immutable/vector/values_at_spec.rb +0 -33
  354. data/spec/lib/immutable/vector/zip_spec.rb +0 -57
  355. data/spec/lib/load_spec.rb +0 -42
  356. data/spec/spec_helper.rb +0 -96
@@ -0,0 +1,3067 @@
1
+ require 'immutable/undefined'
2
+ require 'immutable/enumerable'
3
+ require 'immutable/trie'
4
+ require 'immutable/sorted_set'
5
+ require 'set'
6
+
7
+ module Immutable
8
+
9
+ # An `Immutable::Hash` maps a set of unique keys to corresponding values, much
10
+ # like a dictionary maps from words to definitions. Given a key, it can store
11
+ # and retrieve an associated value in constant time. If an existing key is
12
+ # stored again, the new value will replace the old. It behaves much like
13
+ # Ruby's built-in Hash, which we will call RubyHash for clarity. Like
14
+ # RubyHash, two keys that are `#eql?` to each other and have the same
15
+ # `#hash` are considered identical in an `Immutable::Hash`.
16
+ #
17
+ # An `Immutable::Hash` can be created in a couple of ways:
18
+ #
19
+ # Immutable::Hash.new(font_size: 10, font_family: 'Arial')
20
+ # Immutable::Hash[first_name: 'John', last_name: 'Smith']
21
+ #
22
+ # Any `Enumerable` object which yields two-element `[key, value]` arrays
23
+ # can be used to initialize an `Immutable::Hash`:
24
+ #
25
+ # Immutable::Hash.new([[:first_name, 'John'], [:last_name, 'Smith']])
26
+ #
27
+ # Key/value pairs can be added using {#put}. A new hash is returned and the
28
+ # existing one is left unchanged:
29
+ #
30
+ # hash = Immutable::Hash[a: 100, b: 200]
31
+ # hash.put(:c, 500) # => Immutable::Hash[:a => 100, :b => 200, :c => 500]
32
+ # hash # => Immutable::Hash[:a => 100, :b => 200]
33
+ #
34
+ # {#put} can also take a block, which is used to calculate the value to be
35
+ # stored.
36
+ #
37
+ # hash.put(:a) { |current| current + 200 } # => Immutable::Hash[:a => 300, :b => 200]
38
+ #
39
+ # Since it is immutable, all methods which you might expect to "modify" a
40
+ # `Immutable::Hash` actually return a new hash and leave the existing one
41
+ # unchanged. This means that the `hash[key] = value` syntax from RubyHash
42
+ # *cannot* be used with `Immutable::Hash`.
43
+ #
44
+ # Nested data structures can easily be updated using {#update_in}:
45
+ #
46
+ # hash = Immutable::Hash["a" => Immutable::Vector[Immutable::Hash["c" => 42]]]
47
+ # hash.update_in("a", 0, "c") { |value| value + 5 }
48
+ # # => Immutable::Hash["a" => Immutable::Hash["b" => Immutable::Hash["c" => 47]]]
49
+ #
50
+ # While an `Immutable::Hash` can iterate over its keys or values, it does not
51
+ # guarantee any specific iteration order (unlike RubyHash). Methods like
52
+ # {#flatten} do not guarantee the order of returned key/value pairs.
53
+ #
54
+ # Like RubyHash, an `Immutable::Hash` can have a default block which is used
55
+ # when looking up a key that does not exist. Unlike RubyHash, the default
56
+ # block will only be passed the missing key, without the hash itself:
57
+ #
58
+ # hash = Immutable::Hash.new { |missing_key| missing_key * 10 }
59
+ # hash[5] # => 50
60
+ class Hash
61
+ include Immutable::Enumerable
62
+
63
+ class << self
64
+ # Create a new `Hash` populated with the given key/value pairs.
65
+ #
66
+ # @example
67
+ # Immutable::Hash["A" => 1, "B" => 2] # => Immutable::Hash["A" => 1, "B" => 2]
68
+ # Immutable::Hash[["A", 1], ["B", 2]] # => Immutable::Hash["A" => 1, "B" => 2]
69
+ #
70
+ # @param pairs [::Enumerable] initial content of hash. An empty hash is returned if not provided.
71
+ # @return [Hash]
72
+ def [](pairs = nil)
73
+ (pairs.nil? || pairs.empty?) ? empty : new(pairs)
74
+ end
75
+
76
+ # Return an empty `Hash`. If used on a subclass, returns an empty instance
77
+ # of that class.
78
+ #
79
+ # @return [Hash]
80
+ def empty
81
+ @empty ||= new
82
+ end
83
+
84
+ # "Raw" allocation of a new `Hash`. Used internally to create a new
85
+ # instance quickly after obtaining a modified {Trie}.
86
+ #
87
+ # @return [Hash]
88
+ # @private
89
+ def alloc(trie = EmptyTrie, block = nil)
90
+ obj = allocate
91
+ obj.instance_variable_set(:@trie, trie)
92
+ obj.instance_variable_set(:@default, block)
93
+ obj.freeze
94
+ end
95
+ end
96
+
97
+ # @param pairs [::Enumerable] initial content of hash. An empty hash is returned if not provided.
98
+ # @yield [key] Optional _default block_ to be stored and used to calculate the default value of a missing key. It will not be yielded during this method. It will not be preserved when marshalling.
99
+ # @yieldparam key Key that was not present in the hash.
100
+ def initialize(pairs = nil, &block)
101
+ @trie = pairs ? Trie[pairs] : EmptyTrie
102
+ @default = block
103
+ freeze
104
+ end
105
+
106
+ # Return the default block if there is one. Otherwise, return `nil`.
107
+ #
108
+ # @return [Proc]
109
+ def default_proc
110
+ @default
111
+ end
112
+
113
+ # Return the number of key/value pairs in this `Hash`.
114
+ #
115
+ # @example
116
+ # Immutable::Hash["A" => 1, "B" => 2, "C" => 3].size # => 3
117
+ #
118
+ # @return [Integer]
119
+ def size
120
+ @trie.size
121
+ end
122
+ alias length size
123
+
124
+ # Return `true` if this `Hash` contains no key/value pairs.
125
+ #
126
+ # @return [Boolean]
127
+ def empty?
128
+ @trie.empty?
129
+ end
130
+
131
+ # Return `true` if the given key object is present in this `Hash`. More precisely,
132
+ # return `true` if a key with the same `#hash` code, and which is also `#eql?`
133
+ # to the given key object is present.
134
+ #
135
+ # @example
136
+ # Immutable::Hash["A" => 1, "B" => 2, "C" => 3].key?("B") # => true
137
+ #
138
+ # @param key [Object] The key to check for
139
+ # @return [Boolean]
140
+ def key?(key)
141
+ @trie.key?(key)
142
+ end
143
+ alias has_key? key?
144
+ alias include? key?
145
+ alias member? key?
146
+
147
+ # Return `true` if this `Hash` has one or more keys which map to the provided value.
148
+ #
149
+ # @example
150
+ # Immutable::Hash["A" => 1, "B" => 2, "C" => 3].value?(2) # => true
151
+ #
152
+ # @param value [Object] The value to check for
153
+ # @return [Boolean]
154
+ def value?(value)
155
+ each { |k,v| return true if value == v }
156
+ false
157
+ end
158
+ alias has_value? value?
159
+
160
+ # Retrieve the value corresponding to the provided key object. If not found, and
161
+ # this `Hash` has a default block, the default block is called to provide the
162
+ # value. Otherwise, return `nil`.
163
+ #
164
+ # @example
165
+ # h = Immutable::Hash["A" => 1, "B" => 2, "C" => 3]
166
+ # h["B"] # => 2
167
+ # h.get("B") # => 2
168
+ # h.get("Elephant") # => nil
169
+ #
170
+ # # Immutable Hash with a default proc:
171
+ # h = Immutable::Hash.new("A" => 1, "B" => 2, "C" => 3) { |key| key.size }
172
+ # h.get("B") # => 2
173
+ # h.get("Elephant") # => 8
174
+ #
175
+ # @param key [Object] The key to look up
176
+ # @return [Object]
177
+ def get(key)
178
+ entry = @trie.get(key)
179
+ if entry
180
+ entry[1]
181
+ elsif @default
182
+ @default.call(key)
183
+ end
184
+ end
185
+ alias [] get
186
+
187
+ # Retrieve the value corresponding to the given key object, or use the provided
188
+ # default value or block, or otherwise raise a `KeyError`.
189
+ #
190
+ # @overload fetch(key)
191
+ # Retrieve the value corresponding to the given key, or raise a `KeyError`
192
+ # if it is not found.
193
+ # @param key [Object] The key to look up
194
+ # @overload fetch(key) { |key| ... }
195
+ # Retrieve the value corresponding to the given key, or call the optional
196
+ # code block (with the missing key) and get its return value.
197
+ # @yield [key] The key which was not found
198
+ # @yieldreturn [Object] Object to return since the key was not found
199
+ # @param key [Object] The key to look up
200
+ # @overload fetch(key, default)
201
+ # Retrieve the value corresponding to the given key, or else return
202
+ # the provided `default` value.
203
+ # @param key [Object] The key to look up
204
+ # @param default [Object] Object to return if the key is not found
205
+ #
206
+ # @example
207
+ # h = Immutable::Hash["A" => 1, "B" => 2, "C" => 3]
208
+ # h.fetch("B") # => 2
209
+ # h.fetch("Elephant") # => KeyError: key not found: "Elephant"
210
+ #
211
+ # # with a default value:
212
+ # h.fetch("B", 99) # => 2
213
+ # h.fetch("Elephant", 99) # => 99
214
+ #
215
+ # # with a block:
216
+ # h.fetch("B") { |key| key.size } # => 2
217
+ # h.fetch("Elephant") { |key| key.size } # => 8
218
+ #
219
+ # @return [Object]
220
+ def fetch(key, default = Undefined)
221
+ entry = @trie.get(key)
222
+ if entry
223
+ entry[1]
224
+ elsif block_given?
225
+ yield(key)
226
+ elsif default != Undefined
227
+ default
228
+ else
229
+ raise KeyError, "key not found: #{key.inspect}"
230
+ end
231
+ end
232
+
233
+ # Return a new `Hash` with the existing key/value associations, plus an association
234
+ # between the provided key and value. If an equivalent key is already present, its
235
+ # associated value will be replaced with the provided one.
236
+ #
237
+ # If the `value` argument is missing, but an optional code block is provided,
238
+ # it will be passed the existing value (or `nil` if there is none) and what it
239
+ # returns will replace the existing value. This is useful for "transforming"
240
+ # the value associated with a certain key.
241
+ #
242
+ # Avoid mutating objects which are used as keys. `String`s are an exception:
243
+ # unfrozen `String`s which are used as keys are internally duplicated and
244
+ # frozen. This matches RubyHash's behaviour.
245
+ #
246
+ # @example
247
+ # h = Immutable::Hash["A" => 1, "B" => 2]
248
+ # h.put("C", 3)
249
+ # # => Immutable::Hash["A" => 1, "B" => 2, "C" => 3]
250
+ # h.put("B") { |value| value * 10 }
251
+ # # => Immutable::Hash["A" => 1, "B" => 20]
252
+ #
253
+ # @param key [Object] The key to store
254
+ # @param value [Object] The value to associate it with
255
+ # @yield [value] The previously stored value, or `nil` if none.
256
+ # @yieldreturn [Object] The new value to store
257
+ # @return [Hash]
258
+ def put(key, value = yield(get(key)))
259
+ new_trie = @trie.put(key, value)
260
+ if new_trie.equal?(@trie)
261
+ self
262
+ else
263
+ self.class.alloc(new_trie, @default)
264
+ end
265
+ end
266
+
267
+ # @private
268
+ # @raise NoMethodError
269
+ def []=(*)
270
+ raise NoMethodError, "Immutable::Hash doesn't support `[]='; use `put' instead"
271
+ end
272
+
273
+ # Return a new `Hash` with a deeply nested value modified to the result of
274
+ # the given code block. When traversing the nested `Hash`es and `Vector`s,
275
+ # non-existing keys are created with empty `Hash` values.
276
+ #
277
+ # The code block receives the existing value of the deeply nested key (or
278
+ # `nil` if it doesn't exist). This is useful for "transforming" the value
279
+ # associated with a certain key.
280
+ #
281
+ # Note that the original `Hash` and sub-`Hash`es and sub-`Vector`s are left
282
+ # unmodified; new data structure copies are created along the path wherever
283
+ # needed.
284
+ #
285
+ # @example
286
+ # hash = Immutable::Hash["a" => Immutable::Hash["b" => Immutable::Hash["c" => 42]]]
287
+ # hash.update_in("a", "b", "c") { |value| value + 5 }
288
+ # # => Immutable::Hash["a" => Immutable::Hash["b" => Immutable::Hash["c" => 47]]]
289
+ #
290
+ # @param key_path [::Array<Object>] List of keys which form the path to the key to be modified
291
+ # @yield [value] The previously stored value
292
+ # @yieldreturn [Object] The new value to store
293
+ # @return [Hash]
294
+ def update_in(*key_path, &block)
295
+ if key_path.empty?
296
+ raise ArgumentError, 'must have at least one key in path'
297
+ end
298
+ key = key_path[0]
299
+ if key_path.size == 1
300
+ new_value = block.call(get(key))
301
+ else
302
+ value = fetch(key, EmptyHash)
303
+ new_value = value.update_in(*key_path[1..-1], &block)
304
+ end
305
+ put(key, new_value)
306
+ end
307
+
308
+ # An alias for {#put} to match RubyHash's API. Does not support {#put}'s
309
+ # block form.
310
+ #
311
+ # @see #put
312
+ # @param key [Object] The key to store
313
+ # @param value [Object] The value to associate it with
314
+ # @return [Hash]
315
+ def store(key, value)
316
+ put(key, value)
317
+ end
318
+
319
+ # Return a new `Hash` with `key` removed. If `key` is not present, return
320
+ # `self`.
321
+ #
322
+ # @example
323
+ # Immutable::Hash["A" => 1, "B" => 2, "C" => 3].delete("B")
324
+ # # => Immutable::Hash["A" => 1, "C" => 3]
325
+ #
326
+ # @param key [Object] The key to remove
327
+ # @return [Hash]
328
+ def delete(key)
329
+ derive_new_hash(@trie.delete(key))
330
+ end
331
+
332
+ # Call the block once for each key/value pair in this `Hash`, passing the key/value
333
+ # pair as parameters. No specific iteration order is guaranteed, though the order will
334
+ # be stable for any particular `Hash`.
335
+ #
336
+ # @example
337
+ # Immutable::Hash["A" => 1, "B" => 2, "C" => 3].each { |k, v| puts "k=#{k} v=#{v}" }
338
+ #
339
+ # k=A v=1
340
+ # k=C v=3
341
+ # k=B v=2
342
+ # # => Immutable::Hash["A" => 1, "B" => 2, "C" => 3]
343
+ #
344
+ # @yield [key, value] Once for each key/value pair.
345
+ # @return [self]
346
+ def each(&block)
347
+ return to_enum if not block_given?
348
+ @trie.each(&block)
349
+ self
350
+ end
351
+ alias each_pair each
352
+
353
+ # Call the block once for each key/value pair in this `Hash`, passing the key/value
354
+ # pair as parameters. Iteration order will be the opposite of {#each}.
355
+ #
356
+ # @example
357
+ # Immutable::Hash["A" => 1, "B" => 2, "C" => 3].reverse_each { |k, v| puts "k=#{k} v=#{v}" }
358
+ #
359
+ # k=B v=2
360
+ # k=C v=3
361
+ # k=A v=1
362
+ # # => Immutable::Hash["A" => 1, "B" => 2, "C" => 3]
363
+ #
364
+ # @yield [key, value] Once for each key/value pair.
365
+ # @return [self]
366
+ def reverse_each(&block)
367
+ return enum_for(:reverse_each) if not block_given?
368
+ @trie.reverse_each(&block)
369
+ self
370
+ end
371
+
372
+ # Call the block once for each key/value pair in this `Hash`, passing the key as a
373
+ # parameter. Ordering guarantees are the same as {#each}.
374
+ #
375
+ # @example
376
+ # Immutable::Hash["A" => 1, "B" => 2, "C" => 3].each_key { |k| puts "k=#{k}" }
377
+ #
378
+ # k=A
379
+ # k=C
380
+ # k=B
381
+ # # => Immutable::Hash["A" => 1, "B" => 2, "C" => 3]
382
+ #
383
+ # @yield [key] Once for each key/value pair.
384
+ # @return [self]
385
+ def each_key
386
+ return enum_for(:each_key) if not block_given?
387
+ @trie.each { |k,v| yield k }
388
+ self
389
+ end
390
+
391
+ # Call the block once for each key/value pair in this `Hash`, passing the value as a
392
+ # parameter. Ordering guarantees are the same as {#each}.
393
+ #
394
+ # @example
395
+ # Immutable::Hash["A" => 1, "B" => 2, "C" => 3].each_value { |v| puts "v=#{v}" }
396
+ #
397
+ # v=1
398
+ # v=3
399
+ # v=2
400
+ # # => Immutable::Hash["A" => 1, "B" => 2, "C" => 3]
401
+ #
402
+ # @yield [value] Once for each key/value pair.
403
+ # @return [self]
404
+ def each_value
405
+ return enum_for(:each_value) if not block_given?
406
+ @trie.each { |k,v| yield v }
407
+ self
408
+ end
409
+
410
+ # Call the block once for each key/value pair in this `Hash`, passing the key/value
411
+ # pair as parameters. The block should return a `[key, value]` array each time.
412
+ # All the returned `[key, value]` arrays will be gathered into a new `Hash`.
413
+ #
414
+ # @example
415
+ # h = Immutable::Hash["A" => 1, "B" => 2, "C" => 3]
416
+ # h.map { |k, v| ["new-#{k}", v * v] }
417
+ # # => Hash["new-C" => 9, "new-B" => 4, "new-A" => 1]
418
+ #
419
+ # @yield [key, value] Once for each key/value pair.
420
+ # @return [Hash]
421
+ def map
422
+ return enum_for(:map) unless block_given?
423
+ return self if empty?
424
+ self.class.new(super, &@default)
425
+ end
426
+ alias collect map
427
+
428
+ # Return a new `Hash` with all the key/value pairs for which the block returns true.
429
+ #
430
+ # @example
431
+ # h = Immutable::Hash["A" => 1, "B" => 2, "C" => 3]
432
+ # h.select { |k, v| v >= 2 }
433
+ # # => Immutable::Hash["B" => 2, "C" => 3]
434
+ #
435
+ # @yield [key, value] Once for each key/value pair.
436
+ # @yieldreturn Truthy if this pair should be present in the new `Hash`.
437
+ # @return [Hash]
438
+ def select(&block)
439
+ return enum_for(:select) unless block_given?
440
+ derive_new_hash(@trie.select(&block))
441
+ end
442
+ alias find_all select
443
+ alias keep_if select
444
+
445
+ # Yield `[key, value]` pairs until one is found for which the block returns true.
446
+ # Return that `[key, value]` pair. If the block never returns true, return `nil`.
447
+ #
448
+ # @example
449
+ # h = Immutable::Hash["A" => 1, "B" => 2, "C" => 3]
450
+ # h.find { |k, v| v.even? }
451
+ # # => ["B", 2]
452
+ #
453
+ # @return [Array]
454
+ # @yield [key, value] At most once for each key/value pair, until the block returns `true`.
455
+ # @yieldreturn Truthy to halt iteration and return the yielded key/value pair.
456
+ def find
457
+ return enum_for(:find) unless block_given?
458
+ each { |entry| return entry if yield entry }
459
+ nil
460
+ end
461
+ alias detect find
462
+
463
+ # Return a new `Hash` containing all the key/value pairs from this `Hash` and
464
+ # `other`. If no block is provided, the value for entries with colliding keys
465
+ # will be that from `other`. Otherwise, the value for each duplicate key is
466
+ # determined by calling the block.
467
+ #
468
+ # `other` can be an `Immutable::Hash`, a built-in Ruby `Hash`, or any `Enumerable`
469
+ # object which yields `[key, value]` pairs.
470
+ #
471
+ # @example
472
+ # h1 = Immutable::Hash["A" => 1, "B" => 2, "C" => 3]
473
+ # h2 = Immutable::Hash["C" => 70, "D" => 80]
474
+ # h1.merge(h2)
475
+ # # => Immutable::Hash["C" => 70, "A" => 1, "D" => 80, "B" => 2]
476
+ # h1.merge(h2) { |key, v1, v2| v1 + v2 }
477
+ # # => Immutable::Hash["C" => 73, "A" => 1, "D" => 80, "B" => 2]
478
+ #
479
+ # @param other [::Enumerable] The collection to merge with
480
+ # @yieldparam key [Object] The key which was present in both collections
481
+ # @yieldparam my_value [Object] The associated value from this `Hash`
482
+ # @yieldparam other_value [Object] The associated value from the other collection
483
+ # @yieldreturn [Object] The value to associate this key with in the new `Hash`
484
+ # @return [Hash]
485
+ def merge(other)
486
+ trie = if block_given?
487
+ other.reduce(@trie) do |trie, (key, value)|
488
+ if (entry = trie.get(key))
489
+ trie.put(key, yield(key, entry[1], value))
490
+ else
491
+ trie.put(key, value)
492
+ end
493
+ end
494
+ else
495
+ @trie.bulk_put(other)
496
+ end
497
+
498
+ derive_new_hash(trie)
499
+ end
500
+
501
+ # Retrieve the value corresponding to the given key object, or use the provided
502
+ # default value or block, or otherwise raise a `KeyError`.
503
+ #
504
+ # @overload fetch(key)
505
+ # Retrieve the value corresponding to the given key, or raise a `KeyError`
506
+ # if it is not found.
507
+ # @param key [Object] The key to look up
508
+ # @overload fetch(key) { |key| ... }
509
+
510
+ # Return a sorted {Vector} which contains all the `[key, value]` pairs in
511
+ # this `Hash` as two-element `Array`s.
512
+ #
513
+ # @overload sort
514
+ # Uses `#<=>` to determine sorted order.
515
+ # @overload sort { |(k1, v1), (k2, v2)| ... }
516
+ # Uses the block as a comparator to determine sorted order.
517
+ #
518
+ # @example
519
+ # h = Immutable::Hash["Dog" => 1, "Elephant" => 2, "Lion" => 3]
520
+ # h.sort { |(k1, v1), (k2, v2)| k1.size <=> k2.size }
521
+ # # => Immutable::Vector[["Dog", 1], ["Lion", 3], ["Elephant", 2]]
522
+ # @yield [(k1, v1), (k2, v2)] Any number of times with different pairs of key/value associations.
523
+ # @yieldreturn [Integer] Negative if the first pair should be sorted
524
+ # lower, positive if the latter pair, or 0 if equal.
525
+ #
526
+ # @see ::Enumerable#sort
527
+ #
528
+ # @return [Vector]
529
+ def sort
530
+ Vector.new(super)
531
+ end
532
+
533
+ # Return a {Vector} which contains all the `[key, value]` pairs in this `Hash`
534
+ # as two-element Arrays. The order which the pairs will appear in is determined by
535
+ # passing each pair to the code block to obtain a sort key object, and comparing
536
+ # the sort keys using `#<=>`.
537
+ #
538
+ # @see ::Enumerable#sort_by
539
+ #
540
+ # @example
541
+ # h = Immutable::Hash["Dog" => 1, "Elephant" => 2, "Lion" => 3]
542
+ # h.sort_by { |key, value| key.size }
543
+ # # => Immutable::Vector[["Dog", 1], ["Lion", 3], ["Elephant", 2]]
544
+ #
545
+ # @yield [key, value] Once for each key/value pair.
546
+ # @yieldreturn a sort key object for the yielded pair.
547
+ # @return [Vector]
548
+ def sort_by
549
+ Vector.new(super)
550
+ end
551
+
552
+ # Return a new `Hash` with the associations for all of the given `keys` removed.
553
+ #
554
+ # @example
555
+ # h = Immutable::Hash["A" => 1, "B" => 2, "C" => 3]
556
+ # h.except("A", "C") # => Immutable::Hash["B" => 2]
557
+ #
558
+ # @param keys [Array] The keys to remove
559
+ # @return [Hash]
560
+ def except(*keys)
561
+ keys.reduce(self) { |hash, key| hash.delete(key) }
562
+ end
563
+
564
+ # Return a new `Hash` with only the associations for the `wanted` keys retained.
565
+ #
566
+ # @example
567
+ # h = Immutable::Hash["A" => 1, "B" => 2, "C" => 3]
568
+ # h.slice("B", "C") # => Immutable::Hash["B" => 2, "C" => 3]
569
+ #
570
+ # @param wanted [::Enumerable] The keys to retain
571
+ # @return [Hash]
572
+ def slice(*wanted)
573
+ trie = Trie.new(0)
574
+ wanted.each { |key| trie.put!(key, get(key)) if key?(key) }
575
+ self.class.alloc(trie, @default)
576
+ end
577
+
578
+ # Return a {Vector} of the values which correspond to the `wanted` keys.
579
+ # If any of the `wanted` keys are not present in this `Hash`, `nil` will be
580
+ # placed instead, or the result of the default proc (if one is defined),
581
+ # similar to the behavior of {#get}.
582
+ #
583
+ # @example
584
+ # h = Immutable::Hash["A" => 1, "B" => 2, "C" => 3]
585
+ # h.values_at("B", "A", "D") # => Immutable::Vector[2, 1, nil]
586
+ #
587
+ # @param wanted [Array] The keys to retrieve
588
+ # @return [Vector]
589
+ def values_at(*wanted)
590
+ Vector.new(wanted.map { |key| get(key) }.freeze)
591
+ end
592
+
593
+ # Return a {Vector} of the values which correspond to the `wanted` keys.
594
+ # If any of the `wanted` keys are not present in this `Hash`, raise `KeyError`
595
+ # exception.
596
+ #
597
+ # @example
598
+ # h = Immutable::Hash["A" => 1, "B" => 2, "C" => 3]
599
+ # h.fetch_values("C", "A") # => Immutable::Vector[3, 1]
600
+ # h.fetch_values("C", "Z") # => KeyError: key not found: "Z"
601
+ #
602
+ # @param wanted [Array] The keys to retrieve
603
+ # @return [Vector]
604
+ def fetch_values(*wanted)
605
+ array = wanted.map { |key| fetch(key) }
606
+ Vector.new(array.freeze)
607
+ end
608
+
609
+ # Return the value of successively indexing into a nested collection.
610
+ # If any of the keys is not present, return `nil`.
611
+ #
612
+ # @example
613
+ # h = Immutable::Hash[a: 9, b: Immutable::Hash[c: 'a', d: 4], e: nil]
614
+ # h.dig(:b, :c) # => "a"
615
+ # h.dig(:b, :f) # => nil
616
+ #
617
+ # @return [Object]
618
+ def dig(key, *rest)
619
+ value = self[key]
620
+ if rest.empty? || value.nil?
621
+ value
622
+ else
623
+ value.dig(*rest)
624
+ end
625
+ end
626
+
627
+ # Return a new {Set} containing the keys from this `Hash`.
628
+ #
629
+ # @example
630
+ # Immutable::Hash["A" => 1, "B" => 2, "C" => 3, "D" => 2].keys
631
+ # # => Immutable::Set["D", "C", "B", "A"]
632
+ #
633
+ # @return [Set]
634
+ def keys
635
+ Set.alloc(@trie)
636
+ end
637
+
638
+ # Return a new {Vector} populated with the values from this `Hash`.
639
+ #
640
+ # @example
641
+ # Immutable::Hash["A" => 1, "B" => 2, "C" => 3, "D" => 2].values
642
+ # # => Immutable::Vector[2, 3, 2, 1]
643
+ #
644
+ # @return [Vector]
645
+ def values
646
+ Vector.new(each_value.to_a.freeze)
647
+ end
648
+
649
+ # Return a new `Hash` created by using keys as values and values as keys.
650
+ # If there are multiple values which are equivalent (as determined by `#hash` and
651
+ # `#eql?`), only one out of each group of equivalent values will be
652
+ # retained. Which one specifically is undefined.
653
+ #
654
+ # @example
655
+ # Immutable::Hash["A" => 1, "B" => 2, "C" => 3, "D" => 2].invert
656
+ # # => Immutable::Hash[1 => "A", 3 => "C", 2 => "B"]
657
+ #
658
+ # @return [Hash]
659
+ def invert
660
+ pairs = []
661
+ each { |k,v| pairs << [v, k] }
662
+ self.class.new(pairs, &@default)
663
+ end
664
+
665
+ # Return a new {Vector} which is a one-dimensional flattening of this `Hash`.
666
+ # If `level` is 1, all the `[key, value]` pairs in the hash will be concatenated
667
+ # into one {Vector}. If `level` is greater than 1, keys or values which are
668
+ # themselves `Array`s or {Vector}s will be recursively flattened into the output
669
+ # {Vector}. The depth to which that flattening will be recursively applied is
670
+ # determined by `level`.
671
+ #
672
+ # As a special case, if `level` is 0, each `[key, value]` pair will be a
673
+ # separate element in the returned {Vector}.
674
+ #
675
+ # @example
676
+ # h = Immutable::Hash["A" => 1, "B" => [2, 3, 4]]
677
+ # h.flatten
678
+ # # => Immutable::Vector["A", 1, "B", [2, 3, 4]]
679
+ # h.flatten(2)
680
+ # # => Immutable::Vector["A", 1, "B", 2, 3, 4]
681
+ #
682
+ # @param level [Integer] The number of times to recursively flatten the `[key, value]` pairs in this `Hash`.
683
+ # @return [Vector]
684
+ def flatten(level = 1)
685
+ return Vector.new(self) if level == 0
686
+ array = []
687
+ each { |k,v| array << k; array << v }
688
+ array.flatten!(level-1) if level > 1
689
+ Vector.new(array.freeze)
690
+ end
691
+
692
+ # Searches through the `Hash`, comparing `obj` with each key (using `#==`).
693
+ # When a matching key is found, return the `[key, value]` pair as an array.
694
+ # Return `nil` if no match is found.
695
+ #
696
+ # @example
697
+ # Immutable::Hash["A" => 1, "B" => 2, "C" => 3].assoc("B") # => ["B", 2]
698
+ #
699
+ # @param obj [Object] The key to search for (using #==)
700
+ # @return [Array]
701
+ def assoc(obj)
702
+ each { |entry| return entry if obj == entry[0] }
703
+ nil
704
+ end
705
+
706
+ # Searches through the `Hash`, comparing `obj` with each value (using `#==`).
707
+ # When a matching value is found, return the `[key, value]` pair as an array.
708
+ # Return `nil` if no match is found.
709
+ #
710
+ # @example
711
+ # Immutable::Hash["A" => 1, "B" => 2, "C" => 3].rassoc(2) # => ["B", 2]
712
+ #
713
+ # @param obj [Object] The value to search for (using #==)
714
+ # @return [Array]
715
+ def rassoc(obj)
716
+ each { |entry| return entry if obj == entry[1] }
717
+ nil
718
+ end
719
+
720
+ # Searches through the `Hash`, comparing `value` with each value (using `#==`).
721
+ # When a matching value is found, return its associated key object.
722
+ # Return `nil` if no match is found.
723
+ #
724
+ # @example
725
+ # Immutable::Hash["A" => 1, "B" => 2, "C" => 3].key(2) # => "B"
726
+ #
727
+ # @param value [Object] The value to search for (using #==)
728
+ # @return [Object]
729
+ def key(value)
730
+ each { |entry| return entry[0] if value == entry[1] }
731
+ nil
732
+ end
733
+
734
+ # Return a randomly chosen `[key, value]` pair from this `Hash`. If the hash is empty,
735
+ # return `nil`.
736
+ #
737
+ # @example
738
+ # Immutable::Hash["A" => 1, "B" => 2, "C" => 3].sample
739
+ # # => ["C", 3]
740
+ #
741
+ # @return [Array]
742
+ def sample
743
+ @trie.at(rand(size))
744
+ end
745
+
746
+ # Return an empty `Hash` instance, of the same class as this one. Useful if you
747
+ # have multiple subclasses of `Hash` and want to treat them polymorphically.
748
+ # Maintains the default block, if there is one.
749
+ #
750
+ # @return [Hash]
751
+ def clear
752
+ if @default
753
+ self.class.alloc(EmptyTrie, @default)
754
+ else
755
+ self.class.empty
756
+ end
757
+ end
758
+
759
+ # Return true if `other` has the same type and contents as this `Hash`.
760
+ #
761
+ # @param other [Object] The collection to compare with
762
+ # @return [Boolean]
763
+ def eql?(other)
764
+ return true if other.equal?(self)
765
+ instance_of?(other.class) && @trie.eql?(other.instance_variable_get(:@trie))
766
+ end
767
+
768
+ # Return true if `other` has the same contents as this `Hash`. Will convert
769
+ # `other` to a Ruby `Hash` using `#to_hash` if necessary.
770
+ #
771
+ # @param other [Object] The object to compare with
772
+ # @return [Boolean]
773
+ def ==(other)
774
+ eql?(other) || (other.respond_to?(:to_hash) && to_hash == other.to_hash)
775
+ end
776
+
777
+ # Return true if this `Hash` is a proper superset of `other`, which means
778
+ # all `other`'s keys are contained in this `Hash` with identical
779
+ # values, and the two hashes are not identical.
780
+ #
781
+ # @param other [Immutable::Hash] The object to compare with
782
+ # @return [Boolean]
783
+ def >(other)
784
+ self != other && self >= other
785
+ end
786
+
787
+ # Return true if this `Hash` is a superset of `other`, which means all
788
+ # `other`'s keys are contained in this `Hash` with identical values.
789
+ #
790
+ # @param other [Immutable::Hash] The object to compare with
791
+ # @return [Boolean]
792
+ def >=(other)
793
+ other.each do |key, value|
794
+ if self[key] != value
795
+ return false
796
+ end
797
+ end
798
+ true
799
+ end
800
+
801
+ # Return true if this `Hash` is a proper subset of `other`, which means all
802
+ # its keys are contained in `other` with the identical values, and the two
803
+ # hashes are not identical.
804
+ #
805
+ # @param other [Immutable::Hash] The object to compare with
806
+ # @return [Boolean]
807
+ def <(other)
808
+ other > self
809
+ end
810
+
811
+ # Return true if this `Hash` is a subset of `other`, which means all its
812
+ # keys are contained in `other` with the identical values, and the two
813
+ # hashes are not identical.
814
+ #
815
+ # @param other [Immutable::Hash] The object to compare with
816
+ # @return [Boolean]
817
+ def <=(other)
818
+ other >= self
819
+ end
820
+
821
+ # See `Object#hash`.
822
+ # @return [Integer]
823
+ def hash
824
+ keys.to_a.sort.reduce(0) do |hash, key|
825
+ (hash << 32) - hash + key.hash + get(key).hash
826
+ end
827
+ end
828
+
829
+ # Return the contents of this `Hash` as a programmer-readable `String`. If all the
830
+ # keys and values are serializable as Ruby literal strings, the returned string can
831
+ # be passed to `eval` to reconstitute an equivalent `Hash`. The default
832
+ # block (if there is one) will be lost when doing this, however.
833
+ #
834
+ # @return [String]
835
+ def inspect
836
+ result = "#{self.class}["
837
+ i = 0
838
+ each do |key, val|
839
+ result << ', ' if i > 0
840
+ result << key.inspect << ' => ' << val.inspect
841
+ i += 1
842
+ end
843
+ result << ']'
844
+ end
845
+
846
+ # Return `self`. Since this is an immutable object duplicates are
847
+ # equivalent.
848
+ # @return [Hash]
849
+ def dup
850
+ self
851
+ end
852
+ alias clone dup
853
+
854
+ # Allows this `Hash` to be printed at the `pry` console, or using `pp` (from the
855
+ # Ruby standard library), in a way which takes the amount of horizontal space on
856
+ # the screen into account, and which indents nested structures to make them easier
857
+ # to read.
858
+ #
859
+ # @private
860
+ def pretty_print(pp)
861
+ pp.group(1, "#{self.class}[", ']') do
862
+ pp.breakable ''
863
+ pp.seplist(self, nil) do |key, val|
864
+ pp.group do
865
+ key.pretty_print(pp)
866
+ pp.text ' => '
867
+ pp.group(1) do
868
+ pp.breakable ''
869
+ val.pretty_print(pp)
870
+ end
871
+ end
872
+ end
873
+ end
874
+ end
875
+
876
+ # Convert this `Immutable::Hash` to an instance of Ruby's built-in `Hash`.
877
+ #
878
+ # @return [::Hash]
879
+ def to_hash
880
+ output = {}
881
+ each do |key, value|
882
+ output[key] = value
883
+ end
884
+ output
885
+ end
886
+ alias to_h to_hash
887
+
888
+ # Return a `Proc` which accepts a key as an argument and returns the value.
889
+ # The `Proc` behaves like {#get} (when the key is missing, it returns nil or
890
+ # the result of the default proc).
891
+ #
892
+ # @example
893
+ # h = Immutable::Hash["A" => 1, "B" => 2, "C" => 3]
894
+ # h.to_proc.call("B")
895
+ # # => 2
896
+ # ["A", "C", "X"].map(&h) # The & is short for .to_proc in Ruby
897
+ # # => [1, 3, nil]
898
+ #
899
+ # @return [Proc]
900
+ def to_proc
901
+ lambda { |key| get(key) }
902
+ end
903
+
904
+ # @return [::Hash]
905
+ # @private
906
+ def marshal_dump
907
+ to_hash
908
+ end
909
+
910
+ # @private
911
+ def marshal_load(dictionary)
912
+ @trie = Trie[dictionary]
913
+ end
914
+
915
+ private
916
+
917
+ # Return a new `Hash` which is derived from this one, using a modified {Trie}.
918
+ # The new `Hash` will retain the existing default block, if there is one.
919
+ #
920
+ def derive_new_hash(trie)
921
+ if trie.equal?(@trie)
922
+ self
923
+ elsif trie.empty?
924
+ if @default
925
+ self.class.alloc(EmptyTrie, @default)
926
+ else
927
+ self.class.empty
928
+ end
929
+ else
930
+ self.class.alloc(trie, @default)
931
+ end
932
+ end
933
+ end
934
+
935
+ # The canonical empty `Hash`. Returned by `Hash[]` when
936
+ # invoked with no arguments; also returned by `Hash.empty`. Prefer using this
937
+ # one rather than creating many empty hashes using `Hash.new`.
938
+ #
939
+ # @private
940
+ EmptyHash = Immutable::Hash.empty
941
+
942
+
943
+ # A `Vector` is an ordered, integer-indexed collection of objects. Like
944
+ # Ruby's `Array`, `Vector` indexing starts at zero and negative indexes count
945
+ # back from the end.
946
+ #
947
+ # `Vector` has a similar interface to `Array`. The main difference is methods
948
+ # that would destructively update an `Array` (such as {#insert} or
949
+ # {#delete_at}) instead return new `Vectors` and leave the existing one
950
+ # unchanged.
951
+ #
952
+ # ### Creating New Vectors
953
+ #
954
+ # Immutable::Vector.new([:first, :second, :third])
955
+ # Immutable::Vector[1, 2, 3, 4, 5]
956
+ #
957
+ # ### Retrieving Items from Vectors
958
+ #
959
+ # vector = Immutable::Vector[1, 2, 3, 4, 5]
960
+ #
961
+ # vector[0] # => 1
962
+ # vector[-1] # => 5
963
+ # vector[0,3] # => Immutable::Vector[1, 2, 3]
964
+ # vector[1..-1] # => Immutable::Vector[2, 3, 4, 5]
965
+ # vector.first # => 1
966
+ # vector.last # => 5
967
+ #
968
+ # ### Creating Modified Vectors
969
+ #
970
+ # vector.add(6) # => Immutable::Vector[1, 2, 3, 4, 5, 6]
971
+ # vector.insert(1, :a, :b) # => Immutable::Vector[1, :a, :b, 2, 3, 4, 5]
972
+ # vector.delete_at(2) # => Immutable::Vector[1, 2, 4, 5]
973
+ # vector + [6, 7] # => Immutable::Vector[1, 2, 3, 4, 5, 6, 7]
974
+ #
975
+ class Vector
976
+ include Immutable::Enumerable
977
+
978
+ # @private
979
+ BLOCK_SIZE = 32
980
+ # @private
981
+ INDEX_MASK = BLOCK_SIZE - 1
982
+ # @private
983
+ BITS_PER_LEVEL = 5
984
+
985
+ # Return the number of items in this `Vector`
986
+ # @return [Integer]
987
+ attr_reader :size
988
+ alias length size
989
+
990
+ class << self
991
+ # Create a new `Vector` populated with the given items.
992
+ # @return [Vector]
993
+ def [](*items)
994
+ new(items.freeze)
995
+ end
996
+
997
+ # Return an empty `Vector`. If used on a subclass, returns an empty instance
998
+ # of that class.
999
+ #
1000
+ # @return [Vector]
1001
+ def empty
1002
+ @empty ||= new
1003
+ end
1004
+
1005
+ # "Raw" allocation of a new `Vector`. Used internally to create a new
1006
+ # instance quickly after building a modified trie.
1007
+ #
1008
+ # @return [Vector]
1009
+ # @private
1010
+ def alloc(root, size, levels)
1011
+ obj = allocate
1012
+ obj.instance_variable_set(:@root, root)
1013
+ obj.instance_variable_set(:@size, size)
1014
+ obj.instance_variable_set(:@levels, levels)
1015
+ obj.freeze
1016
+ end
1017
+ end
1018
+
1019
+ def initialize(items=[].freeze)
1020
+ items = items.to_a
1021
+ if items.size <= 32
1022
+ items = items.dup.freeze if !items.frozen?
1023
+ @root, @size, @levels = items, items.size, 0
1024
+ else
1025
+ root, size, levels = items, items.size, 0
1026
+ while root.size > 32
1027
+ root = root.each_slice(32).to_a
1028
+ levels += 1
1029
+ end
1030
+ @root, @size, @levels = root.freeze, size, levels
1031
+ end
1032
+ freeze
1033
+ end
1034
+
1035
+ # Return `true` if this `Vector` contains no items.
1036
+ #
1037
+ # @return [Boolean]
1038
+ def empty?
1039
+ @size == 0
1040
+ end
1041
+
1042
+ # Return the first item in the `Vector`. If the vector is empty, return `nil`.
1043
+ #
1044
+ # @example
1045
+ # Immutable::Vector["A", "B", "C"].first # => "A"
1046
+ #
1047
+ # @return [Object]
1048
+ def first
1049
+ get(0)
1050
+ end
1051
+
1052
+ # Return the last item in the `Vector`. If the vector is empty, return `nil`.
1053
+ #
1054
+ # @example
1055
+ # Immutable::Vector["A", "B", "C"].last # => "C"
1056
+ #
1057
+ # @return [Object]
1058
+ def last
1059
+ get(-1)
1060
+ end
1061
+
1062
+ # Return a new `Vector` with `item` added after the last occupied position.
1063
+ #
1064
+ # @example
1065
+ # Immutable::Vector[1, 2].add(99) # => Immutable::Vector[1, 2, 99]
1066
+ #
1067
+ # @param item [Object] The object to insert at the end of the vector
1068
+ # @return [Vector]
1069
+ def add(item)
1070
+ update_root(@size, item)
1071
+ end
1072
+ alias << add
1073
+ alias push add
1074
+
1075
+ # Return a new `Vector` with a new value at the given `index`. If `index`
1076
+ # is greater than the length of the vector, the returned vector will be
1077
+ # padded with `nil`s to the correct size.
1078
+ #
1079
+ # @overload set(index, item)
1080
+ # Return a new `Vector` with the item at `index` replaced by `item`.
1081
+ #
1082
+ # @param item [Object] The object to insert into that position
1083
+ # @example
1084
+ # Immutable::Vector[1, 2, 3, 4].set(2, 99)
1085
+ # # => Immutable::Vector[1, 2, 99, 4]
1086
+ # Immutable::Vector[1, 2, 3, 4].set(-1, 99)
1087
+ # # => Immutable::Vector[1, 2, 3, 99]
1088
+ # Immutable::Vector[].set(2, 99)
1089
+ # # => Immutable::Vector[nil, nil, 99]
1090
+ #
1091
+ # @overload set(index)
1092
+ # Return a new `Vector` with the item at `index` replaced by the return
1093
+ # value of the block.
1094
+ #
1095
+ # @yield (existing) Once with the existing value at the given `index`.
1096
+ # @example
1097
+ # Immutable::Vector[1, 2, 3, 4].set(2) { |v| v * 10 }
1098
+ # # => Immutable::Vector[1, 2, 30, 4]
1099
+ #
1100
+ # @param index [Integer] The index to update. May be negative.
1101
+ # @return [Vector]
1102
+ def set(index, item = yield(get(index)))
1103
+ raise IndexError, "index #{index} outside of vector bounds" if index < -@size
1104
+ index += @size if index < 0
1105
+ if index > @size
1106
+ suffix = Array.new(index - @size, nil)
1107
+ suffix << item
1108
+ replace_suffix(@size, suffix)
1109
+ else
1110
+ update_root(index, item)
1111
+ end
1112
+ end
1113
+
1114
+ # Return a new `Vector` with a deeply nested value modified to the result
1115
+ # of the given code block. When traversing the nested `Vector`s and
1116
+ # `Hash`es, non-existing keys are created with empty `Hash` values.
1117
+ #
1118
+ # The code block receives the existing value of the deeply nested key (or
1119
+ # `nil` if it doesn't exist). This is useful for "transforming" the value
1120
+ # associated with a certain key.
1121
+ #
1122
+ # Note that the original `Vector` and sub-`Vector`s and sub-`Hash`es are
1123
+ # left unmodified; new data structure copies are created along the path
1124
+ # wherever needed.
1125
+ #
1126
+ # @example
1127
+ # v = Immutable::Vector[123, 456, 789, Immutable::Hash["a" => Immutable::Vector[5, 6, 7]]]
1128
+ # v.update_in(3, "a", 1) { |value| value + 9 }
1129
+ # # => Immutable::Vector[123, 456, 789, Immutable::Hash["a" => Immutable::Vector[5, 15, 7]]]
1130
+ #
1131
+ # @param key_path [Object(s)] List of keys which form the path to the key to be modified
1132
+ # @yield [value] The previously stored value
1133
+ # @yieldreturn [Object] The new value to store
1134
+ # @return [Vector]
1135
+ def update_in(*key_path, &block)
1136
+ if key_path.empty?
1137
+ raise ArgumentError, 'must have at least one key in path'
1138
+ end
1139
+ key = key_path[0]
1140
+ if key_path.size == 1
1141
+ new_value = block.call(get(key))
1142
+ else
1143
+ value = fetch(key, Immutable::EmptyHash)
1144
+ new_value = value.update_in(*key_path[1..-1], &block)
1145
+ end
1146
+ set(key, new_value)
1147
+ end
1148
+
1149
+ # Retrieve the item at `index`. If there is none (either the provided index
1150
+ # is too high or too low), return `nil`.
1151
+ #
1152
+ # @example
1153
+ # v = Immutable::Vector["A", "B", "C", "D"]
1154
+ # v.get(2) # => "C"
1155
+ # v.get(-1) # => "D"
1156
+ # v.get(4) # => nil
1157
+ #
1158
+ # @param index [Integer] The index to retrieve
1159
+ # @return [Object]
1160
+ def get(index)
1161
+ return nil if @size == 0
1162
+ index += @size if index < 0
1163
+ return nil if index >= @size || index < 0
1164
+ leaf_node_for(@root, @levels * BITS_PER_LEVEL, index)[index & INDEX_MASK]
1165
+ end
1166
+ alias at get
1167
+
1168
+ # Retrieve the value at `index` with optional default.
1169
+ #
1170
+ # @overload fetch(index)
1171
+ # Retrieve the value at the given index, or raise an `IndexError` if not
1172
+ # found.
1173
+ #
1174
+ # @param index [Integer] The index to look up
1175
+ # @raise [IndexError] if index does not exist
1176
+ # @example
1177
+ # v = Immutable::Vector["A", "B", "C", "D"]
1178
+ # v.fetch(2) # => "C"
1179
+ # v.fetch(-1) # => "D"
1180
+ # v.fetch(4) # => IndexError: index 4 outside of vector bounds
1181
+ #
1182
+ # @overload fetch(index) { |index| ... }
1183
+ # Retrieve the value at the given index, or return the result of yielding
1184
+ # the block if not found.
1185
+ #
1186
+ # @yield Once if the index is not found.
1187
+ # @yieldparam [Integer] index The index which does not exist
1188
+ # @yieldreturn [Object] Default value to return
1189
+ # @param index [Integer] The index to look up
1190
+ # @example
1191
+ # v = Immutable::Vector["A", "B", "C", "D"]
1192
+ # v.fetch(2) { |i| i * i } # => "C"
1193
+ # v.fetch(4) { |i| i * i } # => 16
1194
+ #
1195
+ # @overload fetch(index, default)
1196
+ # Retrieve the value at the given index, or return the provided `default`
1197
+ # value if not found.
1198
+ #
1199
+ # @param index [Integer] The index to look up
1200
+ # @param default [Object] Object to return if the key is not found
1201
+ # @example
1202
+ # v = Immutable::Vector["A", "B", "C", "D"]
1203
+ # v.fetch(2, "Z") # => "C"
1204
+ # v.fetch(4, "Z") # => "Z"
1205
+ #
1206
+ # @return [Object]
1207
+ def fetch(index, default = (missing_default = true))
1208
+ if index >= -@size && index < @size
1209
+ get(index)
1210
+ elsif block_given?
1211
+ yield(index)
1212
+ elsif !missing_default
1213
+ default
1214
+ else
1215
+ raise IndexError, "index #{index} outside of vector bounds"
1216
+ end
1217
+ end
1218
+
1219
+ # Return the value of successively indexing into a nested collection.
1220
+ # If any of the keys is not present, return `nil`.
1221
+ #
1222
+ # @example
1223
+ # v = Immutable::Vector[9, Immutable::Hash[c: 'a', d: 4]]
1224
+ # v.dig(1, :c) # => "a"
1225
+ # v.dig(1, :f) # => nil
1226
+ #
1227
+ # @return [Object]
1228
+ def dig(key, *rest)
1229
+ value = self[key]
1230
+ if rest.empty? || value.nil?
1231
+ value
1232
+ else
1233
+ value.dig(*rest)
1234
+ end
1235
+ end
1236
+
1237
+ # Return specific objects from the `Vector`. All overloads return `nil` if
1238
+ # the starting index is out of range.
1239
+ #
1240
+ # @overload vector.slice(index)
1241
+ # Returns a single object at the given `index`. If `index` is negative,
1242
+ # count backwards from the end.
1243
+ #
1244
+ # @param index [Integer] The index to retrieve. May be negative.
1245
+ # @return [Object]
1246
+ # @example
1247
+ # v = Immutable::Vector["A", "B", "C", "D", "E", "F"]
1248
+ # v[2] # => "C"
1249
+ # v[-1] # => "F"
1250
+ # v[6] # => nil
1251
+ #
1252
+ # @overload vector.slice(index, length)
1253
+ # Return a subvector starting at `index` and continuing for `length`
1254
+ # elements or until the end of the `Vector`, whichever occurs first.
1255
+ #
1256
+ # @param start [Integer] The index to start retrieving items from. May be
1257
+ # negative.
1258
+ # @param length [Integer] The number of items to retrieve.
1259
+ # @return [Vector]
1260
+ # @example
1261
+ # v = Immutable::Vector["A", "B", "C", "D", "E", "F"]
1262
+ # v[2, 3] # => Immutable::Vector["C", "D", "E"]
1263
+ # v[-2, 3] # => Immutable::Vector["E", "F"]
1264
+ # v[20, 1] # => nil
1265
+ #
1266
+ # @overload vector.slice(index..end)
1267
+ # Return a subvector starting at `index` and continuing to index
1268
+ # `end` or the end of the `Vector`, whichever occurs first.
1269
+ #
1270
+ # @param range [Range] The range of indices to retrieve.
1271
+ # @return [Vector]
1272
+ # @example
1273
+ # v = Immutable::Vector["A", "B", "C", "D", "E", "F"]
1274
+ # v[2..3] # => Immutable::Vector["C", "D"]
1275
+ # v[-2..100] # => Immutable::Vector["E", "F"]
1276
+ # v[20..21] # => nil
1277
+ def slice(arg, length = (missing_length = true))
1278
+ if missing_length
1279
+ if arg.is_a?(Range)
1280
+ from, to = arg.begin, arg.end
1281
+ from += @size if from < 0
1282
+ to += @size if to < 0
1283
+ to += 1 if !arg.exclude_end?
1284
+ length = to - from
1285
+ length = 0 if length < 0
1286
+ subsequence(from, length)
1287
+ else
1288
+ get(arg)
1289
+ end
1290
+ else
1291
+ arg += @size if arg < 0
1292
+ subsequence(arg, length)
1293
+ end
1294
+ end
1295
+ alias [] slice
1296
+
1297
+ # Return a new `Vector` with the given values inserted before the element
1298
+ # at `index`. If `index` is greater than the current length, `nil` values
1299
+ # are added to pad the `Vector` to the required size.
1300
+ #
1301
+ # @example
1302
+ # Immutable::Vector["A", "B", "C", "D"].insert(2, "X", "Y", "Z")
1303
+ # # => Immutable::Vector["A", "B", "X", "Y", "Z", "C", "D"]
1304
+ # Immutable::Vector[].insert(2, "X", "Y", "Z")
1305
+ # # => Immutable::Vector[nil, nil, "X", "Y", "Z"]
1306
+ #
1307
+ # @param index [Integer] The index where the new items should go
1308
+ # @param items [Array] The items to add
1309
+ # @return [Vector]
1310
+ # @raise [IndexError] if index exceeds negative range.
1311
+ def insert(index, *items)
1312
+ raise IndexError if index < -@size
1313
+ index += @size if index < 0
1314
+
1315
+ if index < @size
1316
+ suffix = flatten_suffix(@root, @levels * BITS_PER_LEVEL, index, [])
1317
+ suffix.unshift(*items)
1318
+ elsif index == @size
1319
+ suffix = items
1320
+ else
1321
+ suffix = Array.new(index - @size, nil).concat(items)
1322
+ index = @size
1323
+ end
1324
+
1325
+ replace_suffix(index, suffix)
1326
+ end
1327
+
1328
+ # Return a new `Vector` with the element at `index` removed. If the given `index`
1329
+ # does not exist, return `self`.
1330
+ #
1331
+ # @example
1332
+ # Immutable::Vector["A", "B", "C", "D"].delete_at(2)
1333
+ # # => Immutable::Vector["A", "B", "D"]
1334
+ #
1335
+ # @param index [Integer] The index to remove
1336
+ # @return [Vector]
1337
+ def delete_at(index)
1338
+ return self if index >= @size || index < -@size
1339
+ index += @size if index < 0
1340
+
1341
+ suffix = flatten_suffix(@root, @levels * BITS_PER_LEVEL, index, [])
1342
+ replace_suffix(index, suffix.tap(&:shift))
1343
+ end
1344
+
1345
+ # Return a new `Vector` with the last element removed. Return `self` if
1346
+ # empty.
1347
+ #
1348
+ # @example
1349
+ # Immutable::Vector["A", "B", "C"].pop # => Immutable::Vector["A", "B"]
1350
+ #
1351
+ # @return [Vector]
1352
+ def pop
1353
+ return self if @size == 0
1354
+ replace_suffix(@size-1, [])
1355
+ end
1356
+
1357
+ # Return a new `Vector` with `object` inserted before the first element,
1358
+ # moving the other elements upwards.
1359
+ #
1360
+ # @example
1361
+ # Immutable::Vector["A", "B"].unshift("Z")
1362
+ # # => Immutable::Vector["Z", "A", "B"]
1363
+ #
1364
+ # @param object [Object] The value to prepend
1365
+ # @return [Vector]
1366
+ def unshift(object)
1367
+ insert(0, object)
1368
+ end
1369
+
1370
+ # Return a new `Vector` with the first element removed. If empty, return
1371
+ # `self`.
1372
+ #
1373
+ # @example
1374
+ # Immutable::Vector["A", "B", "C"].shift # => Immutable::Vector["B", "C"]
1375
+ #
1376
+ # @return [Vector]
1377
+ def shift
1378
+ delete_at(0)
1379
+ end
1380
+
1381
+ # Call the given block once for each item in the vector, passing each
1382
+ # item from first to last successively to the block. If no block is given,
1383
+ # an `Enumerator` is returned instead.
1384
+ #
1385
+ # @example
1386
+ # Immutable::Vector["A", "B", "C"].each { |e| puts "Element: #{e}" }
1387
+ #
1388
+ # Element: A
1389
+ # Element: B
1390
+ # Element: C
1391
+ # # => Immutable::Vector["A", "B", "C"]
1392
+ #
1393
+ # @return [self, Enumerator]
1394
+ def each(&block)
1395
+ return to_enum unless block_given?
1396
+ traverse_depth_first(@root, @levels, &block)
1397
+ self
1398
+ end
1399
+
1400
+ # Call the given block once for each item in the vector, from last to
1401
+ # first.
1402
+ #
1403
+ # @example
1404
+ # Immutable::Vector["A", "B", "C"].reverse_each { |e| puts "Element: #{e}" }
1405
+ #
1406
+ # Element: C
1407
+ # Element: B
1408
+ # Element: A
1409
+ #
1410
+ # @return [self]
1411
+ def reverse_each(&block)
1412
+ return enum_for(:reverse_each) unless block_given?
1413
+ reverse_traverse_depth_first(@root, @levels, &block)
1414
+ self
1415
+ end
1416
+
1417
+ # Return a new `Vector` containing all elements for which the given block returns
1418
+ # true.
1419
+ #
1420
+ # @example
1421
+ # Immutable::Vector["Bird", "Cow", "Elephant"].select { |e| e.size >= 4 }
1422
+ # # => Immutable::Vector["Bird", "Elephant"]
1423
+ #
1424
+ # @return [Vector]
1425
+ # @yield [element] Once for each element.
1426
+ def select
1427
+ return enum_for(:select) unless block_given?
1428
+ reduce(self.class.empty) { |vector, item| yield(item) ? vector.add(item) : vector }
1429
+ end
1430
+ alias find_all select
1431
+ alias keep_if select
1432
+
1433
+ # Return a new `Vector` with all items which are equal to `obj` removed.
1434
+ # `#==` is used for checking equality.
1435
+ #
1436
+ # @example
1437
+ # Immutable::Vector["C", "B", "A", "B"].delete("B") # => Immutable::Vector["C", "A"]
1438
+ #
1439
+ # @param obj [Object] The object to remove (every occurrence)
1440
+ # @return [Vector]
1441
+ def delete(obj)
1442
+ select { |item| item != obj }
1443
+ end
1444
+
1445
+ # Invoke the given block once for each item in the vector, and return a new
1446
+ # `Vector` containing the values returned by the block. If no block is
1447
+ # provided, return an enumerator.
1448
+ #
1449
+ # @example
1450
+ # Immutable::Vector[3, 2, 1].map { |e| e * e } # => Immutable::Vector[9, 4, 1]
1451
+ #
1452
+ # @return [Vector, Enumerator]
1453
+ def map
1454
+ return enum_for(:map) if not block_given?
1455
+ return self if empty?
1456
+ self.class.new(super)
1457
+ end
1458
+ alias collect map
1459
+
1460
+ # Return a new `Vector` with the concatenated results of running the block once
1461
+ # for every element in this `Vector`.
1462
+ #
1463
+ # @example
1464
+ # Immutable::Vector[1, 2, 3].flat_map { |x| [x, -x] }
1465
+ # # => Immutable::Vector[1, -1, 2, -2, 3, -3]
1466
+ #
1467
+ # @return [Vector]
1468
+ def flat_map
1469
+ return enum_for(:flat_map) if not block_given?
1470
+ return self if empty?
1471
+ self.class.new(super)
1472
+ end
1473
+
1474
+ # Return a new `Vector` with the same elements as this one, but randomly permuted.
1475
+ #
1476
+ # @example
1477
+ # Immutable::Vector[1, 2, 3, 4].shuffle # => Immutable::Vector[4, 1, 3, 2]
1478
+ #
1479
+ # @return [Vector]
1480
+ def shuffle
1481
+ self.class.new(((array = to_a).frozen? ? array.shuffle : array.shuffle!).freeze)
1482
+ end
1483
+
1484
+ # Return a new `Vector` with no duplicate elements, as determined by `#hash` and
1485
+ # `#eql?`. For each group of equivalent elements, only the first will be retained.
1486
+ #
1487
+ # @example
1488
+ # Immutable::Vector["A", "B", "C", "B"].uniq # => Immutable::Vector["A", "B", "C"]
1489
+ # Immutable::Vector["a", "A", "b"].uniq(&:upcase) # => Immutable::Vector["a", "b"]
1490
+ #
1491
+ # @return [Vector]
1492
+ def uniq(&block)
1493
+ array = to_a
1494
+ if array.frozen?
1495
+ self.class.new(array.uniq(&block).freeze)
1496
+ elsif array.uniq!(&block) # returns nil if no changes were made
1497
+ self.class.new(array.freeze)
1498
+ else
1499
+ self
1500
+ end
1501
+ end
1502
+
1503
+ # Return a new `Vector` with the same elements as this one, but in reverse order.
1504
+ #
1505
+ # @example
1506
+ # Immutable::Vector["A", "B", "C"].reverse # => Immutable::Vector["C", "B", "A"]
1507
+ #
1508
+ # @return [Vector]
1509
+ def reverse
1510
+ self.class.new(((array = to_a).frozen? ? array.reverse : array.reverse!).freeze)
1511
+ end
1512
+
1513
+ # Return a new `Vector` with the same elements, but rotated so that the one at
1514
+ # index `count` is the first element of the new vector. If `count` is positive,
1515
+ # the elements will be shifted left, and those shifted past the lowest position
1516
+ # will be moved to the end. If `count` is negative, the elements will be shifted
1517
+ # right, and those shifted past the last position will be moved to the beginning.
1518
+ #
1519
+ # @example
1520
+ # v = Immutable::Vector["A", "B", "C", "D", "E", "F"]
1521
+ # v.rotate(2) # => Immutable::Vector["C", "D", "E", "F", "A", "B"]
1522
+ # v.rotate(-1) # => Immutable::Vector["F", "A", "B", "C", "D", "E"]
1523
+ #
1524
+ # @param count [Integer] The number of positions to shift items by
1525
+ # @return [Vector]
1526
+ def rotate(count = 1)
1527
+ return self if (count % @size) == 0
1528
+ self.class.new(((array = to_a).frozen? ? array.rotate(count) : array.rotate!(count)).freeze)
1529
+ end
1530
+
1531
+ # Return a new `Vector` with all nested vectors and arrays recursively "flattened
1532
+ # out". That is, their elements inserted into the new `Vector` in the place where
1533
+ # the nested array/vector originally was. If an optional `level` argument is
1534
+ # provided, the flattening will only be done recursively that number of times.
1535
+ # A `level` of 0 means not to flatten at all, 1 means to only flatten nested
1536
+ # arrays/vectors which are directly contained within this `Vector`.
1537
+ #
1538
+ # @example
1539
+ # v = Immutable::Vector["A", Immutable::Vector["B", "C", Immutable::Vector["D"]]]
1540
+ # v.flatten(1)
1541
+ # # => Immutable::Vector["A", "B", "C", Immutable::Vector["D"]]
1542
+ # v.flatten
1543
+ # # => Immutable::Vector["A", "B", "C", "D"]
1544
+ #
1545
+ # @param level [Integer] The depth to which flattening should be applied
1546
+ # @return [Vector]
1547
+ def flatten(level = -1)
1548
+ return self if level == 0
1549
+ array = to_a
1550
+ if array.frozen?
1551
+ self.class.new(array.flatten(level).freeze)
1552
+ elsif array.flatten!(level) # returns nil if no changes were made
1553
+ self.class.new(array.freeze)
1554
+ else
1555
+ self
1556
+ end
1557
+ end
1558
+
1559
+ # Return a new `Vector` built by concatenating this one with `other`. `other`
1560
+ # can be any object which is convertible to an `Array` using `#to_a`.
1561
+ #
1562
+ # @example
1563
+ # Immutable::Vector["A", "B", "C"] + ["D", "E"]
1564
+ # # => Immutable::Vector["A", "B", "C", "D", "E"]
1565
+ #
1566
+ # @param other [Enumerable] The collection to concatenate onto this vector
1567
+ # @return [Vector]
1568
+ def +(other)
1569
+ other = other.to_a
1570
+ other = other.dup if other.frozen?
1571
+ replace_suffix(@size, other)
1572
+ end
1573
+ alias concat +
1574
+
1575
+ # Combine two vectors by "zipping" them together. `others` should be arrays
1576
+ # and/or vectors. The corresponding elements from this `Vector` and each of
1577
+ # `others` (that is, the elements with the same indices) will be gathered
1578
+ # into arrays.
1579
+ #
1580
+ # If `others` contains fewer elements than this vector, `nil` will be used
1581
+ # for padding.
1582
+ #
1583
+ # @overload zip(*others)
1584
+ # Return a new vector containing the new arrays.
1585
+ #
1586
+ # @return [Vector]
1587
+ #
1588
+ # @overload zip(*others)
1589
+ # @yield [pair] once for each array
1590
+ # @return [nil]
1591
+ #
1592
+ # @example
1593
+ # v1 = Immutable::Vector["A", "B", "C"]
1594
+ # v2 = Immutable::Vector[1, 2]
1595
+ # v1.zip(v2)
1596
+ # # => Immutable::Vector[["A", 1], ["B", 2], ["C", nil]]
1597
+ #
1598
+ # @param others [Array] The arrays/vectors to zip together with this one
1599
+ # @return [Vector]
1600
+ def zip(*others)
1601
+ if block_given?
1602
+ super
1603
+ else
1604
+ self.class.new(super)
1605
+ end
1606
+ end
1607
+
1608
+ # Return a new `Vector` with the same items, but sorted.
1609
+ #
1610
+ # @overload sort
1611
+ # Compare elements with their natural sort key (`#<=>`).
1612
+ #
1613
+ # @example
1614
+ # Immutable::Vector["Elephant", "Dog", "Lion"].sort
1615
+ # # => Immutable::Vector["Dog", "Elephant", "Lion"]
1616
+ #
1617
+ # @overload sort
1618
+ # Uses the block as a comparator to determine sorted order.
1619
+ #
1620
+ # @yield [a, b] Any number of times with different pairs of elements.
1621
+ # @yieldreturn [Integer] Negative if the first element should be sorted
1622
+ # lower, positive if the latter element, or 0 if
1623
+ # equal.
1624
+ # @example
1625
+ # Immutable::Vector["Elephant", "Dog", "Lion"].sort { |a,b| a.size <=> b.size }
1626
+ # # => Immutable::Vector["Dog", "Lion", "Elephant"]
1627
+ #
1628
+ # @return [Vector]
1629
+ def sort
1630
+ self.class.new(super)
1631
+ end
1632
+
1633
+ # Return a new `Vector` with the same items, but sorted. The sort order is
1634
+ # determined by mapping the items through the given block to obtain sort
1635
+ # keys, and then sorting the keys according to their natural sort order
1636
+ # (`#<=>`).
1637
+ #
1638
+ # @yield [element] Once for each element.
1639
+ # @yieldreturn a sort key object for the yielded element.
1640
+ # @example
1641
+ # Immutable::Vector["Elephant", "Dog", "Lion"].sort_by { |e| e.size }
1642
+ # # => Immutable::Vector["Dog", "Lion", "Elephant"]
1643
+ #
1644
+ # @return [Vector]
1645
+ def sort_by
1646
+ self.class.new(super)
1647
+ end
1648
+
1649
+ # Drop the first `n` elements and return the rest in a new `Vector`.
1650
+ #
1651
+ # @example
1652
+ # Immutable::Vector["A", "B", "C", "D", "E", "F"].drop(2)
1653
+ # # => Immutable::Vector["C", "D", "E", "F"]
1654
+ #
1655
+ # @param n [Integer] The number of elements to remove
1656
+ # @return [Vector]
1657
+ # @raise ArgumentError if `n` is negative.
1658
+ def drop(n)
1659
+ return self if n == 0
1660
+ return self.class.empty if n >= @size
1661
+ raise ArgumentError, 'attempt to drop negative size' if n < 0
1662
+ self.class.new(flatten_suffix(@root, @levels * BITS_PER_LEVEL, n, []))
1663
+ end
1664
+
1665
+ # Return only the first `n` elements in a new `Vector`.
1666
+ #
1667
+ # @example
1668
+ # Immutable::Vector["A", "B", "C", "D", "E", "F"].take(4)
1669
+ # # => Immutable::Vector["A", "B", "C", "D"]
1670
+ #
1671
+ # @param n [Integer] The number of elements to retain
1672
+ # @return [Vector]
1673
+ def take(n)
1674
+ return self if n >= @size
1675
+ self.class.new(super)
1676
+ end
1677
+
1678
+ # Drop elements up to, but not including, the first element for which the
1679
+ # block returns `nil` or `false`. Gather the remaining elements into a new
1680
+ # `Vector`. If no block is given, an `Enumerator` is returned instead.
1681
+ #
1682
+ # @example
1683
+ # Immutable::Vector[1, 3, 5, 7, 6, 4, 2].drop_while { |e| e < 5 }
1684
+ # # => Immutable::Vector[5, 7, 6, 4, 2]
1685
+ #
1686
+ # @return [Vector, Enumerator]
1687
+ def drop_while
1688
+ return enum_for(:drop_while) if not block_given?
1689
+ self.class.new(super)
1690
+ end
1691
+
1692
+ # Gather elements up to, but not including, the first element for which the
1693
+ # block returns `nil` or `false`, and return them in a new `Vector`. If no block
1694
+ # is given, an `Enumerator` is returned instead.
1695
+ #
1696
+ # @example
1697
+ # Immutable::Vector[1, 3, 5, 7, 6, 4, 2].take_while { |e| e < 5 }
1698
+ # # => Immutable::Vector[1, 3]
1699
+ #
1700
+ # @return [Vector, Enumerator]
1701
+ def take_while
1702
+ return enum_for(:take_while) if not block_given?
1703
+ self.class.new(super)
1704
+ end
1705
+
1706
+ # Repetition. Return a new `Vector` built by concatenating `times` copies
1707
+ # of this one together.
1708
+ #
1709
+ # @example
1710
+ # Immutable::Vector["A", "B"] * 3
1711
+ # # => Immutable::Vector["A", "B", "A", "B", "A", "B"]
1712
+ #
1713
+ # @param times [Integer] The number of times to repeat the elements in this vector
1714
+ # @return [Vector]
1715
+ def *(times)
1716
+ return self.class.empty if times == 0
1717
+ return self if times == 1
1718
+ result = (to_a * times)
1719
+ result.is_a?(Array) ? self.class.new(result) : result
1720
+ end
1721
+
1722
+ # Replace a range of indexes with the given object.
1723
+ #
1724
+ # @overload fill(object)
1725
+ # Return a new `Vector` of the same size, with every index set to
1726
+ # `object`.
1727
+ #
1728
+ # @param [Object] object Fill value.
1729
+ # @example
1730
+ # Immutable::Vector["A", "B", "C", "D", "E", "F"].fill("Z")
1731
+ # # => Immutable::Vector["Z", "Z", "Z", "Z", "Z", "Z"]
1732
+ #
1733
+ # @overload fill(object, index)
1734
+ # Return a new `Vector` with all indexes from `index` to the end of the
1735
+ # vector set to `object`.
1736
+ #
1737
+ # @param [Object] object Fill value.
1738
+ # @param [Integer] index Starting index. May be negative.
1739
+ # @example
1740
+ # Immutable::Vector["A", "B", "C", "D", "E", "F"].fill("Z", 3)
1741
+ # # => Immutable::Vector["A", "B", "C", "Z", "Z", "Z"]
1742
+ #
1743
+ # @overload fill(object, index, length)
1744
+ # Return a new `Vector` with `length` indexes, beginning from `index`,
1745
+ # set to `object`. Expands the `Vector` if `length` would extend beyond
1746
+ # the current length.
1747
+ #
1748
+ # @param [Object] object Fill value.
1749
+ # @param [Integer] index Starting index. May be negative.
1750
+ # @param [Integer] length
1751
+ # @example
1752
+ # Immutable::Vector["A", "B", "C", "D", "E", "F"].fill("Z", 3, 2)
1753
+ # # => Immutable::Vector["A", "B", "C", "Z", "Z", "F"]
1754
+ # Immutable::Vector["A", "B"].fill("Z", 1, 5)
1755
+ # # => Immutable::Vector["A", "Z", "Z", "Z", "Z", "Z"]
1756
+ #
1757
+ # @return [Vector]
1758
+ # @raise [IndexError] if index is out of negative range.
1759
+ def fill(object, index = 0, length = nil)
1760
+ raise IndexError if index < -@size
1761
+ index += @size if index < 0
1762
+ length ||= @size - index # to the end of the array, if no length given
1763
+
1764
+ if index < @size
1765
+ suffix = flatten_suffix(@root, @levels * BITS_PER_LEVEL, index, [])
1766
+ suffix.fill(object, 0, length)
1767
+ elsif index == @size
1768
+ suffix = Array.new(length, object)
1769
+ else
1770
+ suffix = Array.new(index - @size, nil).concat(Array.new(length, object))
1771
+ index = @size
1772
+ end
1773
+
1774
+ replace_suffix(index, suffix)
1775
+ end
1776
+
1777
+ # When invoked with a block, yields all combinations of length `n` of items
1778
+ # from the `Vector`, and then returns `self`. There is no guarantee about
1779
+ # which order the combinations will be yielded.
1780
+ #
1781
+ # If no block is given, an `Enumerator` is returned instead.
1782
+ #
1783
+ # @example
1784
+ # v = Immutable::Vector[5, 6, 7, 8]
1785
+ # v.combination(3) { |c| puts "Combination: #{c}" }
1786
+ #
1787
+ # Combination: [5, 6, 7]
1788
+ # Combination: [5, 6, 8]
1789
+ # Combination: [5, 7, 8]
1790
+ # Combination: [6, 7, 8]
1791
+ # #=> Immutable::Vector[5, 6, 7, 8]
1792
+ #
1793
+ # @return [self, Enumerator]
1794
+ def combination(n)
1795
+ return enum_for(:combination, n) if not block_given?
1796
+ return self if n < 0 || @size < n
1797
+ if n == 0
1798
+ yield []
1799
+ elsif n == 1
1800
+ each { |item| yield [item] }
1801
+ elsif n == @size
1802
+ yield to_a
1803
+ else
1804
+ combos = lambda do |result,index,remaining|
1805
+ while @size - index > remaining
1806
+ if remaining == 1
1807
+ yield result.dup << get(index)
1808
+ else
1809
+ combos[result.dup << get(index), index+1, remaining-1]
1810
+ end
1811
+ index += 1
1812
+ end
1813
+ index.upto(@size-1) { |i| result << get(i) }
1814
+ yield result
1815
+ end
1816
+ combos[[], 0, n]
1817
+ end
1818
+ self
1819
+ end
1820
+
1821
+ # When invoked with a block, yields all repeated combinations of length `n` of
1822
+ # items from the `Vector`, and then returns `self`. A "repeated combination" is
1823
+ # one in which any item from the `Vector` can appear consecutively any number of
1824
+ # times.
1825
+ #
1826
+ # There is no guarantee about which order the combinations will be yielded in.
1827
+ #
1828
+ # If no block is given, an `Enumerator` is returned instead.
1829
+ #
1830
+ # @example
1831
+ # v = Immutable::Vector[5, 6, 7, 8]
1832
+ # v.repeated_combination(2) { |c| puts "Combination: #{c}" }
1833
+ #
1834
+ # Combination: [5, 5]
1835
+ # Combination: [5, 6]
1836
+ # Combination: [5, 7]
1837
+ # Combination: [5, 8]
1838
+ # Combination: [6, 6]
1839
+ # Combination: [6, 7]
1840
+ # Combination: [6, 8]
1841
+ # Combination: [7, 7]
1842
+ # Combination: [7, 8]
1843
+ # Combination: [8, 8]
1844
+ # # => Immutable::Vector[5, 6, 7, 8]
1845
+ #
1846
+ # @return [self, Enumerator]
1847
+ def repeated_combination(n)
1848
+ return enum_for(:repeated_combination, n) if not block_given?
1849
+ if n < 0
1850
+ # yield nothing
1851
+ elsif n == 0
1852
+ yield []
1853
+ elsif n == 1
1854
+ each { |item| yield [item] }
1855
+ elsif @size == 0
1856
+ # yield nothing
1857
+ else
1858
+ combos = lambda do |result,index,remaining|
1859
+ while index < @size-1
1860
+ if remaining == 1
1861
+ yield result.dup << get(index)
1862
+ else
1863
+ combos[result.dup << get(index), index, remaining-1]
1864
+ end
1865
+ index += 1
1866
+ end
1867
+ item = get(index)
1868
+ remaining.times { result << item }
1869
+ yield result
1870
+ end
1871
+ combos[[], 0, n]
1872
+ end
1873
+ self
1874
+ end
1875
+
1876
+ # Yields all permutations of length `n` of items from the `Vector`, and then
1877
+ # returns `self`. If no length `n` is specified, permutations of all elements
1878
+ # will be yielded.
1879
+ #
1880
+ # There is no guarantee about which order the permutations will be yielded in.
1881
+ #
1882
+ # If no block is given, an `Enumerator` is returned instead.
1883
+ #
1884
+ # @example
1885
+ # v = Immutable::Vector[5, 6, 7]
1886
+ # v.permutation(2) { |p| puts "Permutation: #{p}" }
1887
+ #
1888
+ # Permutation: [5, 6]
1889
+ # Permutation: [5, 7]
1890
+ # Permutation: [6, 5]
1891
+ # Permutation: [6, 7]
1892
+ # Permutation: [7, 5]
1893
+ # Permutation: [7, 6]
1894
+ # # => Immutable::Vector[5, 6, 7]
1895
+ #
1896
+ # @return [self, Enumerator]
1897
+ def permutation(n = @size)
1898
+ return enum_for(:permutation, n) if not block_given?
1899
+ if n < 0 || @size < n
1900
+ # yield nothing
1901
+ elsif n == 0
1902
+ yield []
1903
+ elsif n == 1
1904
+ each { |item| yield [item] }
1905
+ else
1906
+ used, result = [], []
1907
+ perms = lambda do |index|
1908
+ 0.upto(@size-1) do |i|
1909
+ next if used[i]
1910
+ result[index] = get(i)
1911
+ if index < n-1
1912
+ used[i] = true
1913
+ perms[index+1]
1914
+ used[i] = false
1915
+ else
1916
+ yield result.dup
1917
+ end
1918
+ end
1919
+ end
1920
+ perms[0]
1921
+ end
1922
+ self
1923
+ end
1924
+
1925
+ # When invoked with a block, yields all repeated permutations of length `n` of
1926
+ # items from the `Vector`, and then returns `self`. A "repeated permutation" is
1927
+ # one where any item from the `Vector` can appear any number of times, and in
1928
+ # any position (not just consecutively)
1929
+ #
1930
+ # If no length `n` is specified, permutations of all elements will be yielded.
1931
+ # There is no guarantee about which order the permutations will be yielded in.
1932
+ #
1933
+ # If no block is given, an `Enumerator` is returned instead.
1934
+ #
1935
+ # @example
1936
+ # v = Immutable::Vector[5, 6, 7]
1937
+ # v.repeated_permutation(2) { |p| puts "Permutation: #{p}" }
1938
+ #
1939
+ # Permutation: [5, 5]
1940
+ # Permutation: [5, 6]
1941
+ # Permutation: [5, 7]
1942
+ # Permutation: [6, 5]
1943
+ # Permutation: [6, 6]
1944
+ # Permutation: [6, 7]
1945
+ # Permutation: [7, 5]
1946
+ # Permutation: [7, 6]
1947
+ # Permutation: [7, 7]
1948
+ # # => Immutable::Vector[5, 6, 7]
1949
+ #
1950
+ # @return [self, Enumerator]
1951
+ def repeated_permutation(n = @size)
1952
+ return enum_for(:repeated_permutation, n) if not block_given?
1953
+ if n < 0
1954
+ # yield nothing
1955
+ elsif n == 0
1956
+ yield []
1957
+ elsif n == 1
1958
+ each { |item| yield [item] }
1959
+ else
1960
+ result = []
1961
+ perms = lambda do |index|
1962
+ 0.upto(@size-1) do |i|
1963
+ result[index] = get(i)
1964
+ if index < n-1
1965
+ perms[index+1]
1966
+ else
1967
+ yield result.dup
1968
+ end
1969
+ end
1970
+ end
1971
+ perms[0]
1972
+ end
1973
+ self
1974
+ end
1975
+
1976
+ # Cartesian product or multiplication.
1977
+ #
1978
+ # @overload product(*vectors)
1979
+ # Return a `Vector` of all combinations of elements from this `Vector` and each
1980
+ # of the given vectors or arrays. The length of the returned `Vector` is the product
1981
+ # of `self.size` and the size of each argument vector or array.
1982
+ # @example
1983
+ # v1 = Immutable::Vector[1, 2, 3]
1984
+ # v2 = Immutable::Vector["A", "B"]
1985
+ # v1.product(v2)
1986
+ # # => [[1, "A"], [1, "B"], [2, "A"], [2, "B"], [3, "A"], [3, "B"]]
1987
+ # @overload product
1988
+ # Return the result of multiplying all the items in this `Vector` together.
1989
+ #
1990
+ # @example
1991
+ # Immutable::Vector[1, 2, 3, 4, 5].product # => 120
1992
+ #
1993
+ # @return [Vector]
1994
+ def product(*vectors)
1995
+ # if no vectors passed, return "product" as in result of multiplying all items
1996
+ return super if vectors.empty?
1997
+
1998
+ vectors.unshift(self)
1999
+
2000
+ if vectors.any?(&:empty?)
2001
+ return block_given? ? self : []
2002
+ end
2003
+
2004
+ counters = Array.new(vectors.size, 0)
2005
+
2006
+ bump_counters = lambda do
2007
+ i = vectors.size-1
2008
+ counters[i] += 1
2009
+ while counters[i] == vectors[i].size
2010
+ counters[i] = 0
2011
+ i -= 1
2012
+ return true if i == -1 # we are done
2013
+ counters[i] += 1
2014
+ end
2015
+ false # not done yet
2016
+ end
2017
+ build_array = lambda do
2018
+ array = []
2019
+ counters.each_with_index { |index,i| array << vectors[i][index] }
2020
+ array
2021
+ end
2022
+
2023
+ if block_given?
2024
+ loop do
2025
+ yield build_array[]
2026
+ return self if bump_counters[]
2027
+ end
2028
+ else
2029
+ result = []
2030
+ loop do
2031
+ result << build_array[]
2032
+ return result if bump_counters[]
2033
+ end
2034
+ end
2035
+ end
2036
+
2037
+ # Assume all elements are vectors or arrays and transpose the rows and columns.
2038
+ # In other words, take the first element of each nested vector/array and gather
2039
+ # them together into a new `Vector`. Do likewise for the second, third, and so on
2040
+ # down to the end of each nested vector/array. Gather all the resulting `Vectors`
2041
+ # into a new `Vector` and return it.
2042
+ #
2043
+ # This operation is closely related to {#zip}. The result is almost the same as
2044
+ # calling {#zip} on the first nested vector/array with the others supplied as
2045
+ # arguments.
2046
+ #
2047
+ # @example
2048
+ # Immutable::Vector[["A", 10], ["B", 20], ["C", 30]].transpose
2049
+ # # => Immutable::Vector[Immutable::Vector["A", "B", "C"], Immutable::Vector[10, 20, 30]]
2050
+ #
2051
+ # @return [Vector]
2052
+ # @raise [IndexError] if elements are not of the same size.
2053
+ # @raise [TypeError] if an element does not respond to #size and #[]
2054
+ def transpose
2055
+ return self.class.empty if empty?
2056
+ result = Array.new(first.size) { [] }
2057
+
2058
+ 0.upto(@size-1) do |i|
2059
+ source = get(i)
2060
+ if source.size != result.size
2061
+ raise IndexError, "element size differs (#{source.size} should be #{result.size})"
2062
+ end
2063
+
2064
+ 0.upto(result.size-1) do |j|
2065
+ result[j].push(source[j])
2066
+ end
2067
+ end
2068
+
2069
+ result.map! { |a| self.class.new(a) }
2070
+ self.class.new(result)
2071
+ rescue NoMethodError
2072
+ if any? { |x| !x.respond_to?(:size) || !x.respond_to?(:[]) }
2073
+ bad = find { |x| !x.respond_to?(:size) || !x.respond_to?(:[]) }
2074
+ raise TypeError, "'#{bad.inspect}' must respond to #size and #[] to be transposed"
2075
+ else
2076
+ raise
2077
+ end
2078
+ end
2079
+
2080
+ # Finds a value from this `Vector` which meets the condition defined by the
2081
+ # provided block, using a binary search. The vector must already be sorted
2082
+ # with respect to the block. See Ruby's `Array#bsearch` for details,
2083
+ # behaviour is equivalent.
2084
+ #
2085
+ # @example
2086
+ # v = Immutable::Vector[1, 3, 5, 7, 9, 11, 13]
2087
+ # # Block returns true/false for exact element match:
2088
+ # v.bsearch { |e| e > 4 } # => 5
2089
+ # # Block returns number to match an element in 4 <= e <= 7:
2090
+ # v.bsearch { |e| 1 - e / 4 } # => 7
2091
+ #
2092
+ # @yield Once for at most `log n` elements, where `n` is the size of the
2093
+ # vector. The exact elements and ordering are undefined.
2094
+ # @yieldreturn [Boolean] `true` if this element matches the criteria, `false` otherwise.
2095
+ # @yieldreturn [Integer] See `Array#bsearch` for details.
2096
+ # @yieldparam [Object] element element to be evaluated
2097
+ # @return [Object] The matched element, or `nil` if none found.
2098
+ # @raise TypeError if the block returns a non-numeric, non-boolean, non-nil
2099
+ # value.
2100
+ def bsearch
2101
+ return enum_for(:bsearch) if not block_given?
2102
+ low, high, result = 0, @size, nil
2103
+ while low < high
2104
+ mid = (low + ((high - low) >> 1))
2105
+ val = get(mid)
2106
+ v = yield val
2107
+ if v.is_a? Numeric
2108
+ if v == 0
2109
+ return val
2110
+ elsif v > 0
2111
+ high = mid
2112
+ else
2113
+ low = mid + 1
2114
+ end
2115
+ elsif v == true
2116
+ result = val
2117
+ high = mid
2118
+ elsif !v
2119
+ low = mid + 1
2120
+ else
2121
+ raise TypeError, "wrong argument type #{v.class} (must be numeric, true, false, or nil)"
2122
+ end
2123
+ end
2124
+ result
2125
+ end
2126
+
2127
+ # Return an empty `Vector` instance, of the same class as this one. Useful if you
2128
+ # have multiple subclasses of `Vector` and want to treat them polymorphically.
2129
+ #
2130
+ # @return [Vector]
2131
+ def clear
2132
+ self.class.empty
2133
+ end
2134
+
2135
+ # Return a randomly chosen item from this `Vector`. If the vector is empty, return `nil`.
2136
+ #
2137
+ # @example
2138
+ # Immutable::Vector[1, 2, 3, 4, 5].sample # => 2
2139
+ #
2140
+ # @return [Object]
2141
+ def sample
2142
+ get(rand(@size))
2143
+ end
2144
+
2145
+ # Return a new `Vector` with only the elements at the given `indices`, in the
2146
+ # order specified by `indices`. If any of the `indices` do not exist, `nil`s will
2147
+ # appear in their places.
2148
+ #
2149
+ # @example
2150
+ # v = Immutable::Vector["A", "B", "C", "D", "E", "F"]
2151
+ # v.values_at(2, 4, 5) # => Immutable::Vector["C", "E", "F"]
2152
+ #
2153
+ # @param indices [Array] The indices to retrieve and gather into a new `Vector`
2154
+ # @return [Vector]
2155
+ def values_at(*indices)
2156
+ self.class.new(indices.map { |i| get(i) }.freeze)
2157
+ end
2158
+
2159
+ # Find the index of an element, starting from the end of the vector.
2160
+ # Returns `nil` if no element is found.
2161
+ #
2162
+ # @overload rindex(obj)
2163
+ # Return the index of the last element which is `#==` to `obj`.
2164
+ #
2165
+ # @example
2166
+ # v = Immutable::Vector[7, 8, 9, 7, 8, 9]
2167
+ # v.rindex(8) # => 4
2168
+ #
2169
+ # @overload rindex
2170
+ # Return the index of the last element for which the block returns true.
2171
+ #
2172
+ # @yield [element] Once for each element, last to first, until the block
2173
+ # returns true.
2174
+ # @example
2175
+ # v = Immutable::Vector[7, 8, 9, 7, 8, 9]
2176
+ # v.rindex { |e| e.even? } # => 4
2177
+ #
2178
+ # @return [Integer]
2179
+ def rindex(obj = (missing_arg = true))
2180
+ i = @size - 1
2181
+ if missing_arg
2182
+ if block_given?
2183
+ reverse_each { |item| return i if yield item; i -= 1 }
2184
+ nil
2185
+ else
2186
+ enum_for(:rindex)
2187
+ end
2188
+ else
2189
+ reverse_each { |item| return i if item == obj; i -= 1 }
2190
+ nil
2191
+ end
2192
+ end
2193
+
2194
+ # Assumes all elements are nested, indexable collections, and searches through them,
2195
+ # comparing `obj` with the first element of each nested collection. Return the
2196
+ # first nested collection which matches, or `nil` if none is found.
2197
+ # Behaviour is undefined when elements do not meet assumptions (i.e. are
2198
+ # not indexable collections).
2199
+ #
2200
+ # @example
2201
+ # v = Immutable::Vector[["A", 10], ["B", 20], ["C", 30]]
2202
+ # v.assoc("B") # => ["B", 20]
2203
+ #
2204
+ # @param obj [Object] The object to search for
2205
+ # @return [Object]
2206
+ def assoc(obj)
2207
+ each do |array|
2208
+ next if !array.respond_to?(:[])
2209
+ return array if obj == array[0]
2210
+ end
2211
+ nil
2212
+ end
2213
+
2214
+ # Assumes all elements are nested, indexable collections, and searches through them,
2215
+ # comparing `obj` with the second element of each nested collection. Return
2216
+ # the first nested collection which matches, or `nil` if none is found.
2217
+ # Behaviour is undefined when elements do not meet assumptions (i.e. are
2218
+ # not indexable collections).
2219
+ #
2220
+ # @example
2221
+ # v = Immutable::Vector[["A", 10], ["B", 20], ["C", 30]]
2222
+ # v.rassoc(20) # => ["B", 20]
2223
+ #
2224
+ # @param obj [Object] The object to search for
2225
+ # @return [Object]
2226
+ def rassoc(obj)
2227
+ each do |array|
2228
+ next if !array.respond_to?(:[])
2229
+ return array if obj == array[1]
2230
+ end
2231
+ nil
2232
+ end
2233
+
2234
+ # Return an `Array` with the same elements, in the same order. The returned
2235
+ # `Array` may or may not be frozen.
2236
+ #
2237
+ # @return [Array]
2238
+ def to_a
2239
+ if @levels == 0
2240
+ # When initializing a Vector with 32 or less items, we always make
2241
+ # sure @root is frozen, so we can return it directly here
2242
+ @root
2243
+ else
2244
+ flatten_node(@root, @levels * BITS_PER_LEVEL, [])
2245
+ end
2246
+ end
2247
+ alias to_ary to_a
2248
+
2249
+ # Return true if `other` has the same type and contents as this `Vector`.
2250
+ #
2251
+ # @param other [Object] The collection to compare with
2252
+ # @return [Boolean]
2253
+ def eql?(other)
2254
+ return true if other.equal?(self)
2255
+ return false unless instance_of?(other.class) && @size == other.size
2256
+ @root.eql?(other.instance_variable_get(:@root))
2257
+ end
2258
+
2259
+ # See `Object#hash`.
2260
+ # @return [Integer]
2261
+ def hash
2262
+ reduce(0) { |hash, item| (hash << 5) - hash + item.hash }
2263
+ end
2264
+
2265
+ # Return `self`. Since this is an immutable object duplicates are
2266
+ # equivalent.
2267
+ # @return [Vector]
2268
+ def dup
2269
+ self
2270
+ end
2271
+ alias clone dup
2272
+
2273
+ # @return [::Array]
2274
+ # @private
2275
+ def marshal_dump
2276
+ to_a
2277
+ end
2278
+
2279
+ # @private
2280
+ def marshal_load(array)
2281
+ initialize(array.freeze)
2282
+ end
2283
+
2284
+ private
2285
+
2286
+ def traverse_depth_first(node, level, &block)
2287
+ return node.each(&block) if level == 0
2288
+ node.each { |child| traverse_depth_first(child, level - 1, &block) }
2289
+ end
2290
+
2291
+ def reverse_traverse_depth_first(node, level, &block)
2292
+ return node.reverse_each(&block) if level == 0
2293
+ node.reverse_each { |child| reverse_traverse_depth_first(child, level - 1, &block) }
2294
+ end
2295
+
2296
+ def leaf_node_for(node, bitshift, index)
2297
+ while bitshift > 0
2298
+ node = node[(index >> bitshift) & INDEX_MASK]
2299
+ bitshift -= BITS_PER_LEVEL
2300
+ end
2301
+ node
2302
+ end
2303
+
2304
+ def update_root(index, item)
2305
+ root, levels = @root, @levels
2306
+ while index >= (1 << (BITS_PER_LEVEL * (levels + 1)))
2307
+ root = [root].freeze
2308
+ levels += 1
2309
+ end
2310
+ new_root = update_leaf_node(root, levels * BITS_PER_LEVEL, index, item)
2311
+ if new_root.equal?(root)
2312
+ self
2313
+ else
2314
+ self.class.alloc(new_root, @size > index ? @size : index + 1, levels)
2315
+ end
2316
+ end
2317
+
2318
+ def update_leaf_node(node, bitshift, index, item)
2319
+ slot_index = (index >> bitshift) & INDEX_MASK
2320
+ if bitshift > 0
2321
+ old_child = node[slot_index] || []
2322
+ item = update_leaf_node(old_child, bitshift - BITS_PER_LEVEL, index, item)
2323
+ end
2324
+ existing_item = node[slot_index]
2325
+ if existing_item.equal?(item)
2326
+ node
2327
+ else
2328
+ node.dup.tap { |n| n[slot_index] = item }.freeze
2329
+ end
2330
+ end
2331
+
2332
+ def flatten_range(node, bitshift, from, to)
2333
+ from_slot = (from >> bitshift) & INDEX_MASK
2334
+ to_slot = (to >> bitshift) & INDEX_MASK
2335
+
2336
+ if bitshift == 0 # are we at the bottom?
2337
+ node.slice(from_slot, to_slot-from_slot+1)
2338
+ elsif from_slot == to_slot
2339
+ flatten_range(node[from_slot], bitshift - BITS_PER_LEVEL, from, to)
2340
+ else
2341
+ # the following bitmask can be used to pick out the part of the from/to indices
2342
+ # which will be used to direct path BELOW this node
2343
+ mask = ((1 << bitshift) - 1)
2344
+ result = []
2345
+
2346
+ if from & mask == 0
2347
+ flatten_node(node[from_slot], bitshift - BITS_PER_LEVEL, result)
2348
+ else
2349
+ result.concat(flatten_range(node[from_slot], bitshift - BITS_PER_LEVEL, from, from | mask))
2350
+ end
2351
+
2352
+ (from_slot+1).upto(to_slot-1) do |slot_index|
2353
+ flatten_node(node[slot_index], bitshift - BITS_PER_LEVEL, result)
2354
+ end
2355
+
2356
+ if to & mask == mask
2357
+ flatten_node(node[to_slot], bitshift - BITS_PER_LEVEL, result)
2358
+ else
2359
+ result.concat(flatten_range(node[to_slot], bitshift - BITS_PER_LEVEL, to & ~mask, to))
2360
+ end
2361
+
2362
+ result
2363
+ end
2364
+ end
2365
+
2366
+ def flatten_node(node, bitshift, result)
2367
+ if bitshift == 0
2368
+ result.concat(node)
2369
+ elsif bitshift == BITS_PER_LEVEL
2370
+ node.each { |a| result.concat(a) }
2371
+ else
2372
+ bitshift -= BITS_PER_LEVEL
2373
+ node.each { |a| flatten_node(a, bitshift, result) }
2374
+ end
2375
+ result
2376
+ end
2377
+
2378
+ def subsequence(from, length)
2379
+ return nil if from > @size || from < 0 || length < 0
2380
+ length = @size - from if @size < from + length
2381
+ return self.class.empty if length == 0
2382
+ self.class.new(flatten_range(@root, @levels * BITS_PER_LEVEL, from, from + length - 1))
2383
+ end
2384
+
2385
+ def flatten_suffix(node, bitshift, from, result)
2386
+ from_slot = (from >> bitshift) & INDEX_MASK
2387
+
2388
+ if bitshift == 0
2389
+ if from_slot == 0
2390
+ result.concat(node)
2391
+ else
2392
+ result.concat(node.slice(from_slot, 32)) # entire suffix of node. excess length is ignored by #slice
2393
+ end
2394
+ else
2395
+ mask = ((1 << bitshift) - 1)
2396
+ if from & mask == 0
2397
+ from_slot.upto(node.size-1) do |i|
2398
+ flatten_node(node[i], bitshift - BITS_PER_LEVEL, result)
2399
+ end
2400
+ elsif (child = node[from_slot])
2401
+ flatten_suffix(child, bitshift - BITS_PER_LEVEL, from, result)
2402
+ (from_slot+1).upto(node.size-1) do |i|
2403
+ flatten_node(node[i], bitshift - BITS_PER_LEVEL, result)
2404
+ end
2405
+ end
2406
+ result
2407
+ end
2408
+ end
2409
+
2410
+ def replace_suffix(from, suffix)
2411
+ # new suffix can go directly after existing elements
2412
+ raise IndexError if from > @size
2413
+ root, levels = @root, @levels
2414
+
2415
+ if (from >> (BITS_PER_LEVEL * (@levels + 1))) != 0
2416
+ # index where new suffix goes doesn't fall within current tree
2417
+ # we will need to deepen tree
2418
+ root = [root].freeze
2419
+ levels += 1
2420
+ end
2421
+
2422
+ new_size = from + suffix.size
2423
+ root = replace_node_suffix(root, levels * BITS_PER_LEVEL, from, suffix)
2424
+
2425
+ if !suffix.empty?
2426
+ levels.times { suffix = suffix.each_slice(32).to_a }
2427
+ root.concat(suffix)
2428
+ while root.size > 32
2429
+ root = root.each_slice(32).to_a
2430
+ levels += 1
2431
+ end
2432
+ else
2433
+ while root.size == 1 && levels > 0
2434
+ root = root[0]
2435
+ levels -= 1
2436
+ end
2437
+ end
2438
+
2439
+ self.class.alloc(root.freeze, new_size, levels)
2440
+ end
2441
+
2442
+ def replace_node_suffix(node, bitshift, from, suffix)
2443
+ from_slot = (from >> bitshift) & INDEX_MASK
2444
+
2445
+ if bitshift == 0
2446
+ if from_slot == 0
2447
+ suffix.shift(32)
2448
+ else
2449
+ node.take(from_slot).concat(suffix.shift(32 - from_slot))
2450
+ end
2451
+ else
2452
+ mask = ((1 << bitshift) - 1)
2453
+ if from & mask == 0
2454
+ if from_slot == 0
2455
+ new_node = suffix.shift(32 * (1 << bitshift))
2456
+ while bitshift != 0
2457
+ new_node = new_node.each_slice(32).to_a
2458
+ bitshift -= BITS_PER_LEVEL
2459
+ end
2460
+ new_node
2461
+ else
2462
+ result = node.take(from_slot)
2463
+ remainder = suffix.shift((32 - from_slot) * (1 << bitshift))
2464
+ while bitshift != 0
2465
+ remainder = remainder.each_slice(32).to_a
2466
+ bitshift -= BITS_PER_LEVEL
2467
+ end
2468
+ result.concat(remainder)
2469
+ end
2470
+ elsif (child = node[from_slot])
2471
+ result = node.take(from_slot)
2472
+ result.push(replace_node_suffix(child, bitshift - BITS_PER_LEVEL, from, suffix))
2473
+ remainder = suffix.shift((31 - from_slot) * (1 << bitshift))
2474
+ while bitshift != 0
2475
+ remainder = remainder.each_slice(32).to_a
2476
+ bitshift -= BITS_PER_LEVEL
2477
+ end
2478
+ result.concat(remainder)
2479
+ else
2480
+ raise "Shouldn't happen"
2481
+ end
2482
+ end
2483
+ end
2484
+ end
2485
+
2486
+ # The canonical empty `Vector`. Returned by `Vector[]` when
2487
+ # invoked with no arguments; also returned by `Vector.empty`. Prefer using this
2488
+ # one rather than creating many empty vectors using `Vector.new`.
2489
+ #
2490
+ # @private
2491
+ EmptyVector = Immutable::Vector.empty
2492
+
2493
+
2494
+ # `Immutable::Set` is a collection of unordered values with no duplicates. Testing whether
2495
+ # an object is present in the `Set` can be done in constant time. `Set` is also `Enumerable`, so you can
2496
+ # iterate over the members of the set with {#each}, transform them with {#map}, filter
2497
+ # them with {#select}, and so on. Some of the `Enumerable` methods are overridden to
2498
+ # return `immutable-ruby` collections.
2499
+ #
2500
+ # Like the `Set` class in Ruby's standard library, which we will call RubySet,
2501
+ # `Immutable::Set` defines equivalency of objects using `#hash` and `#eql?`. No two
2502
+ # objects with the same `#hash` code, and which are also `#eql?`, can coexist in the
2503
+ # same `Set`. If one is already in the `Set`, attempts to add another one will have
2504
+ # no effect.
2505
+ #
2506
+ # `Set`s have no natural ordering and cannot be compared using `#<=>`. However, they
2507
+ # define {#<}, {#>}, {#<=}, and {#>=} as shorthand for {#proper_subset?},
2508
+ # {#proper_superset?}, {#subset?}, and {#superset?} respectively.
2509
+ #
2510
+ # The basic set-theoretic operations {#union}, {#intersection}, {#difference}, and
2511
+ # {#exclusion} work with any `Enumerable` object.
2512
+ #
2513
+ # A `Set` can be created in either of the following ways:
2514
+ #
2515
+ # Immutable::Set.new([1, 2, 3]) # any Enumerable can be used to initialize
2516
+ # Immutable::Set['A', 'B', 'C', 'D']
2517
+ #
2518
+ # The latter 2 forms of initialization can be used with your own, custom subclasses
2519
+ # of `Immutable::Set`.
2520
+ #
2521
+ # Unlike RubySet, all methods which you might expect to "modify" an `Immutable::Set`
2522
+ # actually return a new set and leave the existing one unchanged.
2523
+ #
2524
+ # @example
2525
+ # set1 = Immutable::Set[1, 2] # => Immutable::Set[1, 2]
2526
+ # set2 = Immutable::Set[1, 2] # => Immutable::Set[1, 2]
2527
+ # set1 == set2 # => true
2528
+ # set3 = set1.add("foo") # => Immutable::Set[1, 2, "foo"]
2529
+ # set3 - set2 # => Immutable::Set["foo"]
2530
+ # set3.subset?(set1) # => false
2531
+ # set1.subset?(set3) # => true
2532
+ #
2533
+ class Set
2534
+ include Immutable::Enumerable
2535
+
2536
+ class << self
2537
+ # Create a new `Set` populated with the given items.
2538
+ # @return [Set]
2539
+ def [](*items)
2540
+ items.empty? ? empty : new(items)
2541
+ end
2542
+
2543
+ # Return an empty `Set`. If used on a subclass, returns an empty instance
2544
+ # of that class.
2545
+ #
2546
+ # @return [Set]
2547
+ def empty
2548
+ @empty ||= new
2549
+ end
2550
+
2551
+ # "Raw" allocation of a new `Set`. Used internally to create a new
2552
+ # instance quickly after obtaining a modified {Trie}.
2553
+ #
2554
+ # @return [Set]
2555
+ # @private
2556
+ def alloc(trie = EmptyTrie)
2557
+ allocate.tap { |s| s.instance_variable_set(:@trie, trie) }.freeze
2558
+ end
2559
+ end
2560
+
2561
+ def initialize(items=[])
2562
+ @trie = Trie.new(0)
2563
+ items.each { |item| @trie.put!(item, nil) }
2564
+ freeze
2565
+ end
2566
+
2567
+ # Return `true` if this `Set` contains no items.
2568
+ # @return [Boolean]
2569
+ def empty?
2570
+ @trie.empty?
2571
+ end
2572
+
2573
+ # Return the number of items in this `Set`.
2574
+ # @return [Integer]
2575
+ def size
2576
+ @trie.size
2577
+ end
2578
+ alias length size
2579
+
2580
+ # Return a new `Set` with `item` added. If `item` is already in the set,
2581
+ # return `self`.
2582
+ #
2583
+ # @example
2584
+ # Immutable::Set[1, 2, 3].add(4) # => Immutable::Set[1, 2, 4, 3]
2585
+ # Immutable::Set[1, 2, 3].add(2) # => Immutable::Set[1, 2, 3]
2586
+ #
2587
+ # @param item [Object] The object to add
2588
+ # @return [Set]
2589
+ def add(item)
2590
+ include?(item) ? self : self.class.alloc(@trie.put(item, nil))
2591
+ end
2592
+ alias << add
2593
+
2594
+ # If `item` is not a member of this `Set`, return a new `Set` with `item` added.
2595
+ # Otherwise, return `false`.
2596
+ #
2597
+ # @example
2598
+ # Immutable::Set[1, 2, 3].add?(4) # => Immutable::Set[1, 2, 4, 3]
2599
+ # Immutable::Set[1, 2, 3].add?(2) # => false
2600
+ #
2601
+ # @param item [Object] The object to add
2602
+ # @return [Set, false]
2603
+ def add?(item)
2604
+ !include?(item) && add(item)
2605
+ end
2606
+
2607
+ # Return a new `Set` with `item` removed. If `item` is not a member of the set,
2608
+ # return `self`.
2609
+ #
2610
+ # @example
2611
+ # Immutable::Set[1, 2, 3].delete(1) # => Immutable::Set[2, 3]
2612
+ # Immutable::Set[1, 2, 3].delete(99) # => Immutable::Set[1, 2, 3]
2613
+ #
2614
+ # @param item [Object] The object to remove
2615
+ # @return [Set]
2616
+ def delete(item)
2617
+ trie = @trie.delete(item)
2618
+ new_trie(trie)
2619
+ end
2620
+
2621
+ # If `item` is a member of this `Set`, return a new `Set` with `item` removed.
2622
+ # Otherwise, return `false`.
2623
+ #
2624
+ # @example
2625
+ # Immutable::Set[1, 2, 3].delete?(1) # => Immutable::Set[2, 3]
2626
+ # Immutable::Set[1, 2, 3].delete?(99) # => false
2627
+ #
2628
+ # @param item [Object] The object to remove
2629
+ # @return [Set, false]
2630
+ def delete?(item)
2631
+ include?(item) && delete(item)
2632
+ end
2633
+
2634
+ # Call the block once for each item in this `Set`. No specific iteration order
2635
+ # is guaranteed, but the order will be stable for any particular `Set`. If
2636
+ # no block is given, an `Enumerator` is returned instead.
2637
+ #
2638
+ # @example
2639
+ # Immutable::Set["Dog", "Elephant", "Lion"].each { |e| puts e }
2640
+ # Elephant
2641
+ # Dog
2642
+ # Lion
2643
+ # # => Immutable::Set["Dog", "Elephant", "Lion"]
2644
+ #
2645
+ # @yield [item] Once for each item.
2646
+ # @return [self, Enumerator]
2647
+ def each
2648
+ return to_enum if not block_given?
2649
+ @trie.each { |key, _| yield(key) }
2650
+ self
2651
+ end
2652
+
2653
+ # Call the block once for each item in this `Set`. Iteration order will be
2654
+ # the opposite of {#each}. If no block is given, an `Enumerator` is
2655
+ # returned instead.
2656
+ #
2657
+ # @example
2658
+ # Immutable::Set["Dog", "Elephant", "Lion"].reverse_each { |e| puts e }
2659
+ # Lion
2660
+ # Dog
2661
+ # Elephant
2662
+ # # => Immutable::Set["Dog", "Elephant", "Lion"]
2663
+ #
2664
+ # @yield [item] Once for each item.
2665
+ # @return [self]
2666
+ def reverse_each
2667
+ return enum_for(:reverse_each) if not block_given?
2668
+ @trie.reverse_each { |key, _| yield(key) }
2669
+ self
2670
+ end
2671
+
2672
+ # Return a new `Set` with all the items for which the block returns true.
2673
+ #
2674
+ # @example
2675
+ # Immutable::Set["Elephant", "Dog", "Lion"].select { |e| e.size >= 4 }
2676
+ # # => Immutable::Set["Elephant", "Lion"]
2677
+ # @yield [item] Once for each item.
2678
+ # @return [Set]
2679
+ def select
2680
+ return enum_for(:select) unless block_given?
2681
+ trie = @trie.select { |key, _| yield(key) }
2682
+ new_trie(trie)
2683
+ end
2684
+ alias find_all select
2685
+ alias keep_if select
2686
+
2687
+ # Call the block once for each item in this `Set`. All the values returned
2688
+ # from the block will be gathered into a new `Set`. If no block is given,
2689
+ # an `Enumerator` is returned instead.
2690
+ #
2691
+ # @example
2692
+ # Immutable::Set["Cat", "Elephant", "Dog", "Lion"].map { |e| e.size }
2693
+ # # => Immutable::Set[8, 4, 3]
2694
+ #
2695
+ # @yield [item] Once for each item.
2696
+ # @return [Set]
2697
+ def map
2698
+ return enum_for(:map) if not block_given?
2699
+ return self if empty?
2700
+ self.class.new(super)
2701
+ end
2702
+ alias collect map
2703
+
2704
+ # Return `true` if the given item is present in this `Set`. More precisely,
2705
+ # return `true` if an object with the same `#hash` code, and which is also `#eql?`
2706
+ # to the given object is present.
2707
+ #
2708
+ # @example
2709
+ # Immutable::Set["A", "B", "C"].include?("B") # => true
2710
+ # Immutable::Set["A", "B", "C"].include?("Z") # => false
2711
+ #
2712
+ # @param object [Object] The object to check for
2713
+ # @return [Boolean]
2714
+ def include?(object)
2715
+ @trie.key?(object)
2716
+ end
2717
+ alias member? include?
2718
+
2719
+ # Return a member of this `Set`. The member chosen will be the first one which
2720
+ # would be yielded by {#each}. If the set is empty, return `nil`.
2721
+ #
2722
+ # @example
2723
+ # Immutable::Set["A", "B", "C"].first # => "C"
2724
+ #
2725
+ # @return [Object]
2726
+ def first
2727
+ (entry = @trie.at(0)) && entry[0]
2728
+ end
2729
+
2730
+ # Return a {SortedSet} which contains the same items as this `Set`, ordered by
2731
+ # the given comparator block.
2732
+ #
2733
+ # @example
2734
+ # Immutable::Set["Elephant", "Dog", "Lion"].sort
2735
+ # # => Immutable::SortedSet["Dog", "Elephant", "Lion"]
2736
+ # Immutable::Set["Elephant", "Dog", "Lion"].sort { |a,b| a.size <=> b.size }
2737
+ # # => Immutable::SortedSet["Dog", "Lion", "Elephant"]
2738
+ #
2739
+ # @yield [a, b] Any number of times with different pairs of elements.
2740
+ # @yieldreturn [Integer] Negative if the first element should be sorted
2741
+ # lower, positive if the latter element, or 0 if
2742
+ # equal.
2743
+ # @return [SortedSet]
2744
+ def sort(&comparator)
2745
+ SortedSet.new(to_a, &comparator)
2746
+ end
2747
+
2748
+ # Return a {SortedSet} which contains the same items as this `Set`, ordered
2749
+ # by mapping each item through the provided block to obtain sort keys, and
2750
+ # then sorting the keys.
2751
+ #
2752
+ # @example
2753
+ # Immutable::Set["Elephant", "Dog", "Lion"].sort_by { |e| e.size }
2754
+ # # => Immutable::SortedSet["Dog", "Lion", "Elephant"]
2755
+ #
2756
+ # @yield [item] Once for each item to create the set, and then potentially
2757
+ # again depending on what operations are performed on the
2758
+ # returned {SortedSet}. As such, it is recommended that the
2759
+ # block be a pure function.
2760
+ # @yieldreturn [Object] sort key for the item
2761
+ # @return [SortedSet]
2762
+ def sort_by(&mapper)
2763
+ SortedSet.new(to_a, &mapper)
2764
+ end
2765
+
2766
+ # Return a new `Set` which contains all the members of both this `Set` and `other`.
2767
+ # `other` can be any `Enumerable` object.
2768
+ #
2769
+ # @example
2770
+ # Immutable::Set[1, 2] | Immutable::Set[2, 3] # => Immutable::Set[1, 2, 3]
2771
+ #
2772
+ # @param other [Enumerable] The collection to merge with
2773
+ # @return [Set]
2774
+ def union(other)
2775
+ if other.is_a?(Immutable::Set)
2776
+ if other.size > size
2777
+ small_set_pairs = @trie
2778
+ large_set_trie = other.instance_variable_get(:@trie)
2779
+ else
2780
+ small_set_pairs = other.instance_variable_get(:@trie)
2781
+ large_set_trie = @trie
2782
+ end
2783
+ else
2784
+ if other.respond_to?(:lazy)
2785
+ small_set_pairs = other.lazy.map { |e| [e, nil] }
2786
+ else
2787
+ small_set_pairs = other.map { |e| [e, nil] }
2788
+ end
2789
+ large_set_trie = @trie
2790
+ end
2791
+
2792
+ trie = large_set_trie.bulk_put(small_set_pairs)
2793
+ new_trie(trie)
2794
+ end
2795
+ alias | union
2796
+ alias + union
2797
+ alias merge union
2798
+
2799
+ # Return a new `Set` which contains all the items which are members of both
2800
+ # this `Set` and `other`. `other` can be any `Enumerable` object.
2801
+ #
2802
+ # @example
2803
+ # Immutable::Set[1, 2] & Immutable::Set[2, 3] # => Immutable::Set[2]
2804
+ #
2805
+ # @param other [Enumerable] The collection to intersect with
2806
+ # @return [Set]
2807
+ def intersection(other)
2808
+ if other.size < @trie.size
2809
+ if other.is_a?(Immutable::Set)
2810
+ trie = other.instance_variable_get(:@trie).select { |key, _| include?(key) }
2811
+ else
2812
+ trie = Trie.new(0)
2813
+ other.each { |obj| trie.put!(obj, nil) if include?(obj) }
2814
+ end
2815
+ else
2816
+ trie = @trie.select { |key, _| other.include?(key) }
2817
+ end
2818
+ new_trie(trie)
2819
+ end
2820
+ alias & intersection
2821
+
2822
+ # Return a new `Set` with all the items in `other` removed. `other` can be
2823
+ # any `Enumerable` object.
2824
+ #
2825
+ # @example
2826
+ # Immutable::Set[1, 2] - Immutable::Set[2, 3] # => Immutable::Set[1]
2827
+ #
2828
+ # @param other [Enumerable] The collection to subtract from this set
2829
+ # @return [Set]
2830
+ def difference(other)
2831
+ trie = if (@trie.size <= other.size) && (other.is_a?(Immutable::Set) || (defined?(::Set) && other.is_a?(::Set)))
2832
+ @trie.select { |key, _| !other.include?(key) }
2833
+ else
2834
+ @trie.bulk_delete(other)
2835
+ end
2836
+ new_trie(trie)
2837
+ end
2838
+ alias subtract difference
2839
+ alias - difference
2840
+
2841
+ # Return a new `Set` which contains all the items which are members of this
2842
+ # `Set` or of `other`, but not both. `other` can be any `Enumerable` object.
2843
+ #
2844
+ # @example
2845
+ # Immutable::Set[1, 2] ^ Immutable::Set[2, 3] # => Immutable::Set[1, 3]
2846
+ #
2847
+ # @param other [Enumerable] The collection to take the exclusive disjunction of
2848
+ # @return [Set]
2849
+ def exclusion(other)
2850
+ ((self | other) - (self & other))
2851
+ end
2852
+ alias ^ exclusion
2853
+
2854
+ # Return `true` if all items in this `Set` are also in `other`.
2855
+ #
2856
+ # @example
2857
+ # Immutable::Set[2, 3].subset?(Immutable::Set[1, 2, 3]) # => true
2858
+ #
2859
+ # @param other [Set]
2860
+ # @return [Boolean]
2861
+ def subset?(other)
2862
+ return false if other.size < size
2863
+
2864
+ # This method has the potential to be very slow if 'other' is a large Array, so to avoid that,
2865
+ # we convert those Arrays to Sets before checking presence of items
2866
+ # Time to convert Array -> Set is linear in array.size
2867
+ # Time to check for presence of all items in an Array is proportional to set.size * array.size
2868
+ # Note that both sides of that equation have array.size -- hence those terms cancel out,
2869
+ # and the break-even point is solely dependent on the size of this collection
2870
+ # After doing some benchmarking to estimate the constants, it appears break-even is at ~190 items
2871
+ # We also check other.size, to avoid the more expensive #is_a? checks in cases where it doesn't matter
2872
+ #
2873
+ if other.size >= 150 && @trie.size >= 190 && !(other.is_a?(Immutable::Set) || other.is_a?(::Set))
2874
+ other = ::Set.new(other)
2875
+ end
2876
+ all? { |item| other.include?(item) }
2877
+ end
2878
+ alias <= subset?
2879
+
2880
+ # Return `true` if all items in `other` are also in this `Set`.
2881
+ #
2882
+ # @example
2883
+ # Immutable::Set[1, 2, 3].superset?(Immutable::Set[2, 3]) # => true
2884
+ #
2885
+ # @param other [Set]
2886
+ # @return [Boolean]
2887
+ def superset?(other)
2888
+ other.subset?(self)
2889
+ end
2890
+ alias >= superset?
2891
+
2892
+ # Returns `true` if `other` contains all the items in this `Set`, plus at least
2893
+ # one item which is not in this set.
2894
+ #
2895
+ # @example
2896
+ # Immutable::Set[2, 3].proper_subset?(Immutable::Set[1, 2, 3]) # => true
2897
+ # Immutable::Set[1, 2, 3].proper_subset?(Immutable::Set[1, 2, 3]) # => false
2898
+ #
2899
+ # @param other [Set]
2900
+ # @return [Boolean]
2901
+ def proper_subset?(other)
2902
+ return false if other.size <= size
2903
+ # See comments above
2904
+ if other.size >= 150 && @trie.size >= 190 && !(other.is_a?(Immutable::Set) || other.is_a?(::Set))
2905
+ other = ::Set.new(other)
2906
+ end
2907
+ all? { |item| other.include?(item) }
2908
+ end
2909
+ alias < proper_subset?
2910
+
2911
+ # Returns `true` if this `Set` contains all the items in `other`, plus at least
2912
+ # one item which is not in `other`.
2913
+ #
2914
+ # @example
2915
+ # Immutable::Set[1, 2, 3].proper_superset?(Immutable::Set[2, 3]) # => true
2916
+ # Immutable::Set[1, 2, 3].proper_superset?(Immutable::Set[1, 2, 3]) # => false
2917
+ #
2918
+ # @param other [Set]
2919
+ # @return [Boolean]
2920
+ def proper_superset?(other)
2921
+ other.proper_subset?(self)
2922
+ end
2923
+ alias > proper_superset?
2924
+
2925
+ # Return `true` if this `Set` and `other` do not share any items.
2926
+ #
2927
+ # @example
2928
+ # Immutable::Set[1, 2].disjoint?(Immutable::Set[8, 9]) # => true
2929
+ #
2930
+ # @param other [Set]
2931
+ # @return [Boolean]
2932
+ def disjoint?(other)
2933
+ if other.size <= size
2934
+ other.each { |item| return false if include?(item) }
2935
+ else
2936
+ # See comment on #subset?
2937
+ if other.size >= 150 && @trie.size >= 190 && !(other.is_a?(Immutable::Set) || other.is_a?(::Set))
2938
+ other = ::Set.new(other)
2939
+ end
2940
+ each { |item| return false if other.include?(item) }
2941
+ end
2942
+ true
2943
+ end
2944
+
2945
+ # Return `true` if this `Set` and `other` have at least one item in common.
2946
+ #
2947
+ # @example
2948
+ # Immutable::Set[1, 2].intersect?(Immutable::Set[2, 3]) # => true
2949
+ #
2950
+ # @param other [Set]
2951
+ # @return [Boolean]
2952
+ def intersect?(other)
2953
+ !disjoint?(other)
2954
+ end
2955
+
2956
+ # Recursively insert the contents of any nested `Set`s into this `Set`, and
2957
+ # remove them.
2958
+ #
2959
+ # @example
2960
+ # Immutable::Set[Immutable::Set[1, 2], Immutable::Set[3, 4]].flatten
2961
+ # # => Immutable::Set[1, 2, 3, 4]
2962
+ #
2963
+ # @return [Set]
2964
+ def flatten
2965
+ reduce(self.class.empty) do |set, item|
2966
+ next set.union(item.flatten) if item.is_a?(Set)
2967
+ set.add(item)
2968
+ end
2969
+ end
2970
+
2971
+ alias group group_by
2972
+ alias classify group_by
2973
+
2974
+ # Return a randomly chosen item from this `Set`. If the set is empty, return `nil`.
2975
+ #
2976
+ # @example
2977
+ # Immutable::Set[1, 2, 3, 4, 5].sample # => 3
2978
+ #
2979
+ # @return [Object]
2980
+ def sample
2981
+ empty? ? nil : @trie.at(rand(size))[0]
2982
+ end
2983
+
2984
+ # Return an empty `Set` instance, of the same class as this one. Useful if you
2985
+ # have multiple subclasses of `Set` and want to treat them polymorphically.
2986
+ #
2987
+ # @return [Set]
2988
+ def clear
2989
+ self.class.empty
2990
+ end
2991
+
2992
+ # Return true if `other` has the same type and contents as this `Set`.
2993
+ #
2994
+ # @param other [Object] The object to compare with
2995
+ # @return [Boolean]
2996
+ def eql?(other)
2997
+ return true if other.equal?(self)
2998
+ return false if not instance_of?(other.class)
2999
+ other_trie = other.instance_variable_get(:@trie)
3000
+ return false if @trie.size != other_trie.size
3001
+ @trie.each do |key, _|
3002
+ return false if !other_trie.key?(key)
3003
+ end
3004
+ true
3005
+ end
3006
+ alias == eql?
3007
+
3008
+ # See `Object#hash`.
3009
+ # @return [Integer]
3010
+ def hash
3011
+ reduce(0) { |hash, item| (hash << 5) - hash + item.hash }
3012
+ end
3013
+
3014
+ # Return `self`. Since this is an immutable object duplicates are
3015
+ # equivalent.
3016
+ # @return [Set]
3017
+ def dup
3018
+ self
3019
+ end
3020
+ alias clone dup
3021
+
3022
+ undef :"<=>" # Sets are not ordered, so Enumerable#<=> will give a meaningless result
3023
+ undef :each_index # Set members cannot be accessed by 'index', so #each_index is not meaningful
3024
+
3025
+ # Return `self`.
3026
+ #
3027
+ # @return [self]
3028
+ def to_set
3029
+ self
3030
+ end
3031
+
3032
+ # @private
3033
+ def marshal_dump
3034
+ output = {}
3035
+ each do |key|
3036
+ output[key] = nil
3037
+ end
3038
+ output
3039
+ end
3040
+
3041
+ # @private
3042
+ def marshal_load(dictionary)
3043
+ @trie = dictionary.reduce(EmptyTrie) do |trie, key_value|
3044
+ trie.put(key_value.first, nil)
3045
+ end
3046
+ end
3047
+
3048
+ private
3049
+
3050
+ def new_trie(trie)
3051
+ if trie.empty?
3052
+ self.class.empty
3053
+ elsif trie.equal?(@trie)
3054
+ self
3055
+ else
3056
+ self.class.alloc(trie)
3057
+ end
3058
+ end
3059
+ end
3060
+
3061
+ # The canonical empty `Set`. Returned by `Set[]` when
3062
+ # invoked with no arguments; also returned by `Set.empty`. Prefer using this
3063
+ # one rather than creating many empty sets using `Set.new`.
3064
+ #
3065
+ # @private
3066
+ EmptySet = Immutable::Set.empty
3067
+ end