hamster 1.0.1.pre.rc2 → 1.0.1.pre.rc3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/hamster.rb +2 -2
- data/lib/hamster/core_ext.rb +0 -1
- data/lib/hamster/core_ext/enumerable.rb +17 -17
- data/lib/hamster/core_ext/io.rb +15 -17
- data/lib/hamster/deque.rb +229 -0
- data/lib/hamster/enumerable.rb +147 -105
- data/lib/hamster/experimental/mutable_queue.rb +2 -2
- data/lib/hamster/hash.rb +488 -82
- data/lib/hamster/immutable.rb +4 -0
- data/lib/hamster/list.rb +839 -196
- data/lib/hamster/read_copy_update.rb +1 -0
- data/lib/hamster/set.rb +317 -54
- data/lib/hamster/sorted_set.rb +1014 -0
- data/lib/hamster/trie.rb +67 -47
- data/lib/hamster/undefined.rb +1 -3
- data/lib/hamster/vector.rb +989 -76
- data/lib/hamster/version.rb +1 -1
- data/spec/{hamster → lib/hamster}/core_ext/array_spec.rb +1 -1
- data/spec/{hamster → lib/hamster}/core_ext/enumerable_spec.rb +4 -0
- data/spec/{hamster → lib/hamster}/core_ext/io_spec.rb +0 -0
- data/spec/lib/hamster/deque/clear_spec.rb +34 -0
- data/spec/lib/hamster/deque/construction_spec.rb +30 -0
- data/spec/lib/hamster/deque/copying_spec.rb +20 -0
- data/spec/lib/hamster/deque/dequeue_spec.rb +27 -0
- data/spec/lib/hamster/deque/empty_spec.rb +42 -0
- data/spec/{hamster/queue → lib/hamster/deque}/enqueue_spec.rb +7 -10
- data/spec/lib/hamster/deque/head_spec.rb +20 -0
- data/spec/lib/hamster/deque/inspect_spec.rb +24 -0
- data/spec/lib/hamster/deque/last_spec.rb +20 -0
- data/spec/lib/hamster/deque/marshal_spec.rb +34 -0
- data/spec/lib/hamster/deque/new_spec.rb +44 -0
- data/spec/lib/hamster/deque/pop_spec.rb +25 -0
- data/spec/lib/hamster/deque/random_modification_spec.rb +34 -0
- data/spec/{hamster/queue → lib/hamster/deque}/size_spec.rb +4 -9
- data/spec/lib/hamster/deque/to_a_spec.rb +27 -0
- data/spec/{hamster/queue → lib/hamster/deque}/to_ary_spec.rb +6 -6
- data/spec/lib/hamster/deque/to_list_spec.rb +26 -0
- data/spec/lib/hamster/deque/unshift_spec.rb +26 -0
- data/spec/{hamster → lib/hamster}/experimental/mutable_set/add_qm_spec.rb +0 -0
- data/spec/{hamster → lib/hamster}/experimental/mutable_set/add_spec.rb +0 -0
- data/spec/{hamster → lib/hamster}/experimental/mutable_set/delete_qm_spec.rb +0 -0
- data/spec/{hamster → lib/hamster}/experimental/mutable_set/delete_spec.rb +0 -0
- data/spec/{hamster → lib/hamster}/hash/all_spec.rb +10 -0
- data/spec/lib/hamster/hash/any_spec.rb +56 -0
- data/spec/lib/hamster/hash/assoc_spec.rb +52 -0
- data/spec/lib/hamster/hash/clear_spec.rb +43 -0
- data/spec/lib/hamster/hash/construction_spec.rb +39 -0
- data/spec/{hamster → lib/hamster}/hash/copying_spec.rb +2 -4
- data/spec/lib/hamster/hash/default_proc_spec.rb +73 -0
- data/spec/lib/hamster/hash/delete_spec.rb +40 -0
- data/spec/lib/hamster/hash/each_spec.rb +78 -0
- data/spec/lib/hamster/hash/each_with_index_spec.rb +30 -0
- data/spec/lib/hamster/hash/empty_spec.rb +46 -0
- data/spec/lib/hamster/hash/eql_spec.rb +70 -0
- data/spec/lib/hamster/hash/except_spec.rb +43 -0
- data/spec/lib/hamster/hash/fetch_spec.rb +58 -0
- data/spec/lib/hamster/hash/filter_spec.rb +58 -0
- data/spec/lib/hamster/hash/find_spec.rb +44 -0
- data/spec/lib/hamster/hash/flat_map_spec.rb +36 -0
- data/spec/lib/hamster/hash/flatten_spec.rb +99 -0
- data/spec/lib/hamster/hash/get_spec.rb +80 -0
- data/spec/lib/hamster/hash/has_key_spec.rb +32 -0
- data/spec/lib/hamster/hash/has_value_spec.rb +28 -0
- data/spec/{hamster → lib/hamster}/hash/hash_spec.rb +5 -12
- data/spec/{hamster → lib/hamster}/hash/immutable_spec.rb +0 -0
- data/spec/lib/hamster/hash/inspect_spec.rb +31 -0
- data/spec/lib/hamster/hash/invert_spec.rb +31 -0
- data/spec/lib/hamster/hash/key_spec.rb +28 -0
- data/spec/{hamster → lib/hamster}/hash/keys_spec.rb +3 -6
- data/spec/lib/hamster/hash/map_spec.rb +46 -0
- data/spec/{hamster → lib/hamster}/hash/marshal_spec.rb +3 -3
- data/spec/lib/hamster/hash/merge_spec.rb +77 -0
- data/spec/lib/hamster/hash/min_max_spec.rb +50 -0
- data/spec/lib/hamster/hash/new_spec.rb +71 -0
- data/spec/{hamster → lib/hamster}/hash/none_spec.rb +12 -14
- data/spec/lib/hamster/hash/partition_spec.rb +36 -0
- data/spec/lib/hamster/hash/pretty_print_spec.rb +35 -0
- data/spec/lib/hamster/hash/put_spec.rb +81 -0
- data/spec/lib/hamster/hash/reduce_spec.rb +36 -0
- data/spec/lib/hamster/hash/remove_spec.rb +62 -0
- data/spec/lib/hamster/hash/reverse_each_spec.rb +28 -0
- data/spec/lib/hamster/hash/sample_spec.rb +14 -0
- data/spec/{hamster → lib/hamster}/hash/size_spec.rb +2 -2
- data/spec/lib/hamster/hash/slice_spec.rb +45 -0
- data/spec/lib/hamster/hash/sort_spec.rb +27 -0
- data/spec/lib/hamster/hash/store_spec.rb +54 -0
- data/spec/lib/hamster/hash/take_spec.rb +36 -0
- data/spec/lib/hamster/hash/to_a_spec.rb +14 -0
- data/spec/lib/hamster/hash/to_hash_spec.rb +22 -0
- data/spec/{hamster → lib/hamster}/hash/uniq_spec.rb +2 -4
- data/spec/lib/hamster/hash/values_at_spec.rb +14 -0
- data/spec/lib/hamster/hash/values_spec.rb +25 -0
- data/spec/{hamster → lib/hamster}/immutable/copying_spec.rb +0 -0
- data/spec/{hamster → lib/hamster}/immutable/immutable_spec.rb +0 -0
- data/spec/{hamster → lib/hamster}/immutable/memoize_spec.rb +2 -2
- data/spec/{hamster → lib/hamster}/immutable/new_spec.rb +0 -0
- data/spec/{hamster → lib/hamster}/immutable/transform_spec.rb +0 -0
- data/spec/{hamster → lib/hamster}/immutable/transform_unless_spec.rb +0 -0
- data/spec/lib/hamster/list/add_spec.rb +20 -0
- data/spec/lib/hamster/list/all_spec.rb +60 -0
- data/spec/{hamster → lib/hamster}/list/any_spec.rb +12 -20
- data/spec/{hamster → lib/hamster}/list/append_spec.rb +9 -10
- data/spec/lib/hamster/list/at_spec.rb +30 -0
- data/spec/lib/hamster/list/break_spec.rb +70 -0
- data/spec/{hamster → lib/hamster}/list/cadr_spec.rb +5 -8
- data/spec/{hamster → lib/hamster}/list/chunk_spec.rb +5 -8
- data/spec/{hamster → lib/hamster}/list/clear_spec.rb +4 -7
- data/spec/lib/hamster/list/combination_spec.rb +34 -0
- data/spec/{hamster → lib/hamster}/list/compact_spec.rb +5 -8
- data/spec/lib/hamster/list/compare_spec.rb +31 -0
- data/spec/{hamster → lib/hamster}/list/cons_spec.rb +5 -9
- data/spec/lib/hamster/list/construction_spec.rb +118 -0
- data/spec/{hamster → lib/hamster}/list/copying_spec.rb +3 -7
- data/spec/lib/hamster/list/count_spec.rb +37 -0
- data/spec/lib/hamster/list/cycle_spec.rb +29 -0
- data/spec/lib/hamster/list/delete_at_spec.rb +19 -0
- data/spec/lib/hamster/list/delete_spec.rb +17 -0
- data/spec/{hamster → lib/hamster}/list/drop_spec.rb +5 -8
- data/spec/lib/hamster/list/drop_while_spec.rb +39 -0
- data/spec/lib/hamster/list/each_slice_spec.rb +52 -0
- data/spec/lib/hamster/list/each_spec.rb +43 -0
- data/spec/lib/hamster/list/each_with_index_spec.rb +29 -0
- data/spec/{hamster → lib/hamster}/list/elem_index_spec.rb +4 -14
- data/spec/{hamster → lib/hamster}/list/elem_indices_spec.rb +5 -9
- data/spec/{hamster → lib/hamster}/list/empty_spec.rb +4 -13
- data/spec/{hamster → lib/hamster}/list/eql_spec.rb +2 -8
- data/spec/lib/hamster/list/fill_spec.rb +50 -0
- data/spec/{hamster → lib/hamster}/list/filter_spec.rb +3 -2
- data/spec/{hamster → lib/hamster}/list/find_all_spec.rb +3 -2
- data/spec/{hamster → lib/hamster}/list/find_index_spec.rb +4 -14
- data/spec/{hamster → lib/hamster}/list/find_indices_spec.rb +11 -9
- data/spec/{hamster → lib/hamster}/list/find_spec.rb +10 -16
- data/spec/{hamster → lib/hamster}/list/flat_map_spec.rb +0 -0
- data/spec/{hamster → lib/hamster}/list/flatten_spec.rb +5 -8
- data/spec/{hamster → lib/hamster}/list/grep_spec.rb +9 -17
- data/spec/{hamster → lib/hamster}/list/group_by_spec.rb +8 -24
- data/spec/{hamster → lib/hamster}/list/hash_spec.rb +4 -12
- data/spec/{hamster → lib/hamster}/list/head_spec.rb +2 -7
- data/spec/{hamster → lib/hamster}/list/include_spec.rb +4 -13
- data/spec/{hamster → lib/hamster}/list/init_spec.rb +5 -9
- data/spec/lib/hamster/list/inits_spec.rb +29 -0
- data/spec/lib/hamster/list/insert_spec.rb +47 -0
- data/spec/lib/hamster/list/inspect_spec.rb +30 -0
- data/spec/{hamster → lib/hamster}/list/intersperse_spec.rb +5 -8
- data/spec/lib/hamster/list/join_spec.rb +64 -0
- data/spec/lib/hamster/list/last_spec.rb +24 -0
- data/spec/{hamster → lib/hamster}/list/map_spec.rb +11 -20
- data/spec/lib/hamster/list/maximum_spec.rb +42 -0
- data/spec/{hamster → lib/hamster}/list/merge_by_spec.rb +4 -13
- data/spec/{hamster → lib/hamster}/list/merge_spec.rb +0 -0
- data/spec/lib/hamster/list/minimum_spec.rb +42 -0
- data/spec/lib/hamster/list/multithreading_spec.rb +48 -0
- data/spec/{hamster → lib/hamster}/list/none_spec.rb +11 -21
- data/spec/{hamster → lib/hamster}/list/one_spec.rb +12 -22
- data/spec/lib/hamster/list/partition_spec.rb +116 -0
- data/spec/lib/hamster/list/permutation_spec.rb +56 -0
- data/spec/{hamster → lib/hamster}/list/pop_spec.rb +1 -1
- data/spec/lib/hamster/list/product_spec.rb +24 -0
- data/spec/lib/hamster/list/reduce_spec.rb +97 -0
- data/spec/{hamster → lib/hamster}/list/remove_spec.rb +9 -19
- data/spec/{hamster → lib/hamster}/list/reverse_spec.rb +7 -14
- data/spec/lib/hamster/list/rotate_spec.rb +37 -0
- data/spec/lib/hamster/list/sample_spec.rb +14 -0
- data/spec/{hamster → lib/hamster}/list/select_spec.rb +3 -2
- data/spec/{hamster → lib/hamster}/list/size_spec.rb +4 -13
- data/spec/lib/hamster/list/slice_spec.rb +230 -0
- data/spec/{hamster → lib/hamster}/list/sorting_spec.rb +10 -20
- data/spec/lib/hamster/list/span_spec.rb +77 -0
- data/spec/{hamster → lib/hamster}/list/split_at_spec.rb +13 -14
- data/spec/lib/hamster/list/subsequences_spec.rb +24 -0
- data/spec/lib/hamster/list/sum_spec.rb +24 -0
- data/spec/lib/hamster/list/tail_spec.rb +31 -0
- data/spec/lib/hamster/list/tails_spec.rb +29 -0
- data/spec/{hamster → lib/hamster}/list/take_spec.rb +5 -8
- data/spec/{hamster → lib/hamster}/list/take_while_spec.rb +11 -17
- data/spec/lib/hamster/list/to_a_spec.rb +40 -0
- data/spec/{hamster → lib/hamster}/list/to_ary_spec.rb +1 -3
- data/spec/{hamster → lib/hamster}/list/to_list_spec.rb +3 -7
- data/spec/{hamster → lib/hamster}/list/to_set_spec.rb +2 -10
- data/spec/lib/hamster/list/transpose_spec.rb +20 -0
- data/spec/{hamster → lib/hamster}/list/union_spec.rb +5 -12
- data/spec/{hamster → lib/hamster}/list/uniq_spec.rb +5 -8
- data/spec/{hamster → lib/hamster}/list/zip_spec.rb +2 -9
- data/spec/lib/hamster/set/add_spec.rb +76 -0
- data/spec/{hamster → lib/hamster}/set/all_spec.rb +18 -14
- data/spec/{hamster → lib/hamster}/set/any_spec.rb +19 -16
- data/spec/{hamster → lib/hamster}/set/clear_spec.rb +8 -11
- data/spec/{hamster → lib/hamster}/set/compact_spec.rb +4 -7
- data/spec/{hamster → lib/hamster}/set/construction_spec.rb +4 -8
- data/spec/{hamster → lib/hamster}/set/copying_spec.rb +3 -5
- data/spec/{hamster → lib/hamster}/set/count_spec.rb +11 -16
- data/spec/lib/hamster/set/delete_spec.rb +72 -0
- data/spec/lib/hamster/set/difference_spec.rb +50 -0
- data/spec/lib/hamster/set/disjoint_spec.rb +26 -0
- data/spec/lib/hamster/set/each_spec.rb +46 -0
- data/spec/lib/hamster/set/empty_spec.rb +47 -0
- data/spec/{hamster → lib/hamster}/set/eqeq_spec.rb +0 -0
- data/spec/{hamster → lib/hamster}/set/eql_spec.rb +7 -1
- data/spec/lib/hamster/set/exclusion_spec.rb +48 -0
- data/spec/lib/hamster/set/filter_spec.rb +74 -0
- data/spec/{hamster → lib/hamster}/set/find_spec.rb +7 -11
- data/spec/lib/hamster/set/flatten_spec.rb +47 -0
- data/spec/{hamster → lib/hamster}/set/foreach_spec.rb +5 -4
- data/spec/{hamster → lib/hamster}/set/grep_spec.rb +1 -1
- data/spec/lib/hamster/set/group_by_spec.rb +60 -0
- data/spec/lib/hamster/set/hash_spec.rb +23 -0
- data/spec/lib/hamster/set/head_spec.rb +31 -0
- data/spec/{hamster → lib/hamster}/set/immutable_spec.rb +0 -0
- data/spec/lib/hamster/set/include_spec.rb +61 -0
- data/spec/lib/hamster/set/inspect_spec.rb +48 -0
- data/spec/lib/hamster/set/intersect_spec.rb +26 -0
- data/spec/lib/hamster/set/intersection_spec.rb +53 -0
- data/spec/lib/hamster/set/join_spec.rb +65 -0
- data/spec/lib/hamster/set/map_spec.rb +60 -0
- data/spec/{hamster → lib/hamster}/set/marshal_spec.rb +3 -3
- data/spec/{hamster → lib/hamster}/set/maximum_spec.rb +6 -15
- data/spec/{hamster → lib/hamster}/set/minimum_spec.rb +6 -16
- data/spec/lib/hamster/set/new_spec.rb +54 -0
- data/spec/{hamster → lib/hamster}/set/none_spec.rb +15 -15
- data/spec/{hamster → lib/hamster}/set/one_spec.rb +14 -16
- data/spec/lib/hamster/set/partition_spec.rb +53 -0
- data/spec/{hamster → lib/hamster}/set/product_spec.rb +6 -6
- data/spec/lib/hamster/set/reduce_spec.rb +56 -0
- data/spec/lib/hamster/set/remove_spec.rb +51 -0
- data/spec/{hamster/set/each_spec.rb → lib/hamster/set/reverse_each_spec.rb} +8 -7
- data/spec/lib/hamster/set/sample_spec.rb +14 -0
- data/spec/{hamster → lib/hamster}/set/size_spec.rb +0 -1
- data/spec/{hamster → lib/hamster}/set/sorting_spec.rb +17 -13
- data/spec/lib/hamster/set/subset_spec.rb +52 -0
- data/spec/lib/hamster/set/sum_spec.rb +24 -0
- data/spec/lib/hamster/set/superset_spec.rb +52 -0
- data/spec/lib/hamster/set/to_a_spec.rb +31 -0
- data/spec/lib/hamster/set/to_list_spec.rb +37 -0
- data/spec/{hamster → lib/hamster}/set/to_set_spec.rb +2 -6
- data/spec/lib/hamster/set/union_spec.rb +55 -0
- data/spec/{hamster → lib/hamster}/set/uniq_spec.rb +2 -5
- data/spec/lib/hamster/sorted_set/above_spec.rb +52 -0
- data/spec/lib/hamster/sorted_set/add_spec.rb +63 -0
- data/spec/lib/hamster/sorted_set/at_spec.rb +25 -0
- data/spec/lib/hamster/sorted_set/below_spec.rb +52 -0
- data/spec/lib/hamster/sorted_set/between_spec.rb +52 -0
- data/spec/lib/hamster/sorted_set/clear_spec.rb +35 -0
- data/spec/lib/hamster/sorted_set/construction_spec.rb +29 -0
- data/spec/lib/hamster/sorted_set/delete_at_spec.rb +19 -0
- data/spec/lib/hamster/sorted_set/delete_spec.rb +81 -0
- data/spec/{hamster/set → lib/hamster/sorted_set}/difference_spec.rb +5 -9
- data/spec/lib/hamster/sorted_set/disjoint_spec.rb +26 -0
- data/spec/lib/hamster/sorted_set/drop_spec.rb +29 -0
- data/spec/lib/hamster/sorted_set/drop_while_spec.rb +35 -0
- data/spec/lib/hamster/sorted_set/each_spec.rb +31 -0
- data/spec/lib/hamster/sorted_set/empty_spec.rb +37 -0
- data/spec/lib/hamster/sorted_set/eql_spec.rb +121 -0
- data/spec/{hamster/set → lib/hamster/sorted_set}/exclusion_spec.rb +4 -9
- data/spec/lib/hamster/sorted_set/fetch_spec.rb +65 -0
- data/spec/lib/hamster/sorted_set/filter_spec.rb +62 -0
- data/spec/lib/hamster/sorted_set/find_index_spec.rb +33 -0
- data/spec/lib/hamster/sorted_set/first_spec.rb +21 -0
- data/spec/lib/hamster/sorted_set/from_spec.rb +52 -0
- data/spec/lib/hamster/sorted_set/group_by_spec.rb +58 -0
- data/spec/lib/hamster/sorted_set/include_spec.rb +24 -0
- data/spec/lib/hamster/sorted_set/inspect_spec.rb +38 -0
- data/spec/lib/hamster/sorted_set/intersect_spec.rb +26 -0
- data/spec/lib/hamster/sorted_set/intersection_spec.rb +29 -0
- data/spec/lib/hamster/sorted_set/last_spec.rb +37 -0
- data/spec/lib/hamster/sorted_set/map_spec.rb +36 -0
- data/spec/lib/hamster/sorted_set/marshal_spec.rb +37 -0
- data/spec/lib/hamster/sorted_set/minimum_spec.rb +22 -0
- data/spec/lib/hamster/sorted_set/new_spec.rb +52 -0
- data/spec/lib/hamster/sorted_set/reverse_each_spec.rb +29 -0
- data/spec/lib/hamster/sorted_set/sample_spec.rb +14 -0
- data/spec/lib/hamster/sorted_set/size_spec.rb +18 -0
- data/spec/lib/hamster/sorted_set/slice_spec.rb +241 -0
- data/spec/lib/hamster/sorted_set/sorting_spec.rb +45 -0
- data/spec/lib/hamster/sorted_set/subset_spec.rb +48 -0
- data/spec/lib/hamster/sorted_set/superset_spec.rb +48 -0
- data/spec/lib/hamster/sorted_set/take_spec.rb +26 -0
- data/spec/lib/hamster/sorted_set/take_while_spec.rb +34 -0
- data/spec/lib/hamster/sorted_set/to_set_spec.rb +19 -0
- data/spec/lib/hamster/sorted_set/union_spec.rb +28 -0
- data/spec/lib/hamster/sorted_set/up_to_spec.rb +52 -0
- data/spec/lib/hamster/sorted_set/values_at_spec.rb +34 -0
- data/spec/lib/hamster/vector/add_spec.rb +68 -0
- data/spec/{hamster → lib/hamster}/vector/any_spec.rb +0 -0
- data/spec/lib/hamster/vector/assoc_spec.rb +36 -0
- data/spec/lib/hamster/vector/bsearch_spec.rb +58 -0
- data/spec/lib/hamster/vector/clear_spec.rb +34 -0
- data/spec/lib/hamster/vector/combination_spec.rb +82 -0
- data/spec/lib/hamster/vector/compact_spec.rb +30 -0
- data/spec/lib/hamster/vector/compare_spec.rb +32 -0
- data/spec/lib/hamster/vector/concat_spec.rb +35 -0
- data/spec/{hamster → lib/hamster}/vector/copying_spec.rb +3 -6
- data/spec/lib/hamster/vector/count_spec.rb +18 -0
- data/spec/lib/hamster/vector/delete_at_spec.rb +54 -0
- data/spec/lib/hamster/vector/delete_spec.rb +31 -0
- data/spec/lib/hamster/vector/drop_spec.rb +35 -0
- data/spec/lib/hamster/vector/drop_while_spec.rb +55 -0
- data/spec/lib/hamster/vector/each_index_spec.rb +41 -0
- data/spec/lib/hamster/vector/each_spec.rb +47 -0
- data/spec/lib/hamster/vector/each_with_index_spec.rb +40 -0
- data/spec/lib/hamster/vector/empty_spec.rb +44 -0
- data/spec/lib/hamster/vector/eql_spec.rb +77 -0
- data/spec/lib/hamster/vector/exist_spec.rb +4 -4
- data/spec/lib/hamster/vector/exists_spec.rb +4 -4
- data/spec/lib/hamster/vector/fetch_spec.rb +65 -0
- data/spec/lib/hamster/vector/fill_spec.rb +89 -0
- data/spec/lib/hamster/vector/filter_spec.rb +64 -0
- data/spec/{hamster → lib/hamster}/vector/first_spec.rb +2 -6
- data/spec/lib/hamster/vector/flatten_spec.rb +44 -0
- data/spec/lib/hamster/vector/get_spec.rb +75 -0
- data/spec/lib/hamster/vector/group_by_spec.rb +58 -0
- data/spec/{hamster → lib/hamster}/vector/include_spec.rb +2 -6
- data/spec/lib/hamster/vector/insert_spec.rb +69 -0
- data/spec/lib/hamster/vector/inspect_spec.rb +50 -0
- data/spec/{hamster/set → lib/hamster/vector}/join_spec.rb +23 -18
- data/spec/{hamster → lib/hamster}/vector/last_spec.rb +12 -3
- data/spec/{hamster → lib/hamster}/vector/length_spec.rb +12 -3
- data/spec/lib/hamster/vector/ltlt_spec.rb +20 -2
- data/spec/lib/hamster/vector/map_spec.rb +52 -0
- data/spec/lib/hamster/vector/marshal_spec.rb +32 -0
- data/spec/lib/hamster/vector/maximum_spec.rb +36 -0
- data/spec/lib/hamster/vector/minimum_spec.rb +36 -0
- data/spec/lib/hamster/vector/multiply_spec.rb +48 -0
- data/spec/lib/hamster/vector/new_spec.rb +51 -0
- data/spec/lib/hamster/vector/partition_spec.rb +53 -0
- data/spec/lib/hamster/vector/permutation_spec.rb +92 -0
- data/spec/lib/hamster/vector/pop_spec.rb +27 -0
- data/spec/lib/hamster/vector/product_spec.rb +71 -0
- data/spec/lib/hamster/vector/reduce_spec.rb +108 -0
- data/spec/lib/hamster/vector/remove_spec.rb +44 -0
- data/spec/lib/hamster/vector/repeated_combination_spec.rb +78 -0
- data/spec/lib/hamster/vector/repeated_permutation_spec.rb +94 -0
- data/spec/lib/hamster/vector/reverse_each_spec.rb +32 -0
- data/spec/lib/hamster/vector/reverse_spec.rb +22 -0
- data/spec/lib/hamster/vector/rindex_spec.rb +37 -0
- data/spec/lib/hamster/vector/rotate_spec.rb +74 -0
- data/spec/lib/hamster/vector/sample_spec.rb +14 -0
- data/spec/{hamster → lib/hamster}/vector/set_spec.rb +48 -14
- data/spec/lib/hamster/vector/shift_spec.rb +28 -0
- data/spec/lib/hamster/vector/shuffle_spec.rb +44 -0
- data/spec/lib/hamster/vector/slice_spec.rb +241 -0
- data/spec/lib/hamster/vector/sorting_spec.rb +57 -0
- data/spec/{hamster/set → lib/hamster/vector}/sum_spec.rb +3 -9
- data/spec/lib/hamster/vector/take_spec.rb +29 -0
- data/spec/lib/hamster/vector/take_while_spec.rb +35 -0
- data/spec/{hamster → lib/hamster}/vector/to_a_spec.rb +11 -12
- data/spec/{hamster → lib/hamster}/vector/to_ary_spec.rb +0 -0
- data/spec/{hamster/set → lib/hamster/vector}/to_list_spec.rb +7 -12
- data/spec/lib/hamster/vector/to_set_spec.rb +23 -0
- data/spec/lib/hamster/vector/transpose_spec.rb +49 -0
- data/spec/lib/hamster/vector/uniq_spec.rb +56 -0
- data/spec/lib/hamster/vector/unshift_spec.rb +29 -0
- data/spec/lib/hamster/vector/values_at_spec.rb +34 -0
- data/spec/lib/hamster/vector/zip_spec.rb +58 -0
- data/spec/spec_helper.rb +34 -1
- metadata +684 -467
- data/lib/hamster/core_ext/enumerator.rb +0 -16
- data/lib/hamster/experimental/mutable_stack.rb +0 -30
- data/lib/hamster/groupable.rb +0 -12
- data/lib/hamster/queue.rb +0 -86
- data/lib/hamster/sorter.rb +0 -25
- data/lib/hamster/stack.rb +0 -77
- data/lib/hamster/tuple.rb +0 -24
- data/spec/hamster/core_ext/enumerator_spec.rb +0 -19
- data/spec/hamster/experimental/mutable_stack/pop_spec.rb +0 -35
- data/spec/hamster/experimental/mutable_stack/push_spec.rb +0 -21
- data/spec/hamster/hash/any_spec.rb +0 -52
- data/spec/hamster/hash/clear_spec.rb +0 -29
- data/spec/hamster/hash/construction_spec.rb +0 -27
- data/spec/hamster/hash/delete_spec.rb +0 -38
- data/spec/hamster/hash/each_spec.rb +0 -30
- data/spec/hamster/hash/empty_spec.rb +0 -27
- data/spec/hamster/hash/eql_spec.rb +0 -70
- data/spec/hamster/hash/except_spec.rb +0 -22
- data/spec/hamster/hash/fetch_spec.rb +0 -72
- data/spec/hamster/hash/filter_spec.rb +0 -48
- data/spec/hamster/hash/find_spec.rb +0 -45
- data/spec/hamster/hash/get_spec.rb +0 -55
- data/spec/hamster/hash/has_key_spec.rb +0 -26
- data/spec/hamster/hash/inspect_spec.rb +0 -24
- data/spec/hamster/hash/map_spec.rb +0 -49
- data/spec/hamster/hash/merge_spec.rb +0 -30
- data/spec/hamster/hash/new_spec.rb +0 -21
- data/spec/hamster/hash/put_spec.rb +0 -67
- data/spec/hamster/hash/reduce_spec.rb +0 -52
- data/spec/hamster/hash/remove_spec.rb +0 -48
- data/spec/hamster/hash/slice_spec.rb +0 -26
- data/spec/hamster/hash/values_spec.rb +0 -29
- data/spec/hamster/list/add_spec.rb +0 -11
- data/spec/hamster/list/all_spec.rb +0 -84
- data/spec/hamster/list/at_spec.rb +0 -37
- data/spec/hamster/list/break_spec.rb +0 -73
- data/spec/hamster/list/combinations_spec.rb +0 -41
- data/spec/hamster/list/construction_spec.rb +0 -137
- data/spec/hamster/list/count_spec.rb +0 -52
- data/spec/hamster/list/cycle_spec.rb +0 -36
- data/spec/hamster/list/drop_while_spec.rb +0 -47
- data/spec/hamster/list/each_slice_spec.rb +0 -64
- data/spec/hamster/list/each_spec.rb +0 -56
- data/spec/hamster/list/each_with_index_spec.rb +0 -33
- data/spec/hamster/list/inits_spec.rb +0 -34
- data/spec/hamster/list/inspect_spec.rb +0 -33
- data/spec/hamster/list/join_spec.rb +0 -64
- data/spec/hamster/list/last_spec.rb +0 -34
- data/spec/hamster/list/maximum_spec.rb +0 -58
- data/spec/hamster/list/minimum_spec.rb +0 -58
- data/spec/hamster/list/partition_spec.rb +0 -63
- data/spec/hamster/list/product_spec.rb +0 -34
- data/spec/hamster/list/reduce_spec.rb +0 -72
- data/spec/hamster/list/slice_spec.rb +0 -40
- data/spec/hamster/list/span_spec.rb +0 -75
- data/spec/hamster/list/sum_spec.rb +0 -34
- data/spec/hamster/list/tail_spec.rb +0 -38
- data/spec/hamster/list/tails_spec.rb +0 -34
- data/spec/hamster/list/to_a_spec.rb +0 -42
- data/spec/hamster/queue/clear_spec.rb +0 -28
- data/spec/hamster/queue/construction_spec.rb +0 -34
- data/spec/hamster/queue/dequeue_spec.rb +0 -30
- data/spec/hamster/queue/empty_spec.rb +0 -35
- data/spec/hamster/queue/head_spec.rb +0 -25
- data/spec/hamster/queue/inspect_spec.rb +0 -23
- data/spec/hamster/queue/to_a_spec.rb +0 -32
- data/spec/hamster/queue/to_list_spec.rb +0 -34
- data/spec/hamster/set/add_spec.rb +0 -40
- data/spec/hamster/set/delete_spec.rb +0 -38
- data/spec/hamster/set/empty_spec.rb +0 -25
- data/spec/hamster/set/filter_spec.rb +0 -72
- data/spec/hamster/set/flatten_spec.rb +0 -47
- data/spec/hamster/set/group_by_spec.rb +0 -56
- data/spec/hamster/set/hash_spec.rb +0 -20
- data/spec/hamster/set/head_spec.rb +0 -28
- data/spec/hamster/set/include_spec.rb +0 -27
- data/spec/hamster/set/inspect_spec.rb +0 -24
- data/spec/hamster/set/intersection_spec.rb +0 -36
- data/spec/hamster/set/map_spec.rb +0 -49
- data/spec/hamster/set/new_spec.rb +0 -21
- data/spec/hamster/set/partition_spec.rb +0 -59
- data/spec/hamster/set/reduce_spec.rb +0 -62
- data/spec/hamster/set/remove_spec.rb +0 -48
- data/spec/hamster/set/subset_spec.rb +0 -31
- data/spec/hamster/set/superset_spec.rb +0 -31
- data/spec/hamster/set/to_a_spec.rb +0 -32
- data/spec/hamster/set/union_spec.rb +0 -35
- data/spec/hamster/sorter/immutable_spec.rb +0 -9
- data/spec/hamster/stack/clear_spec.rb +0 -28
- data/spec/hamster/stack/construction_spec.rb +0 -34
- data/spec/hamster/stack/copying_spec.rb +0 -23
- data/spec/hamster/stack/empty_spec.rb +0 -23
- data/spec/hamster/stack/eql_spec.rb +0 -48
- data/spec/hamster/stack/immutable_spec.rb +0 -9
- data/spec/hamster/stack/inspect_spec.rb +0 -23
- data/spec/hamster/stack/peek_spec.rb +0 -30
- data/spec/hamster/stack/pop_spec.rb +0 -31
- data/spec/hamster/stack/push_spec.rb +0 -31
- data/spec/hamster/stack/size_spec.rb +0 -25
- data/spec/hamster/stack/to_a_spec.rb +0 -32
- data/spec/hamster/stack/to_ary.rb +0 -37
- data/spec/hamster/stack/to_list_spec.rb +0 -25
- data/spec/hamster/trie/remove_spec.rb +0 -117
- data/spec/hamster/tuple/construction_spec.rb +0 -30
- data/spec/hamster/tuple/copying_spec.rb +0 -17
- data/spec/hamster/tuple/eql_spec.rb +0 -78
- data/spec/hamster/tuple/first_spec.rb +0 -14
- data/spec/hamster/tuple/immutable_spec.rb +0 -9
- data/spec/hamster/tuple/inspect_spec.rb +0 -14
- data/spec/hamster/tuple/last_spec.rb +0 -14
- data/spec/hamster/tuple/to_a_spec.rb +0 -30
- data/spec/hamster/tuple/to_ary_spec.rb +0 -37
- data/spec/hamster/undefined/erase_spec.rb +0 -36
- data/spec/hamster/vector/add_spec.rb +0 -56
- data/spec/hamster/vector/clear_spec.rb +0 -28
- data/spec/hamster/vector/each_spec.rb +0 -35
- data/spec/hamster/vector/each_with_index_spec.rb +0 -33
- data/spec/hamster/vector/empty_spec.rb +0 -32
- data/spec/hamster/vector/eql_spec.rb +0 -53
- data/spec/hamster/vector/filter_spec.rb +0 -58
- data/spec/hamster/vector/get_spec.rb +0 -58
- data/spec/hamster/vector/inspect_spec.rb +0 -33
- data/spec/hamster/vector/map_spec.rb +0 -57
- data/spec/hamster/vector/new_spec.rb +0 -48
- data/spec/hamster/vector/reduce_spec.rb +0 -62
- data/spec/lib/hamster/vector/cons_spec.rb +0 -48
@@ -0,0 +1,1014 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
require "hamster/immutable"
|
3
|
+
require "hamster/enumerable"
|
4
|
+
|
5
|
+
module Hamster
|
6
|
+
def self.sorted_set(*items, &block)
|
7
|
+
(items.empty? && block.nil?) ? EmptySortedSet : SortedSet.new(items, &block)
|
8
|
+
end
|
9
|
+
|
10
|
+
# A `SortedSet` is a collection of ordered values with no duplicates. Unlike a
|
11
|
+
# {Vector}, in which items can appear in any arbitrary order, a `SortedSet` always
|
12
|
+
# keeps items either in their natural order, or in an order defined by a comparator
|
13
|
+
# block which is provided at initialization time.
|
14
|
+
#
|
15
|
+
# `SortedSet` uses `#<=>` (or its comparator block) to determine which items are
|
16
|
+
# equivalent. If the comparator indicates that an existing item and a new item are
|
17
|
+
# equal, any attempt to insert the new item will have no effect.
|
18
|
+
#
|
19
|
+
# This means that *all* the items inserted into any one `SortedSet` must all be
|
20
|
+
# comparable. For example, you cannot put `String`s and `Integer`s in the same
|
21
|
+
# `SortedSet`. This is unlike {Set}, which can store items of any type, as long
|
22
|
+
# as they all support `#hash` and `#eql?`.
|
23
|
+
#
|
24
|
+
# A `SortedSet` can be created in any of the following ways:
|
25
|
+
#
|
26
|
+
# Hamster.sorted_set('Tom', 'Dick', 'Harry')
|
27
|
+
# Hamster::SortedSet.new([1, 2, 3]) # any Enumerable can be used to initialize
|
28
|
+
# Hamster::SortedSet['A', 'B', 'C', 'D']
|
29
|
+
#
|
30
|
+
# Or if you want to use a custom ordering:
|
31
|
+
#
|
32
|
+
# Hamster.sorted_set('Tom', 'Dick', 'Harry') { |a, b| a.reverse <=> b.reverse }
|
33
|
+
# Hamster.sorted_set('Tom', 'Dick', 'Harry') { |str| str.reverse }
|
34
|
+
# Hamster::SortedSet.new([1,2,3]) { |a, b| -a <=> -b }
|
35
|
+
# Hamster::SortedSet.new([1, 2, 3]) { |num| -num }
|
36
|
+
#
|
37
|
+
# As you can see, `SortedSet` can use a 2-parameter block which returns 0, 1, or -1
|
38
|
+
# as a comparator (like `Array#sort`), *or* use a 1-parameter block to derive sort
|
39
|
+
# keys (like `Array#sort_by`) which will be compared using `#<=>`.
|
40
|
+
#
|
41
|
+
# Like all Hamster collections, `SortedSet`s are immutable. Any operation which you
|
42
|
+
# might expect to "modify" a `SortedSet` will actually return a new collection and
|
43
|
+
# leave the existing one unchanged.
|
44
|
+
#
|
45
|
+
# `SortedSet` supports the same basic set-theoretic operations as {Set}, including
|
46
|
+
# {#union}, {#intersection}, {#difference}, and {#exclusion}, as well as {#subset?},
|
47
|
+
# {#superset?}, and so on. Unlike {Set}, it does not define comparison operators like
|
48
|
+
# {#>} or {#<} as aliases for the superset/subset predicates. Instead, these comparison
|
49
|
+
# operators do a item-by-item comparison between the `SortedSet` and another sequential
|
50
|
+
# collection. (See `Array#<=>` for details.)
|
51
|
+
#
|
52
|
+
# Additionally, since `SortedSet`s are ordered, they also support indexed retrieval
|
53
|
+
# of items (or slices of items) using {#at} or {#[]}. Like {Vector} (or `Array`),
|
54
|
+
# negative indices count back from the end of the `SortedSet`.
|
55
|
+
#
|
56
|
+
# Getting the {#max} or {#min} item from a `SortedSet`, as defined by its comparator,
|
57
|
+
# is very efficient.
|
58
|
+
#
|
59
|
+
class SortedSet
|
60
|
+
extend Forwardable
|
61
|
+
include Immutable
|
62
|
+
include Enumerable
|
63
|
+
|
64
|
+
class << self
|
65
|
+
# Create a new `SortedSet` populated with the given items. This method does not
|
66
|
+
# accept a comparator block.
|
67
|
+
#
|
68
|
+
# @return [SortedSet]
|
69
|
+
def [](*items)
|
70
|
+
new(items)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Return an empty `SortedSet`. If used on a subclass, returns an empty instance
|
74
|
+
# of that class.
|
75
|
+
#
|
76
|
+
# @return [SortedSet]
|
77
|
+
def empty
|
78
|
+
@empty ||= self.alloc(EmptyAVLNode, lambda { |a,b| a <=> b })
|
79
|
+
end
|
80
|
+
|
81
|
+
# "Raw" allocation of a new `SortedSet`. Used internally to create a new
|
82
|
+
# instance quickly after obtaining a modified binary tree.
|
83
|
+
#
|
84
|
+
# @return [Set]
|
85
|
+
# @private
|
86
|
+
def alloc(node, comparator)
|
87
|
+
result = allocate
|
88
|
+
result.instance_variable_set(:@node, node)
|
89
|
+
result.instance_variable_set(:@comparator, comparator)
|
90
|
+
result
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def initialize(items=[], &block)
|
95
|
+
items = items.to_a
|
96
|
+
if block
|
97
|
+
@comparator = if block.arity == 1
|
98
|
+
lambda { |a,b| block.call(a) <=> block.call(b) }
|
99
|
+
else
|
100
|
+
block
|
101
|
+
end
|
102
|
+
items = items.sort(&@comparator)
|
103
|
+
else
|
104
|
+
items = items.sort
|
105
|
+
end
|
106
|
+
@node = AVLNode.from_items(items, 0, items.size-1)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Return `true` if this `SortedSet` contains no items.
|
110
|
+
#
|
111
|
+
# @return [Boolean]
|
112
|
+
def empty?
|
113
|
+
@node.empty?
|
114
|
+
end
|
115
|
+
def_delegator :self, :empty?, :null?
|
116
|
+
|
117
|
+
# Return the number of items in this `SortedSet`.
|
118
|
+
#
|
119
|
+
# @return [Integer]
|
120
|
+
def size
|
121
|
+
@node.size
|
122
|
+
end
|
123
|
+
def_delegator :self, :size, :length
|
124
|
+
|
125
|
+
# Return a new `SortedSet` with `item` added. If `item` is already in the set,
|
126
|
+
# return `self`.
|
127
|
+
#
|
128
|
+
# @param item [Object] The object to add
|
129
|
+
# @return [SortedSet]
|
130
|
+
def add(item)
|
131
|
+
return self if include?(item)
|
132
|
+
node = @node.insert(item, @comparator)
|
133
|
+
self.class.alloc(node, @comparator)
|
134
|
+
end
|
135
|
+
def_delegator :self, :add, :<<
|
136
|
+
def_delegator :self, :add, :conj
|
137
|
+
def_delegator :self, :add, :conjoin
|
138
|
+
|
139
|
+
# If `item` is not a member of this `SortedSet`, return a new `SortedSet` with
|
140
|
+
# `item` added. Otherwise, return `false`.
|
141
|
+
#
|
142
|
+
# @param item [Object] The object to add
|
143
|
+
# @return [SortedSet, false]
|
144
|
+
def add?(item)
|
145
|
+
!include?(item) && add(item)
|
146
|
+
end
|
147
|
+
|
148
|
+
# Return a new `SortedSet` with `item` removed. If `item` is not a member of the set,
|
149
|
+
# return `self`.
|
150
|
+
#
|
151
|
+
# @param item [Object] The object to remove
|
152
|
+
# @return [SortedSet]
|
153
|
+
def delete(item)
|
154
|
+
return self if not include?(item)
|
155
|
+
node = @node.delete(item, @comparator)
|
156
|
+
if node.empty?
|
157
|
+
self.class.empty
|
158
|
+
else
|
159
|
+
self.class.alloc(node, @comparator)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
# If `item` is a member of this `SortedSet`, return a new `SortedSet` with
|
164
|
+
# `item` removed. Otherwise, return `false`.
|
165
|
+
#
|
166
|
+
# @param item [Object] The object to remove
|
167
|
+
# @return [SortedSet, false]
|
168
|
+
def delete?(item)
|
169
|
+
include?(item) && delete(item)
|
170
|
+
end
|
171
|
+
|
172
|
+
# Return a new `SortedSet` with the item at `index` removed. If the given `index`
|
173
|
+
# does not exist (if it is too high or too low), return `self`.
|
174
|
+
#
|
175
|
+
# @param index [Integer] The index to remove
|
176
|
+
# @return [SortedSet]
|
177
|
+
def delete_at(index)
|
178
|
+
(item = at(index)) ? delete(item) : self
|
179
|
+
end
|
180
|
+
|
181
|
+
# Retrieve the item at `index`. If there is none (either the provided index
|
182
|
+
# is too high or too low), return `nil`.
|
183
|
+
#
|
184
|
+
# @param index [Integer] The index to retrieve
|
185
|
+
# @return [Object]
|
186
|
+
def at(index)
|
187
|
+
index += @node.size if index < 0
|
188
|
+
return nil if index >= @node.size || index < 0
|
189
|
+
@node.at(index)
|
190
|
+
end
|
191
|
+
|
192
|
+
# Retrieve the value at `index`, or use the provided default value or block,
|
193
|
+
# or otherwise raise an `IndexError`.
|
194
|
+
#
|
195
|
+
# @overload fetch(index)
|
196
|
+
# Retrieve the value at the given index, or raise an `IndexError` if it is
|
197
|
+
# not found.
|
198
|
+
# @param index [Integer] The index to look up
|
199
|
+
# @overload fetch(index) { |index| ... }
|
200
|
+
# Retrieve the value at the given index, or call the optional
|
201
|
+
# code block (with the non-existent index) and get its return value.
|
202
|
+
# @yield [index] The index which does not exist
|
203
|
+
# @yieldreturn [Object] Object to return instead
|
204
|
+
# @param index [Integer] The index to look up
|
205
|
+
# @overload fetch(index, default)
|
206
|
+
# Retrieve the value at the given index, or else return the provided
|
207
|
+
# `default` value.
|
208
|
+
# @param index [Integer] The index to look up
|
209
|
+
# @param default [Object] Object to return if the key is not found
|
210
|
+
#
|
211
|
+
# @return [Object]
|
212
|
+
def fetch(index, default = (missing_default = true))
|
213
|
+
if index >= -@node.size && index < @node.size
|
214
|
+
at(index)
|
215
|
+
elsif block_given?
|
216
|
+
yield(index)
|
217
|
+
elsif !missing_default
|
218
|
+
default
|
219
|
+
else
|
220
|
+
raise IndexError, "index #{index} outside of sorted set bounds"
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
# Element reference. Return the item at a specific index, or a specified,
|
225
|
+
# contiguous range of items (as a new `SortedSet`).
|
226
|
+
#
|
227
|
+
# @overload set[index]
|
228
|
+
# Return the item at `index`.
|
229
|
+
# @param index [Integer] The index to retrieve.
|
230
|
+
# @overload set[start, length]
|
231
|
+
# Return a subset starting at index `start` and continuing for `length` elements.
|
232
|
+
# @param start [Integer] The index to start retrieving items from.
|
233
|
+
# @param length [Integer] The number of items to retrieve.
|
234
|
+
# @overload set[range]
|
235
|
+
# Return a subset specified by the given `range` of indices.
|
236
|
+
# @param range [Range] The range of indices to retrieve.
|
237
|
+
#
|
238
|
+
# @return [Object]
|
239
|
+
def [](arg, length = (missing_length = true))
|
240
|
+
if missing_length
|
241
|
+
if arg.is_a?(Range)
|
242
|
+
from, to = arg.begin, arg.end
|
243
|
+
from += @node.size if from < 0
|
244
|
+
to += @node.size if to < 0
|
245
|
+
to += 1 if !arg.exclude_end?
|
246
|
+
length = to - from
|
247
|
+
length = 0 if length < 0
|
248
|
+
subsequence(from, length)
|
249
|
+
else
|
250
|
+
at(arg)
|
251
|
+
end
|
252
|
+
else
|
253
|
+
arg += @node.size if arg < 0
|
254
|
+
subsequence(arg, length)
|
255
|
+
end
|
256
|
+
end
|
257
|
+
def_delegator :self, :[], :slice
|
258
|
+
|
259
|
+
# Return a new `SortedSet` with only the elements at the given `indices`.
|
260
|
+
# If any of the `indices` do not exist, they will be skipped.
|
261
|
+
#
|
262
|
+
# @param indices [Array] The indices to retrieve and gather into a new `SortedSet`
|
263
|
+
# @return [SortedSet]
|
264
|
+
def values_at(*indices)
|
265
|
+
indices.select! { |i| i >= -@node.size && i < @node.size }
|
266
|
+
self.class.new(indices.map! { |i| at(i) })
|
267
|
+
end
|
268
|
+
|
269
|
+
# Call the given block once for each item in the set, passing each
|
270
|
+
# item from first to last successively to the block.
|
271
|
+
#
|
272
|
+
# @return [self]
|
273
|
+
def each(&block)
|
274
|
+
return @node.to_enum if not block_given?
|
275
|
+
@node.each(&block)
|
276
|
+
self
|
277
|
+
end
|
278
|
+
|
279
|
+
# Call the given block once for each item in the set, passing each
|
280
|
+
# item starting from the last, and counting back to the first, successively to
|
281
|
+
# the block.
|
282
|
+
#
|
283
|
+
# @return [self]
|
284
|
+
def reverse_each(&block)
|
285
|
+
return @node.enum_for(:reverse_each) if not block_given?
|
286
|
+
@node.reverse_each(&block)
|
287
|
+
self
|
288
|
+
end
|
289
|
+
|
290
|
+
# Return the "lowest" element in this set, as determined by its sort order.
|
291
|
+
# @return [Object]
|
292
|
+
def min
|
293
|
+
@node.min
|
294
|
+
end
|
295
|
+
alias :first :min
|
296
|
+
def_delegator :self, :first, :head
|
297
|
+
|
298
|
+
# Return the "highest" element in this set, as determined by its sort order.
|
299
|
+
# @return [Object]
|
300
|
+
def max
|
301
|
+
@node.max
|
302
|
+
end
|
303
|
+
alias :last :max
|
304
|
+
|
305
|
+
# Return a new `SortedSet` containing all elements for which the given block returns
|
306
|
+
# true.
|
307
|
+
#
|
308
|
+
# @return [SortedSet]
|
309
|
+
def filter
|
310
|
+
return enum_for(:filter) unless block_given?
|
311
|
+
reduce(self) { |set, item| yield(item) ? set : set.delete(item) }
|
312
|
+
end
|
313
|
+
|
314
|
+
# Invoke the given block once for each item in the set, and return a new
|
315
|
+
# `SortedSet` containing the values returned by the block.
|
316
|
+
#
|
317
|
+
# @return [SortedSet]
|
318
|
+
def map
|
319
|
+
return enum_for(:map) if not block_given?
|
320
|
+
return self if empty?
|
321
|
+
self.class.new(super, &@comparator)
|
322
|
+
end
|
323
|
+
def_delegator :self, :map, :collect
|
324
|
+
|
325
|
+
# Return `true` if the given item is present in this `SortedSet`. More precisely,
|
326
|
+
# return `true` if an object which compares as "equal" using this set's
|
327
|
+
# comparator is present.
|
328
|
+
#
|
329
|
+
# @param item [Object] The object to check for
|
330
|
+
# @return [Boolean]
|
331
|
+
def include?(item)
|
332
|
+
@node.include?(item, @comparator)
|
333
|
+
end
|
334
|
+
def_delegator :self, :include?, :member?
|
335
|
+
|
336
|
+
# Return a new `SortedSet` with the same items, but a sort order determined by
|
337
|
+
# the given block.
|
338
|
+
#
|
339
|
+
# @return [SortedSet]
|
340
|
+
def sort(&block)
|
341
|
+
block ||= lambda { |a,b| a <=> b }
|
342
|
+
self.class.new(self.to_a, &block)
|
343
|
+
end
|
344
|
+
alias :sort_by :sort
|
345
|
+
|
346
|
+
# Return the index of the first object in this set which is equal to
|
347
|
+
# `obj`. Rather than using `#==`, we use `#<=>` (or our comparator block) for
|
348
|
+
# comparisons. This means we can find the index in O(log N) time, rather than O(N).
|
349
|
+
#
|
350
|
+
# @param obj [Object] The object to search for
|
351
|
+
# @return [Integer]
|
352
|
+
def find_index(obj = (missing_obj = true), &block)
|
353
|
+
if !missing_obj
|
354
|
+
# Enumerable provides a default implementation, but this is more efficient
|
355
|
+
node = @node
|
356
|
+
index = node.left.size
|
357
|
+
while !node.empty?
|
358
|
+
direction = node.direction(obj, @comparator)
|
359
|
+
if direction > 0
|
360
|
+
node = node.right
|
361
|
+
index += node.left.size
|
362
|
+
elsif direction < 0
|
363
|
+
node = node.left
|
364
|
+
index -= node.right.size
|
365
|
+
else
|
366
|
+
return index
|
367
|
+
end
|
368
|
+
end
|
369
|
+
nil
|
370
|
+
else
|
371
|
+
super(&block)
|
372
|
+
end
|
373
|
+
end
|
374
|
+
def_delegator :self, :find_index, :index
|
375
|
+
|
376
|
+
# Drop the first `n` elements and return the rest in a new `SortedSet`.
|
377
|
+
# @param n [Integer] The number of elements to remove
|
378
|
+
# @return [SortedSet]
|
379
|
+
def drop(n)
|
380
|
+
self.class.new(super)
|
381
|
+
end
|
382
|
+
|
383
|
+
# Return only the first `n` elements in a new `SortedSet`.
|
384
|
+
# @param n [Integer] The number of elements to retain
|
385
|
+
# @return [SortedSet]
|
386
|
+
def take(n)
|
387
|
+
self.class.new(super)
|
388
|
+
end
|
389
|
+
|
390
|
+
# Drop elements up to, but not including, the first element for which the
|
391
|
+
# block returns `nil` or `false`. Gather the remaining elements into a new
|
392
|
+
# `SortedSet`. If no block is given, an `Enumerator` is returned instead.
|
393
|
+
#
|
394
|
+
# @return [SortedSet, Enumerator]
|
395
|
+
def drop_while
|
396
|
+
return enum_for(:drop_while) if not block_given?
|
397
|
+
self.class.new(super)
|
398
|
+
end
|
399
|
+
|
400
|
+
# Gather elements up to, but not including, the first element for which the
|
401
|
+
# block returns `nil` or `false`, and return them in a new `SortedSet`. If no block
|
402
|
+
# is given, an `Enumerator` is returned instead.
|
403
|
+
#
|
404
|
+
# @return [SortedSet, Enumerator]
|
405
|
+
def take_while
|
406
|
+
return enum_for(:take_while) if not block_given?
|
407
|
+
self.class.new(super)
|
408
|
+
end
|
409
|
+
|
410
|
+
# Return a new `SortedSet` which contains all the members of both this set and `other`.
|
411
|
+
# `other` can be any `Enumerable` object.
|
412
|
+
#
|
413
|
+
# @example
|
414
|
+
# Hamster::SortedSet[1, 2] | Hamster::SortedSet[2, 3]
|
415
|
+
# # => Hamster::SortedSet[1, 2, 3]
|
416
|
+
#
|
417
|
+
# @param other [Enumerable] The collection to merge with
|
418
|
+
# @return [SortedSet]
|
419
|
+
def union(other)
|
420
|
+
self.class.alloc(@node.bulk_insert(other, @comparator), @comparator)
|
421
|
+
end
|
422
|
+
def_delegator :self, :union, :|
|
423
|
+
def_delegator :self, :union, :+
|
424
|
+
def_delegator :self, :union, :merge
|
425
|
+
|
426
|
+
# Return a new `SortedSet` which contains all the items which are members of both
|
427
|
+
# this set and `other`. `other` can be any `Enumerable` object.
|
428
|
+
#
|
429
|
+
# @example
|
430
|
+
# Hamster::SortedSet[1, 2] & Hamster::SortedSet[2, 3]
|
431
|
+
# # => Hamster::SortedSet[2]
|
432
|
+
#
|
433
|
+
# @param other [Enumerable] The collection to intersect with
|
434
|
+
# @return [SortedSet]
|
435
|
+
def intersection(other)
|
436
|
+
self.class.alloc(@node.keep_only(other, @comparator), @comparator)
|
437
|
+
end
|
438
|
+
def_delegator :self, :intersection, :intersect
|
439
|
+
def_delegator :self, :intersection, :&
|
440
|
+
|
441
|
+
# Return a new `SortedSet` with all the items in `other` removed. `other` can be
|
442
|
+
# any `Enumerable` object.
|
443
|
+
#
|
444
|
+
# @example
|
445
|
+
# Hamster::SortedSet[1, 2] - Hamster::SortedSet[2, 3]
|
446
|
+
# # => Hamster::SortedSet[1]
|
447
|
+
#
|
448
|
+
# @param other [Enumerable] The collection to subtract from this set
|
449
|
+
# @return [SortedSet]
|
450
|
+
def difference(other)
|
451
|
+
self.class.alloc(@node.bulk_delete(other, @comparator), @comparator)
|
452
|
+
end
|
453
|
+
def_delegator :self, :difference, :diff
|
454
|
+
def_delegator :self, :difference, :subtract
|
455
|
+
def_delegator :self, :difference, :-
|
456
|
+
|
457
|
+
# Return a new `SortedSet` with all the items which are members of this
|
458
|
+
# set or of `other`, but not both. `other` can be any `Enumerable` object.
|
459
|
+
#
|
460
|
+
# @example
|
461
|
+
# Hamster::SortedSet[1, 2] ^ Hamster::SortedSet[2, 3]
|
462
|
+
# # => Hamster::SortedSet[1, 3]
|
463
|
+
#
|
464
|
+
# @param other [Enumerable] The collection to take the exclusive disjunction of
|
465
|
+
# @return [SortedSet]
|
466
|
+
def exclusion(other)
|
467
|
+
((self | other) - (self & other))
|
468
|
+
end
|
469
|
+
def_delegator :self, :exclusion, :^
|
470
|
+
|
471
|
+
# Return `true` if all items in this set are also in `other`.
|
472
|
+
#
|
473
|
+
# @param other [Enumerable]
|
474
|
+
# @return [Boolean]
|
475
|
+
def subset?(other)
|
476
|
+
return false if other.size < size
|
477
|
+
all? { |item| other.include?(item) }
|
478
|
+
end
|
479
|
+
|
480
|
+
# Return `true` if all items in `other` are also in this set.
|
481
|
+
#
|
482
|
+
# @param other [Enumerable]
|
483
|
+
# @return [Boolean]
|
484
|
+
def superset?(other)
|
485
|
+
other.subset?(self)
|
486
|
+
end
|
487
|
+
|
488
|
+
# Returns `true` if `other` contains all the items in this set, plus at least
|
489
|
+
# one item which is not in this set.
|
490
|
+
#
|
491
|
+
# @param other [Enumerable]
|
492
|
+
# @return [Boolean]
|
493
|
+
def proper_subset?(other)
|
494
|
+
return false if other.size <= size
|
495
|
+
all? { |item| other.include?(item) }
|
496
|
+
end
|
497
|
+
|
498
|
+
# Returns `true` if this set contains all the items in `other`, plus at least
|
499
|
+
# one item which is not in `other`.
|
500
|
+
#
|
501
|
+
# @param other [Enumerable]
|
502
|
+
# @return [Boolean]
|
503
|
+
def proper_superset?(other)
|
504
|
+
other.proper_subset?(self)
|
505
|
+
end
|
506
|
+
|
507
|
+
# Return `true` if this set and `other` do not share any items.
|
508
|
+
#
|
509
|
+
# @param other [Enumerable]
|
510
|
+
# @return [Boolean]
|
511
|
+
def disjoint?(other)
|
512
|
+
if size < other.size
|
513
|
+
each { |item| return false if other.include?(item) }
|
514
|
+
else
|
515
|
+
other.each { |item| return false if include?(item) }
|
516
|
+
end
|
517
|
+
true
|
518
|
+
end
|
519
|
+
|
520
|
+
# Return `true` if this set and `other` have at least one item in common.
|
521
|
+
#
|
522
|
+
# @param other [Enumerable]
|
523
|
+
# @return [Boolean]
|
524
|
+
def intersect?(other)
|
525
|
+
!disjoint?(other)
|
526
|
+
end
|
527
|
+
|
528
|
+
def_delegator :self, :group_by, :group
|
529
|
+
def_delegator :self, :group_by, :classify
|
530
|
+
|
531
|
+
# With a block, yield all the items which are "higher" than `item` (as defined
|
532
|
+
# by the set's comparator). Otherwise, return them as a new `SortedSet`.
|
533
|
+
#
|
534
|
+
# @param item [Object]
|
535
|
+
def above(item, &block)
|
536
|
+
if block_given?
|
537
|
+
@node.each_greater(item, @comparator, false, &block)
|
538
|
+
else
|
539
|
+
self.class.alloc(@node.suffix(item, @comparator, false), @comparator)
|
540
|
+
end
|
541
|
+
end
|
542
|
+
|
543
|
+
# With a block, yield all the items which are "higher" than `item` (as defined
|
544
|
+
# by the set's comparator). Otherwise, return them as a new `SortedSet`.
|
545
|
+
#
|
546
|
+
# @param item [Object]
|
547
|
+
def below(item, &block)
|
548
|
+
if block_given?
|
549
|
+
@node.each_less(item, @comparator, false, &block)
|
550
|
+
else
|
551
|
+
self.class.alloc(@node.prefix(item, @comparator, false), @comparator)
|
552
|
+
end
|
553
|
+
end
|
554
|
+
|
555
|
+
# With a block, yield all the items which are "higher" or equal to `item`
|
556
|
+
# (as determined by the set's comparator). Otherwise, return them as a new
|
557
|
+
# `SortedSet`.
|
558
|
+
#
|
559
|
+
# @param item [Object]
|
560
|
+
def from(item, &block)
|
561
|
+
if block_given?
|
562
|
+
@node.each_greater(item, @comparator, true, &block)
|
563
|
+
else
|
564
|
+
self.class.alloc(@node.suffix(item, @comparator, true), @comparator)
|
565
|
+
end
|
566
|
+
end
|
567
|
+
|
568
|
+
# With a block, yield all the items which are "lower" than `item` (as defined
|
569
|
+
# by the set's comparator). Otherwise, return them as a new `SortedSet`.
|
570
|
+
#
|
571
|
+
# @param item [Object]
|
572
|
+
def up_to(item, &block)
|
573
|
+
if block_given?
|
574
|
+
@node.each_less(item, @comparator, true, &block)
|
575
|
+
else
|
576
|
+
self.class.alloc(@node.prefix(item, @comparator, true), @comparator)
|
577
|
+
end
|
578
|
+
end
|
579
|
+
|
580
|
+
# With a block, yield all the items which are equal or higher than `from` and
|
581
|
+
# equal or less than `to` (as determined by the set's comparator). Otherwise,
|
582
|
+
# return the specified range of items as a new `SortedSet`.
|
583
|
+
#
|
584
|
+
# @param from [Object]
|
585
|
+
# @param to [Object]
|
586
|
+
def between(from, to, &block)
|
587
|
+
if block_given?
|
588
|
+
@node.each_between(from, to, @comparator, &block)
|
589
|
+
else
|
590
|
+
self.class.alloc(@node.between(from, to, @comparator), @comparator)
|
591
|
+
end
|
592
|
+
end
|
593
|
+
|
594
|
+
# Return a randomly chosen item from this set. If the set is empty, return `nil`.
|
595
|
+
#
|
596
|
+
# @return [Object]
|
597
|
+
def sample
|
598
|
+
@node.at(rand(@node.size))
|
599
|
+
end
|
600
|
+
|
601
|
+
# Return an empty `SortedSet` instance, of the same class as this one. Useful if you
|
602
|
+
# have multiple subclasses of `SortedSet` and want to treat them polymorphically.
|
603
|
+
#
|
604
|
+
# @return [Hash]
|
605
|
+
def clear
|
606
|
+
self.class.empty
|
607
|
+
end
|
608
|
+
|
609
|
+
# Return true if `other` has the same type and contents as this `SortedSet`.
|
610
|
+
#
|
611
|
+
# @param other [Object] The object to compare with
|
612
|
+
# @return [Boolean]
|
613
|
+
def eql?(other)
|
614
|
+
return true if other.equal?(self)
|
615
|
+
return false if not instance_of?(other.class)
|
616
|
+
return false if size != other.size
|
617
|
+
a, b = self.to_enum, other.to_enum
|
618
|
+
while true
|
619
|
+
return false if !a.next.eql?(b.next)
|
620
|
+
end
|
621
|
+
rescue StopIteration
|
622
|
+
true
|
623
|
+
end
|
624
|
+
|
625
|
+
# See `Object#hash`.
|
626
|
+
# @return [Integer]
|
627
|
+
def hash
|
628
|
+
reduce(0) { |hash, item| (hash << 5) - hash + item.hash }
|
629
|
+
end
|
630
|
+
|
631
|
+
def_delegator :self, :dup, :uniq
|
632
|
+
def_delegator :self, :dup, :nub
|
633
|
+
def_delegator :self, :dup, :remove_duplicates
|
634
|
+
|
635
|
+
# @return [::Array]
|
636
|
+
# @private
|
637
|
+
def marshal_dump
|
638
|
+
if @comparator
|
639
|
+
raise TypeError, "can't dump SortedSet with custom sort order"
|
640
|
+
else
|
641
|
+
to_a
|
642
|
+
end
|
643
|
+
end
|
644
|
+
|
645
|
+
# @private
|
646
|
+
def marshal_load(array)
|
647
|
+
initialize(array)
|
648
|
+
end
|
649
|
+
|
650
|
+
private
|
651
|
+
|
652
|
+
def subsequence(from, length)
|
653
|
+
return nil if from > @node.size || from < 0 || length < 0
|
654
|
+
length = @node.size - from if @node.size < from + length
|
655
|
+
return self.class.empty if length == 0
|
656
|
+
self.class.alloc(@node.slice(from, length), @comparator)
|
657
|
+
end
|
658
|
+
|
659
|
+
# @private
|
660
|
+
class AVLNode
|
661
|
+
def self.from_items(items, from, to) # items must be sorted
|
662
|
+
size = to - from + 1
|
663
|
+
if size >= 3
|
664
|
+
middle = (to + from) / 2
|
665
|
+
AVLNode.new(items[middle], AVLNode.from_items(items, from, middle-1), AVLNode.from_items(items, middle+1, to))
|
666
|
+
elsif size == 2
|
667
|
+
AVLNode.new(items[from], EmptyAVLNode, AVLNode.new(items[from+1], EmptyAVLNode, EmptyAVLNode))
|
668
|
+
elsif size == 1
|
669
|
+
AVLNode.new(items[from], EmptyAVLNode, EmptyAVLNode)
|
670
|
+
elsif size == 0
|
671
|
+
EmptyAVLNode
|
672
|
+
end
|
673
|
+
end
|
674
|
+
|
675
|
+
def initialize(item, left, right)
|
676
|
+
@item, @left, @right = item, left, right
|
677
|
+
@height = ((@right.height > @left.height) ? @right.height : @left.height) + 1
|
678
|
+
@size = @right.size + @left.size + 1
|
679
|
+
end
|
680
|
+
attr_reader :item, :left, :right, :height, :size
|
681
|
+
|
682
|
+
def empty?
|
683
|
+
false
|
684
|
+
end
|
685
|
+
|
686
|
+
def insert(item, comparator)
|
687
|
+
dir = direction(item, comparator)
|
688
|
+
if dir == 0
|
689
|
+
self
|
690
|
+
elsif dir > 0
|
691
|
+
rebalance_right(@left, @right.insert(item, comparator))
|
692
|
+
else
|
693
|
+
rebalance_left(@left.insert(item, comparator), @right)
|
694
|
+
end
|
695
|
+
end
|
696
|
+
|
697
|
+
def bulk_insert(items, comparator)
|
698
|
+
return self if items.empty?
|
699
|
+
return insert(items.first, comparator) if items.size == 1
|
700
|
+
|
701
|
+
left, right = partition(items, comparator)
|
702
|
+
|
703
|
+
if right.size > left.size
|
704
|
+
rebalance_right(@left.bulk_insert(left, comparator), @right.bulk_insert(right, comparator))
|
705
|
+
else
|
706
|
+
rebalance_left(@left.bulk_insert(left, comparator), @right.bulk_insert(right, comparator))
|
707
|
+
end
|
708
|
+
end
|
709
|
+
|
710
|
+
def delete(item, comparator)
|
711
|
+
dir = direction(item, comparator)
|
712
|
+
if dir == 0
|
713
|
+
if @right.empty?
|
714
|
+
return @left # replace this node with its only child
|
715
|
+
elsif @left.empty?
|
716
|
+
return @right # likewise
|
717
|
+
end
|
718
|
+
|
719
|
+
if balance > 0
|
720
|
+
# tree is leaning to the left. replace with highest node on that side
|
721
|
+
replace_with = @left.max
|
722
|
+
AVLNode.new(replace_with, @left.delete(replace_with, comparator), @right)
|
723
|
+
else
|
724
|
+
# tree is leaning to the right. replace with lowest node on that side
|
725
|
+
replace_with = @right.min
|
726
|
+
AVLNode.new(replace_with, @left, @right.delete(replace_with, comparator))
|
727
|
+
end
|
728
|
+
elsif dir > 0
|
729
|
+
rebalance_left(@left, @right.delete(item, comparator))
|
730
|
+
else
|
731
|
+
rebalance_right(@left.delete(item, comparator), @right)
|
732
|
+
end
|
733
|
+
end
|
734
|
+
|
735
|
+
def bulk_delete(items, comparator)
|
736
|
+
return self if items.empty?
|
737
|
+
return delete(items.first, comparator) if items.size == 1
|
738
|
+
|
739
|
+
left, right, keep_item = [], [], true
|
740
|
+
items.each do |item|
|
741
|
+
dir = direction(item, comparator)
|
742
|
+
if dir > 0
|
743
|
+
right << item
|
744
|
+
elsif dir < 0
|
745
|
+
left << item
|
746
|
+
else
|
747
|
+
keep_item = false
|
748
|
+
end
|
749
|
+
end
|
750
|
+
|
751
|
+
left = @left.bulk_delete(left, comparator)
|
752
|
+
right = @right.bulk_delete(right, comparator)
|
753
|
+
finish_removal(keep_item, left, right, comparator)
|
754
|
+
end
|
755
|
+
|
756
|
+
def keep_only(items, comparator)
|
757
|
+
return EmptyAVLNode if items.empty?
|
758
|
+
|
759
|
+
left, right, keep_item = [], [], false
|
760
|
+
items.each do |item|
|
761
|
+
dir = direction(item, comparator)
|
762
|
+
if dir > 0
|
763
|
+
right << item
|
764
|
+
elsif dir < 0
|
765
|
+
left << item
|
766
|
+
else
|
767
|
+
keep_item = true
|
768
|
+
end
|
769
|
+
end
|
770
|
+
|
771
|
+
left = @left.keep_only(left, comparator)
|
772
|
+
right = @right.keep_only(right, comparator)
|
773
|
+
finish_removal(keep_item, left, right, comparator)
|
774
|
+
end
|
775
|
+
|
776
|
+
def finish_removal(keep_item, left, right, comparator)
|
777
|
+
# deletion of items may have occurred on left and right sides
|
778
|
+
# now we may also need to delete the current item
|
779
|
+
if keep_item
|
780
|
+
rebalance(left, right) # no need to delete the current item
|
781
|
+
elsif left.empty?
|
782
|
+
right
|
783
|
+
elsif right.empty?
|
784
|
+
left
|
785
|
+
elsif left.height > right.height
|
786
|
+
replace_with = left.max
|
787
|
+
AVLNode.new(replace_with, left.delete(replace_with, comparator), right)
|
788
|
+
else
|
789
|
+
replace_with = right.min
|
790
|
+
AVLNode.new(replace_with, left, right.delete(replace_with, comparator))
|
791
|
+
end
|
792
|
+
end
|
793
|
+
|
794
|
+
def prefix(item, comparator, inclusive)
|
795
|
+
dir = direction(item, comparator)
|
796
|
+
if dir > 0 || (inclusive && dir == 0)
|
797
|
+
rebalance_left(@left, @right.prefix(item, comparator, inclusive))
|
798
|
+
else
|
799
|
+
@left.prefix(item, comparator, inclusive)
|
800
|
+
end
|
801
|
+
end
|
802
|
+
|
803
|
+
def suffix(item, comparator, inclusive)
|
804
|
+
dir = direction(item, comparator)
|
805
|
+
if dir < 0 || (inclusive && dir == 0)
|
806
|
+
rebalance_right(@left.suffix(item, comparator, inclusive), @right)
|
807
|
+
else
|
808
|
+
@right.suffix(item, comparator, inclusive)
|
809
|
+
end
|
810
|
+
end
|
811
|
+
|
812
|
+
def between(from, to, comparator)
|
813
|
+
if direction(from, comparator) > 0 # all on the right
|
814
|
+
@right.between(from, to, comparator)
|
815
|
+
elsif direction(to, comparator) < 0 # all on the left
|
816
|
+
@left.between(from, to, comparator)
|
817
|
+
else
|
818
|
+
left = @left.suffix(from, comparator, true)
|
819
|
+
right = @right.prefix(to, comparator, true)
|
820
|
+
rebalance(left, right)
|
821
|
+
end
|
822
|
+
end
|
823
|
+
|
824
|
+
def each_less(item, comparator, inclusive, &block)
|
825
|
+
dir = direction(item, comparator)
|
826
|
+
if dir > 0 || (inclusive && dir == 0)
|
827
|
+
@left.each(&block)
|
828
|
+
yield @item
|
829
|
+
@right.each_less(item, comparator, inclusive, &block)
|
830
|
+
else
|
831
|
+
@left.each_less(item, comparator, inclusive, &block)
|
832
|
+
end
|
833
|
+
end
|
834
|
+
|
835
|
+
def each_greater(item, comparator, inclusive, &block)
|
836
|
+
dir = direction(item, comparator)
|
837
|
+
if dir < 0 || (inclusive && dir == 0)
|
838
|
+
@left.each_greater(item, comparator, inclusive, &block)
|
839
|
+
yield @item
|
840
|
+
@right.each(&block)
|
841
|
+
else
|
842
|
+
@right.each_greater(item, comparator, inclusive, &block)
|
843
|
+
end
|
844
|
+
end
|
845
|
+
|
846
|
+
def each_between(from, to, comparator, &block)
|
847
|
+
if direction(from, comparator) > 0 # all on the right
|
848
|
+
@right.each_between(from, to, comparator, &block)
|
849
|
+
elsif direction(to, comparator) < 0 # all on the left
|
850
|
+
@left.each_between(from, to, comparator, &block)
|
851
|
+
else
|
852
|
+
@left.each_greater(from, comparator, true, &block)
|
853
|
+
yield @item
|
854
|
+
@right.each_less(to, comparator, true, &block)
|
855
|
+
end
|
856
|
+
end
|
857
|
+
|
858
|
+
def each(&block)
|
859
|
+
@left.each(&block)
|
860
|
+
yield @item
|
861
|
+
@right.each(&block)
|
862
|
+
end
|
863
|
+
|
864
|
+
def reverse_each(&block)
|
865
|
+
@right.reverse_each(&block)
|
866
|
+
yield @item
|
867
|
+
@left.reverse_each(&block)
|
868
|
+
end
|
869
|
+
|
870
|
+
def include?(item, comparator)
|
871
|
+
dir = direction(item, comparator)
|
872
|
+
if dir == 0
|
873
|
+
true
|
874
|
+
elsif dir > 0
|
875
|
+
@right.include?(item, comparator)
|
876
|
+
else
|
877
|
+
@left.include?(item, comparator)
|
878
|
+
end
|
879
|
+
end
|
880
|
+
|
881
|
+
def at(index)
|
882
|
+
if index < @left.size
|
883
|
+
@left.at(index)
|
884
|
+
elsif index > @left.size
|
885
|
+
@right.at(index - @left.size - 1)
|
886
|
+
else
|
887
|
+
@item
|
888
|
+
end
|
889
|
+
end
|
890
|
+
|
891
|
+
def max
|
892
|
+
@right.empty? ? @item : @right.max
|
893
|
+
end
|
894
|
+
|
895
|
+
def min
|
896
|
+
@left.empty? ? @item : @left.min
|
897
|
+
end
|
898
|
+
|
899
|
+
def balance
|
900
|
+
@left.height - @right.height
|
901
|
+
end
|
902
|
+
|
903
|
+
def slice(from, length)
|
904
|
+
if length <= 0
|
905
|
+
EmptyAVLNode
|
906
|
+
elsif from + length <= @left.size
|
907
|
+
@left.slice(from, length)
|
908
|
+
elsif from > @left.size
|
909
|
+
@right.slice(from - @left.size - 1, length)
|
910
|
+
else
|
911
|
+
left = @left.slice(from, @left.size - from)
|
912
|
+
right = @right.slice(0, from + length - @left.size - 1)
|
913
|
+
rebalance(left, right)
|
914
|
+
end
|
915
|
+
end
|
916
|
+
|
917
|
+
def partition(items, comparator)
|
918
|
+
left, right = [], []
|
919
|
+
items.each do |item|
|
920
|
+
dir = direction(item, comparator)
|
921
|
+
if dir > 0
|
922
|
+
right << item
|
923
|
+
elsif dir < 0
|
924
|
+
left << item
|
925
|
+
end
|
926
|
+
end
|
927
|
+
[left, right]
|
928
|
+
end
|
929
|
+
|
930
|
+
def rebalance(left, right)
|
931
|
+
if left.height > right.height
|
932
|
+
rebalance_left(left, right)
|
933
|
+
else
|
934
|
+
rebalance_right(left, right)
|
935
|
+
end
|
936
|
+
end
|
937
|
+
|
938
|
+
def rebalance_left(left, right)
|
939
|
+
# the tree might be unbalanced to the left (paths on the left too long)
|
940
|
+
balance = left.height - right.height
|
941
|
+
if balance >= 2
|
942
|
+
if left.balance > 0
|
943
|
+
# single right rotation
|
944
|
+
AVLNode.new(left.item, left.left, AVLNode.new(@item, left.right, right))
|
945
|
+
else
|
946
|
+
# left rotation, then right
|
947
|
+
AVLNode.new(left.right.item, AVLNode.new(left.item, left.left, left.right.left), AVLNode.new(@item, left.right.right, right))
|
948
|
+
end
|
949
|
+
else
|
950
|
+
AVLNode.new(@item, left, right)
|
951
|
+
end
|
952
|
+
end
|
953
|
+
|
954
|
+
def rebalance_right(left, right)
|
955
|
+
# the tree might be unbalanced to the right (paths on the right too long)
|
956
|
+
balance = left.height - right.height
|
957
|
+
if balance <= -2
|
958
|
+
if right.balance > 0
|
959
|
+
# right rotation, then left
|
960
|
+
AVLNode.new(right.left.item, AVLNode.new(@item, left, right.left.left), AVLNode.new(right.item, right.left.right, right.right))
|
961
|
+
else
|
962
|
+
# single left rotation
|
963
|
+
AVLNode.new(right.item, AVLNode.new(@item, left, right.left), right.right)
|
964
|
+
end
|
965
|
+
else
|
966
|
+
AVLNode.new(@item, left, right)
|
967
|
+
end
|
968
|
+
end
|
969
|
+
|
970
|
+
def direction(item, comparator)
|
971
|
+
if comparator
|
972
|
+
comparator.call(item, @item)
|
973
|
+
else
|
974
|
+
item <=> @item
|
975
|
+
end
|
976
|
+
end
|
977
|
+
end
|
978
|
+
|
979
|
+
EmptyAVLNode = Object.new.tap do |e|
|
980
|
+
def e.left; self; end
|
981
|
+
def e.right; self; end
|
982
|
+
def e.height; 0; end
|
983
|
+
def e.size; 0; end
|
984
|
+
def e.min; nil; end
|
985
|
+
def e.max; nil; end
|
986
|
+
def e.each; end
|
987
|
+
def e.reverse_each; end
|
988
|
+
def e.at(index); nil; end
|
989
|
+
def e.insert(item, comparator); AVLNode.new(item, self, self); end
|
990
|
+
def e.bulk_insert(items, comparator)
|
991
|
+
items = items.to_a if !items.is_a?(Array)
|
992
|
+
AVLNode.from_items(items.sort(&comparator), 0, items.size-1)
|
993
|
+
end
|
994
|
+
def e.bulk_delete(items, comparator); self; end
|
995
|
+
def e.keep_only(items, comparator); self; end
|
996
|
+
def e.delete(item, comparator); self; end
|
997
|
+
def e.include?(item, comparator); false; end
|
998
|
+
def e.prefix(item, comparator, inclusive); self; end
|
999
|
+
def e.suffix(item, comparator, inclusive); self; end
|
1000
|
+
def e.between(from, to, comparator); self; end
|
1001
|
+
def e.each_greater(item, comparator, inclusive); end
|
1002
|
+
def e.each_less(item, comparator, inclusive); end
|
1003
|
+
def e.each_between(item, comparator, inclusive); end
|
1004
|
+
def e.empty?; true; end
|
1005
|
+
def e.slice(from, length); self; end
|
1006
|
+
end.freeze
|
1007
|
+
end
|
1008
|
+
|
1009
|
+
# The canonical empty `SortedSet`. Returned by `Hamster.sorted_set` and `SortedSet[]`
|
1010
|
+
# when invoked with no arguments; also returned by `SortedSet.empty`. Prefer using
|
1011
|
+
# this one rather than creating many empty sorted sets using `SortedSet.new`.
|
1012
|
+
#
|
1013
|
+
EmptySortedSet = Hamster::SortedSet.empty
|
1014
|
+
end
|