immutable-ruby 0.0.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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