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