hamster 1.0.0 → 1.0.1.pre.rc.1

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