hamster 0.4.3 → 1.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 +7 -0
- data/lib/hamster.rb +11 -9
- data/lib/hamster/core_ext.rb +2 -3
- data/lib/hamster/core_ext/enumerable.rb +18 -27
- data/lib/hamster/core_ext/io.rb +16 -25
- data/lib/hamster/deque.rb +252 -0
- data/lib/hamster/enumerable.rb +123 -112
- data/lib/hamster/experimental/mutable_queue.rb +5 -14
- data/lib/hamster/experimental/mutable_set.rb +7 -14
- data/lib/hamster/hash.rb +732 -102
- data/lib/hamster/immutable.rb +4 -10
- data/lib/hamster/list.rb +1155 -215
- data/lib/hamster/{experimental/mutable_hash.rb → mutable_hash.rb} +11 -14
- data/lib/hamster/nested.rb +36 -0
- data/lib/hamster/{experimental/read_copy_update.rb → read_copy_update.rb} +10 -8
- data/lib/hamster/set.rb +488 -90
- data/lib/hamster/sorted_set.rb +1397 -0
- data/lib/hamster/trie.rb +210 -65
- data/lib/hamster/undefined.rb +1 -7
- data/lib/hamster/vector.rb +1329 -83
- data/lib/hamster/version.rb +1 -3
- data/spec/{hamster/core_ext → fixtures}/io_spec.txt +0 -0
- data/spec/lib/hamster/core_ext/array_spec.rb +14 -0
- data/spec/lib/hamster/core_ext/enumerable_spec.rb +30 -0
- data/spec/lib/hamster/core_ext/io_spec.rb +29 -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 +35 -0
- data/spec/lib/hamster/deque/empty_spec.rb +40 -0
- data/spec/lib/hamster/deque/enqueue_spec.rb +28 -0
- data/spec/lib/hamster/deque/first_spec.rb +18 -0
- data/spec/lib/hamster/deque/inspect_spec.rb +24 -0
- data/spec/lib/hamster/deque/last_spec.rb +18 -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 +33 -0
- data/spec/lib/hamster/deque/pretty_print_spec.rb +24 -0
- data/spec/lib/hamster/deque/random_modification_spec.rb +34 -0
- data/spec/lib/hamster/deque/size_spec.rb +20 -0
- data/spec/lib/hamster/deque/to_a_spec.rb +27 -0
- data/spec/lib/hamster/deque/to_ary_spec.rb +36 -0
- data/spec/lib/hamster/deque/to_list_spec.rb +26 -0
- data/spec/lib/hamster/deque/unshift_spec.rb +26 -0
- data/spec/lib/hamster/experimental/mutable_set/add_qm_spec.rb +39 -0
- data/spec/lib/hamster/experimental/mutable_set/add_spec.rb +37 -0
- data/spec/lib/hamster/experimental/mutable_set/delete_qm_spec.rb +38 -0
- data/spec/lib/hamster/experimental/mutable_set/delete_spec.rb +37 -0
- data/spec/lib/hamster/hash/all_spec.rb +54 -0
- data/spec/lib/hamster/hash/any_spec.rb +54 -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/lib/hamster/hash/copying_spec.rb +14 -0
- 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 +44 -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/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/lib/hamster/hash/hash_spec.rb +30 -0
- data/spec/{hamster → lib/hamster}/hash/immutable_spec.rb +3 -6
- 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/lib/hamster/hash/keys_spec.rb +17 -0
- data/spec/lib/hamster/hash/map_spec.rb +46 -0
- data/spec/lib/hamster/hash/marshal_spec.rb +29 -0
- data/spec/lib/hamster/hash/merge_spec.rb +83 -0
- data/spec/lib/hamster/hash/min_max_spec.rb +46 -0
- data/spec/lib/hamster/hash/new_spec.rb +71 -0
- data/spec/lib/hamster/hash/none_spec.rb +49 -0
- 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 +103 -0
- data/spec/lib/hamster/hash/reduce_spec.rb +36 -0
- data/spec/lib/hamster/hash/reject_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/lib/hamster/hash/select_spec.rb +58 -0
- data/spec/{hamster → lib/hamster}/hash/size_spec.rb +9 -18
- 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 +76 -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/lib/hamster/hash/update_in_spec.rb +80 -0
- 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 +3 -10
- data/spec/{hamster → lib/hamster}/immutable/immutable_spec.rb +3 -16
- data/spec/lib/hamster/immutable/memoize_spec.rb +56 -0
- data/spec/lib/hamster/immutable/new_spec.rb +14 -0
- data/spec/lib/hamster/immutable/transform_spec.rb +26 -0
- data/spec/lib/hamster/immutable/transform_unless_spec.rb +44 -0
- data/spec/lib/hamster/list/add_spec.rb +26 -0
- data/spec/lib/hamster/list/all_spec.rb +58 -0
- data/spec/lib/hamster/list/any_spec.rb +50 -0
- data/spec/lib/hamster/list/append_spec.rb +39 -0
- data/spec/lib/hamster/list/at_spec.rb +30 -0
- data/spec/lib/hamster/list/break_spec.rb +70 -0
- data/spec/lib/hamster/list/cadr_spec.rb +39 -0
- data/spec/lib/hamster/list/chunk_spec.rb +29 -0
- data/spec/lib/hamster/list/clear_spec.rb +25 -0
- data/spec/lib/hamster/list/combination_spec.rb +34 -0
- data/spec/lib/hamster/list/compact_spec.rb +35 -0
- data/spec/lib/hamster/list/compare_spec.rb +31 -0
- data/spec/lib/hamster/list/cons_spec.rb +26 -0
- data/spec/lib/hamster/list/construction_spec.rb +111 -0
- data/spec/lib/hamster/list/copying_spec.rb +20 -0
- 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/lib/hamster/list/drop_spec.rb +31 -0
- 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 +41 -0
- data/spec/lib/hamster/list/each_with_index_spec.rb +29 -0
- data/spec/lib/hamster/list/empty_spec.rb +24 -0
- data/spec/lib/hamster/list/eql_spec.rb +62 -0
- data/spec/lib/hamster/list/fill_spec.rb +50 -0
- data/spec/lib/hamster/list/find_all_spec.rb +71 -0
- data/spec/{hamster → lib/hamster}/list/find_index_spec.rb +7 -29
- data/spec/{hamster → lib/hamster}/list/find_spec.rb +13 -35
- data/spec/lib/hamster/list/flat_map_spec.rb +52 -0
- data/spec/lib/hamster/list/flatten_spec.rb +31 -0
- data/spec/lib/hamster/list/grep_spec.rb +47 -0
- data/spec/lib/hamster/list/group_by_spec.rb +42 -0
- data/spec/lib/hamster/list/hash_spec.rb +22 -0
- data/spec/{hamster → lib/hamster}/list/head_spec.rb +6 -21
- data/spec/{hamster → lib/hamster}/list/include_spec.rb +8 -29
- data/spec/lib/hamster/list/index_spec.rb +34 -0
- data/spec/lib/hamster/list/indices_spec.rb +62 -0
- data/spec/lib/hamster/list/init_spec.rb +29 -0
- 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/lib/hamster/list/intersperse_spec.rb +29 -0
- data/spec/lib/hamster/list/join_spec.rb +64 -0
- data/spec/lib/hamster/list/last_spec.rb +24 -0
- data/spec/lib/hamster/list/ltlt_spec.rb +20 -0
- data/spec/lib/hamster/list/map_spec.rb +46 -0
- data/spec/lib/hamster/list/maximum_spec.rb +40 -0
- data/spec/{hamster → lib/hamster}/list/merge_by_spec.rb +9 -36
- data/spec/{hamster → lib/hamster}/list/merge_spec.rb +5 -24
- data/spec/lib/hamster/list/minimum_spec.rb +40 -0
- data/spec/lib/hamster/list/multithreading_spec.rb +48 -0
- data/spec/{hamster → lib/hamster}/list/none_spec.rb +14 -41
- data/spec/{hamster → lib/hamster}/list/one_spec.rb +15 -40
- data/spec/lib/hamster/list/partition_spec.rb +116 -0
- data/spec/lib/hamster/list/permutation_spec.rb +56 -0
- data/spec/lib/hamster/list/pop_spec.rb +26 -0
- data/spec/lib/hamster/list/product_spec.rb +24 -0
- data/spec/lib/hamster/list/reduce_spec.rb +54 -0
- data/spec/lib/hamster/list/reject_spec.rb +46 -0
- data/spec/lib/hamster/list/reverse_spec.rb +35 -0
- data/spec/lib/hamster/list/rotate_spec.rb +37 -0
- data/spec/lib/hamster/list/sample_spec.rb +14 -0
- data/spec/lib/hamster/list/select_spec.rb +71 -0
- data/spec/lib/hamster/list/size_spec.rb +26 -0
- data/spec/lib/hamster/list/slice_spec.rb +230 -0
- data/spec/lib/hamster/list/sorting_spec.rb +47 -0
- data/spec/lib/hamster/list/span_spec.rb +77 -0
- data/spec/lib/hamster/list/split_at_spec.rb +44 -0
- 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/lib/hamster/list/take_spec.rb +31 -0
- data/spec/lib/hamster/list/take_while_spec.rb +47 -0
- data/spec/lib/hamster/list/to_a_spec.rb +40 -0
- data/spec/lib/hamster/list/to_ary_spec.rb +42 -0
- data/spec/lib/hamster/list/to_list_spec.rb +20 -0
- data/spec/lib/hamster/list/to_set_spec.rb +19 -0
- data/spec/lib/hamster/list/transpose_spec.rb +20 -0
- data/spec/lib/hamster/list/union_spec.rb +32 -0
- data/spec/lib/hamster/list/uniq_spec.rb +30 -0
- data/spec/lib/hamster/list/zip_spec.rb +24 -0
- data/spec/lib/hamster/nested/construction_spec.rb +44 -0
- data/spec/lib/hamster/set/add_spec.rb +76 -0
- data/spec/lib/hamster/set/all_spec.rb +52 -0
- data/spec/lib/hamster/set/any_spec.rb +52 -0
- data/spec/lib/hamster/set/clear_spec.rb +34 -0
- data/spec/{hamster → lib/hamster}/set/compact_spec.rb +9 -20
- data/spec/lib/hamster/set/construction_spec.rb +19 -0
- data/spec/lib/hamster/set/copying_spec.rb +14 -0
- data/spec/lib/hamster/set/count_spec.rb +37 -0
- 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 +45 -0
- data/spec/lib/hamster/set/eqeq_spec.rb +104 -0
- data/spec/lib/hamster/set/eql_spec.rb +110 -0
- data/spec/lib/hamster/set/exclusion_spec.rb +48 -0
- data/spec/{hamster → lib/hamster}/set/find_spec.rb +10 -27
- data/spec/lib/hamster/set/first_spec.rb +29 -0
- data/spec/lib/hamster/set/flatten_spec.rb +47 -0
- data/spec/lib/hamster/set/grep_spec.rb +58 -0
- data/spec/lib/hamster/set/group_by_spec.rb +60 -0
- data/spec/lib/hamster/set/hash_spec.rb +23 -0
- data/spec/{hamster → lib/hamster}/set/immutable_spec.rb +4 -7
- 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/lib/hamster/set/marshal_spec.rb +29 -0
- data/spec/lib/hamster/set/maximum_spec.rb +37 -0
- data/spec/lib/hamster/set/minimum_spec.rb +37 -0
- data/spec/lib/hamster/set/new_spec.rb +54 -0
- data/spec/{hamster → lib/hamster}/set/none_spec.rb +17 -32
- data/spec/{hamster → lib/hamster}/set/one_spec.rb +16 -31
- data/spec/lib/hamster/set/partition_spec.rb +53 -0
- data/spec/lib/hamster/set/product_spec.rb +24 -0
- data/spec/lib/hamster/set/reduce_spec.rb +56 -0
- data/spec/lib/hamster/set/reject_spec.rb +51 -0
- data/spec/lib/hamster/set/reverse_each_spec.rb +39 -0
- data/spec/lib/hamster/set/sample_spec.rb +14 -0
- data/spec/lib/hamster/set/select_spec.rb +74 -0
- data/spec/{hamster → lib/hamster}/set/size_spec.rb +4 -13
- data/spec/lib/hamster/set/sorting_spec.rb +49 -0
- 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/lib/hamster/set/to_set_spec.rb +20 -0
- data/spec/lib/hamster/set/union_spec.rb +64 -0
- 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 +44 -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 +90 -0
- data/spec/lib/hamster/sorted_set/difference_spec.rb +23 -0
- data/spec/lib/hamster/sorted_set/disjoint_spec.rb +26 -0
- data/spec/lib/hamster/sorted_set/drop_spec.rb +56 -0
- data/spec/lib/hamster/sorted_set/drop_while_spec.rb +35 -0
- data/spec/lib/hamster/sorted_set/each_spec.rb +29 -0
- data/spec/lib/hamster/sorted_set/empty_spec.rb +35 -0
- data/spec/lib/hamster/sorted_set/eql_spec.rb +121 -0
- data/spec/lib/hamster/sorted_set/exclusion_spec.rb +23 -0
- data/spec/lib/hamster/sorted_set/fetch_spec.rb +65 -0
- data/spec/lib/hamster/sorted_set/find_index_spec.rb +41 -0
- data/spec/lib/hamster/sorted_set/first_spec.rb +19 -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/maximum_spec.rb +37 -0
- data/spec/lib/hamster/sorted_set/minimum_spec.rb +20 -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/select_spec.rb +62 -0
- data/spec/{hamster/vector → lib/hamster/sorted_set}/size_spec.rb +6 -15
- data/spec/lib/hamster/sorted_set/slice_spec.rb +257 -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 +55 -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/lib/hamster/vector/any_spec.rb +70 -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/lib/hamster/vector/copying_spec.rb +21 -0
- 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 +42 -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 +45 -0
- data/spec/lib/hamster/vector/each_with_index_spec.rb +40 -0
- data/spec/lib/hamster/vector/empty_spec.rb +42 -0
- data/spec/lib/hamster/vector/eql_spec.rb +77 -0
- 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/first_spec.rb +19 -0
- data/spec/lib/hamster/vector/flat_map_spec.rb +51 -0
- 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 +6 -20
- 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 +24 -34
- data/spec/lib/hamster/vector/last_spec.rb +46 -0
- data/spec/lib/hamster/vector/length_spec.rb +46 -0
- data/spec/lib/hamster/vector/ltlt_spec.rb +66 -0
- 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 +34 -0
- data/spec/lib/hamster/vector/minimum_spec.rb +34 -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/{hamster → lib/hamster}/vector/reduce_spec.rb +18 -49
- data/spec/lib/hamster/vector/reject_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/lib/hamster/vector/select_spec.rb +64 -0
- data/spec/lib/hamster/vector/set_spec.rb +175 -0
- 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 +5 -19
- data/spec/lib/hamster/vector/take_spec.rb +43 -0
- data/spec/lib/hamster/vector/take_while_spec.rb +35 -0
- data/spec/lib/hamster/vector/to_a_spec.rb +42 -0
- data/spec/lib/hamster/vector/to_ary_spec.rb +35 -0
- data/spec/lib/hamster/vector/to_list_spec.rb +32 -0
- 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/update_in_spec.rb +83 -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 +45 -13
- metadata +807 -458
- data/History.rdoc +0 -419
- data/LICENSE +0 -20
- data/README.rdoc +0 -236
- data/Rakefile +0 -5
- data/lib/hamster/core_ext/enumerator.rb +0 -30
- data/lib/hamster/experimental/mutable_stack.rb +0 -35
- data/lib/hamster/queue.rb +0 -93
- data/lib/hamster/sorter.rb +0 -32
- data/lib/hamster/stack.rb +0 -82
- data/lib/hamster/tuple.rb +0 -45
- data/spec/hamster/core_ext/array_spec.rb +0 -20
- data/spec/hamster/core_ext/coverage/assets/0.4.4/app.js +0 -66
- data/spec/hamster/core_ext/coverage/assets/0.4.4/fancybox/blank.gif +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/fancybox/fancy_close.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/fancybox/fancy_loading.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/fancybox/fancy_nav_left.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/fancybox/fancy_nav_right.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/fancybox/fancy_shadow_e.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/fancybox/fancy_shadow_n.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/fancybox/fancy_shadow_ne.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/fancybox/fancy_shadow_nw.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/fancybox/fancy_shadow_s.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/fancybox/fancy_shadow_se.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/fancybox/fancy_shadow_sw.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/fancybox/fancy_shadow_w.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/fancybox/fancy_title_left.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/fancybox/fancy_title_main.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/fancybox/fancy_title_over.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/fancybox/fancy_title_right.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/fancybox/fancybox-x.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/fancybox/fancybox-y.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/fancybox/fancybox.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/fancybox/jquery.fancybox-1.3.1.css +0 -363
- data/spec/hamster/core_ext/coverage/assets/0.4.4/fancybox/jquery.fancybox-1.3.1.pack.js +0 -44
- data/spec/hamster/core_ext/coverage/assets/0.4.4/favicon.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/jquery-1.4.2.min.js +0 -155
- data/spec/hamster/core_ext/coverage/assets/0.4.4/jquery.dataTables.min.js +0 -152
- data/spec/hamster/core_ext/coverage/assets/0.4.4/jquery.timeago.js +0 -141
- data/spec/hamster/core_ext/coverage/assets/0.4.4/jquery.url.js +0 -174
- data/spec/hamster/core_ext/coverage/assets/0.4.4/loading.gif +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/magnify.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/spec/hamster/core_ext/coverage/assets/0.4.4/smoothness/jquery-ui-1.8.4.custom.css +0 -295
- data/spec/hamster/core_ext/coverage/assets/0.4.4/stylesheet.css +0 -341
- data/spec/hamster/core_ext/coverage/covered_percent +0 -1
- data/spec/hamster/core_ext/coverage/index.html +0 -71
- data/spec/hamster/core_ext/coverage/resultset.yml +0 -10
- data/spec/hamster/core_ext/enumerable_spec.rb +0 -34
- data/spec/hamster/core_ext/enumerator_spec.rb +0 -25
- data/spec/hamster/core_ext/io_spec.rb +0 -29
- data/spec/hamster/experimental/mutable_set/add?_spec.rb +0 -47
- data/spec/hamster/experimental/mutable_set/add_spec.rb +0 -51
- data/spec/hamster/experimental/mutable_set/delete?_spec.rb +0 -47
- data/spec/hamster/experimental/mutable_set/delete_spec.rb +0 -47
- data/spec/hamster/experimental/mutable_stack/pop_spec.rb +0 -41
- data/spec/hamster/experimental/mutable_stack/push_spec.rb +0 -41
- data/spec/hamster/hash/all_spec.rb +0 -59
- data/spec/hamster/hash/any_spec.rb +0 -68
- data/spec/hamster/hash/clear_spec.rb +0 -36
- data/spec/hamster/hash/construction_spec.rb +0 -35
- data/spec/hamster/hash/copying_spec.rb +0 -23
- data/spec/hamster/hash/delete_spec.rb +0 -47
- data/spec/hamster/hash/each_spec.rb +0 -41
- data/spec/hamster/hash/empty_spec.rb +0 -27
- data/spec/hamster/hash/eql_spec.rb +0 -62
- data/spec/hamster/hash/except_spec.rb +0 -31
- data/spec/hamster/hash/fetch_spec.rb +0 -95
- data/spec/hamster/hash/filter_spec.rb +0 -63
- data/spec/hamster/hash/find_spec.rb +0 -58
- data/spec/hamster/hash/get_spec.rb +0 -68
- data/spec/hamster/hash/has_key_spec.rb +0 -35
- data/spec/hamster/hash/hash_spec.rb +0 -54
- data/spec/hamster/hash/inspect_spec.rb +0 -32
- data/spec/hamster/hash/keys_spec.rb +0 -21
- data/spec/hamster/hash/map_spec.rb +0 -64
- data/spec/hamster/hash/merge_spec.rb +0 -36
- data/spec/hamster/hash/none_spec.rb +0 -64
- data/spec/hamster/hash/put_spec.rb +0 -65
- data/spec/hamster/hash/reduce_spec.rb +0 -60
- data/spec/hamster/hash/remove_spec.rb +0 -63
- data/spec/hamster/hash/slice_spec.rb +0 -31
- data/spec/hamster/hash/uniq_spec.rb +0 -23
- data/spec/hamster/hash/values_spec.rb +0 -34
- data/spec/hamster/immutable/memoize_spec.rb +0 -64
- data/spec/hamster/immutable/new_spec.rb +0 -28
- data/spec/hamster/immutable/transform_spec.rb +0 -31
- data/spec/hamster/immutable/transform_unless_spec.rb +0 -55
- data/spec/hamster/list/all_spec.rb +0 -111
- data/spec/hamster/list/any_spec.rb +0 -79
- data/spec/hamster/list/append_spec.rb +0 -50
- data/spec/hamster/list/at_spec.rb +0 -49
- data/spec/hamster/list/break_spec.rb +0 -85
- data/spec/hamster/list/cadr_spec.rb +0 -50
- data/spec/hamster/list/chunk_spec.rb +0 -40
- data/spec/hamster/list/clear_spec.rb +0 -36
- data/spec/hamster/list/combinations_spec.rb +0 -51
- data/spec/hamster/list/compact_spec.rb +0 -46
- data/spec/hamster/list/cons_spec.rb +0 -41
- data/spec/hamster/list/construction_spec.rb +0 -140
- data/spec/hamster/list/copying_spec.rb +0 -32
- data/spec/hamster/list/count_spec.rb +0 -66
- data/spec/hamster/list/coverage/assets/0.4.4/app.js +0 -66
- data/spec/hamster/list/coverage/assets/0.4.4/fancybox/blank.gif +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/fancybox/fancy_close.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/fancybox/fancy_loading.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/fancybox/fancy_nav_left.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/fancybox/fancy_nav_right.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/fancybox/fancy_shadow_e.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/fancybox/fancy_shadow_n.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/fancybox/fancy_shadow_ne.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/fancybox/fancy_shadow_nw.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/fancybox/fancy_shadow_s.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/fancybox/fancy_shadow_se.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/fancybox/fancy_shadow_sw.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/fancybox/fancy_shadow_w.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/fancybox/fancy_title_left.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/fancybox/fancy_title_main.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/fancybox/fancy_title_over.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/fancybox/fancy_title_right.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/fancybox/fancybox-x.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/fancybox/fancybox-y.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/fancybox/fancybox.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/fancybox/jquery.fancybox-1.3.1.css +0 -363
- data/spec/hamster/list/coverage/assets/0.4.4/fancybox/jquery.fancybox-1.3.1.pack.js +0 -44
- data/spec/hamster/list/coverage/assets/0.4.4/favicon.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/jquery-1.4.2.min.js +0 -155
- data/spec/hamster/list/coverage/assets/0.4.4/jquery.dataTables.min.js +0 -152
- data/spec/hamster/list/coverage/assets/0.4.4/jquery.timeago.js +0 -141
- data/spec/hamster/list/coverage/assets/0.4.4/jquery.url.js +0 -174
- data/spec/hamster/list/coverage/assets/0.4.4/loading.gif +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/magnify.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/spec/hamster/list/coverage/assets/0.4.4/smoothness/jquery-ui-1.8.4.custom.css +0 -295
- data/spec/hamster/list/coverage/assets/0.4.4/stylesheet.css +0 -341
- data/spec/hamster/list/coverage/covered_percent +0 -1
- data/spec/hamster/list/coverage/index.html +0 -71
- data/spec/hamster/list/coverage/resultset.yml +0 -225
- data/spec/hamster/list/cycle_spec.rb +0 -45
- data/spec/hamster/list/drop_spec.rb +0 -42
- data/spec/hamster/list/drop_while_spec.rb +0 -59
- data/spec/hamster/list/each_slice_spec.rb +0 -80
- data/spec/hamster/list/each_spec.rb +0 -72
- data/spec/hamster/list/each_with_index_spec.rb +0 -42
- data/spec/hamster/list/elem_index_spec.rb +0 -58
- data/spec/hamster/list/elem_indices_spec.rb +0 -45
- data/spec/hamster/list/empty_spec.rb +0 -47
- data/spec/hamster/list/eql_spec.rb +0 -78
- data/spec/hamster/list/filter_spec.rb +0 -61
- data/spec/hamster/list/find_indices_spec.rb +0 -45
- data/spec/hamster/list/flatten_spec.rb +0 -42
- data/spec/hamster/list/grep_spec.rb +0 -70
- data/spec/hamster/list/group_by_spec.rb +0 -77
- data/spec/hamster/list/hash_spec.rb +0 -43
- data/spec/hamster/list/init_spec.rb +0 -40
- data/spec/hamster/list/inits_spec.rb +0 -42
- data/spec/hamster/list/inspect_spec.rb +0 -43
- data/spec/hamster/list/intersperse_spec.rb +0 -40
- data/spec/hamster/list/join_spec.rb +0 -81
- data/spec/hamster/list/last_spec.rb +0 -44
- data/spec/hamster/list/map_spec.rb +0 -69
- data/spec/hamster/list/maximum_spec.rb +0 -77
- data/spec/hamster/list/minimum_spec.rb +0 -77
- data/spec/hamster/list/partition_spec.rb +0 -75
- data/spec/hamster/list/product_spec.rb +0 -44
- data/spec/hamster/list/reduce_spec.rb +0 -99
- data/spec/hamster/list/remove_spec.rb +0 -67
- data/spec/hamster/list/reverse_spec.rb +0 -52
- data/spec/hamster/list/size_spec.rb +0 -47
- data/spec/hamster/list/slice_spec.rb +0 -50
- data/spec/hamster/list/sorting_spec.rb +0 -70
- data/spec/hamster/list/span_spec.rb +0 -86
- data/spec/hamster/list/split_at_spec.rb +0 -53
- data/spec/hamster/list/sum_spec.rb +0 -44
- data/spec/hamster/list/tail_spec.rb +0 -48
- data/spec/hamster/list/tails_spec.rb +0 -42
- data/spec/hamster/list/take_spec.rb +0 -42
- data/spec/hamster/list/take_while_spec.rb +0 -62
- data/spec/hamster/list/to_a_spec.rb +0 -54
- data/spec/hamster/list/to_ary_spec.rb +0 -56
- data/spec/hamster/list/to_list_spec.rb +0 -32
- data/spec/hamster/list/to_set_spec.rb +0 -33
- data/spec/hamster/list/union_spec.rb +0 -49
- data/spec/hamster/list/uniq_spec.rb +0 -45
- data/spec/hamster/list/zip_spec.rb +0 -39
- data/spec/hamster/queue/clear_spec.rb +0 -36
- data/spec/hamster/queue/construction_spec.rb +0 -43
- data/spec/hamster/queue/dequeue_spec.rb +0 -40
- data/spec/hamster/queue/empty_spec.rb +0 -47
- data/spec/hamster/queue/enqueue_spec.rb +0 -41
- data/spec/hamster/queue/head_spec.rb +0 -35
- data/spec/hamster/queue/inspect_spec.rb +0 -31
- data/spec/hamster/queue/size_spec.rb +0 -35
- data/spec/hamster/queue/to_a_spec.rb +0 -42
- data/spec/hamster/queue/to_ary_spec.rb +0 -44
- data/spec/hamster/queue/to_list_spec.rb +0 -44
- data/spec/hamster/set/add_spec.rb +0 -51
- data/spec/hamster/set/all_spec.rb +0 -67
- data/spec/hamster/set/any_spec.rb +0 -67
- data/spec/hamster/set/clear_spec.rb +0 -36
- data/spec/hamster/set/construction_spec.rb +0 -31
- data/spec/hamster/set/copying_spec.rb +0 -23
- data/spec/hamster/set/count_spec.rb +0 -54
- data/spec/hamster/set/coverage/assets/0.4.4/app.js +0 -66
- data/spec/hamster/set/coverage/assets/0.4.4/fancybox/blank.gif +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/fancybox/fancy_close.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/fancybox/fancy_loading.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/fancybox/fancy_nav_left.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/fancybox/fancy_nav_right.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/fancybox/fancy_shadow_e.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/fancybox/fancy_shadow_n.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/fancybox/fancy_shadow_ne.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/fancybox/fancy_shadow_nw.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/fancybox/fancy_shadow_s.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/fancybox/fancy_shadow_se.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/fancybox/fancy_shadow_sw.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/fancybox/fancy_shadow_w.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/fancybox/fancy_title_left.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/fancybox/fancy_title_main.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/fancybox/fancy_title_over.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/fancybox/fancy_title_right.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/fancybox/fancybox-x.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/fancybox/fancybox-y.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/fancybox/fancybox.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/fancybox/jquery.fancybox-1.3.1.css +0 -363
- data/spec/hamster/set/coverage/assets/0.4.4/fancybox/jquery.fancybox-1.3.1.pack.js +0 -44
- data/spec/hamster/set/coverage/assets/0.4.4/favicon.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/jquery-1.4.2.min.js +0 -155
- data/spec/hamster/set/coverage/assets/0.4.4/jquery.dataTables.min.js +0 -152
- data/spec/hamster/set/coverage/assets/0.4.4/jquery.timeago.js +0 -141
- data/spec/hamster/set/coverage/assets/0.4.4/jquery.url.js +0 -174
- data/spec/hamster/set/coverage/assets/0.4.4/loading.gif +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/magnify.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/spec/hamster/set/coverage/assets/0.4.4/smoothness/jquery-ui-1.8.4.custom.css +0 -295
- data/spec/hamster/set/coverage/assets/0.4.4/stylesheet.css +0 -341
- data/spec/hamster/set/coverage/covered_percent +0 -1
- data/spec/hamster/set/coverage/index.html +0 -71
- data/spec/hamster/set/coverage/resultset.yml +0 -13
- data/spec/hamster/set/delete_spec.rb +0 -47
- data/spec/hamster/set/difference_spec.rb +0 -37
- data/spec/hamster/set/each_spec.rb +0 -42
- data/spec/hamster/set/empty_spec.rb +0 -35
- data/spec/hamster/set/eql_spec.rb +0 -62
- data/spec/hamster/set/exclusion_spec.rb +0 -38
- data/spec/hamster/set/filter_spec.rb +0 -79
- data/spec/hamster/set/flatten_spec.rb +0 -49
- data/spec/hamster/set/grep_spec.rb +0 -62
- data/spec/hamster/set/group_by_spec.rb +0 -65
- data/spec/hamster/set/hash_spec.rb +0 -31
- data/spec/hamster/set/head_spec.rb +0 -39
- data/spec/hamster/set/include_spec.rb +0 -35
- data/spec/hamster/set/inspect_spec.rb +0 -32
- data/spec/hamster/set/intersection_spec.rb +0 -46
- data/spec/hamster/set/map_spec.rb +0 -64
- data/spec/hamster/set/maximum_spec.rb +0 -65
- data/spec/hamster/set/minimum_spec.rb +0 -65
- data/spec/hamster/set/partition_spec.rb +0 -71
- data/spec/hamster/set/product_spec.rb +0 -32
- data/spec/hamster/set/reduce_spec.rb +0 -87
- data/spec/hamster/set/remove_spec.rb +0 -63
- data/spec/hamster/set/sorting_spec.rb +0 -58
- data/spec/hamster/set/subset_spec.rb +0 -39
- data/spec/hamster/set/superset_spec.rb +0 -39
- data/spec/hamster/set/to_a_spec.rb +0 -42
- data/spec/hamster/set/to_list_spec.rb +0 -47
- data/spec/hamster/set/to_set_spec.rb +0 -32
- data/spec/hamster/set/union_spec.rb +0 -45
- data/spec/hamster/set/uniq_spec.rb +0 -23
- data/spec/hamster/sorter/coverage/assets/0.4.4/app.js +0 -66
- data/spec/hamster/sorter/coverage/assets/0.4.4/fancybox/blank.gif +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/fancybox/fancy_close.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/fancybox/fancy_loading.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/fancybox/fancy_nav_left.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/fancybox/fancy_nav_right.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/fancybox/fancy_shadow_e.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/fancybox/fancy_shadow_n.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/fancybox/fancy_shadow_ne.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/fancybox/fancy_shadow_nw.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/fancybox/fancy_shadow_s.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/fancybox/fancy_shadow_se.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/fancybox/fancy_shadow_sw.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/fancybox/fancy_shadow_w.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/fancybox/fancy_title_left.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/fancybox/fancy_title_main.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/fancybox/fancy_title_over.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/fancybox/fancy_title_right.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/fancybox/fancybox-x.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/fancybox/fancybox-y.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/fancybox/fancybox.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/fancybox/jquery.fancybox-1.3.1.css +0 -363
- data/spec/hamster/sorter/coverage/assets/0.4.4/fancybox/jquery.fancybox-1.3.1.pack.js +0 -44
- data/spec/hamster/sorter/coverage/assets/0.4.4/favicon.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/jquery-1.4.2.min.js +0 -155
- data/spec/hamster/sorter/coverage/assets/0.4.4/jquery.dataTables.min.js +0 -152
- data/spec/hamster/sorter/coverage/assets/0.4.4/jquery.timeago.js +0 -141
- data/spec/hamster/sorter/coverage/assets/0.4.4/jquery.url.js +0 -174
- data/spec/hamster/sorter/coverage/assets/0.4.4/loading.gif +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/magnify.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/spec/hamster/sorter/coverage/assets/0.4.4/smoothness/jquery-ui-1.8.4.custom.css +0 -295
- data/spec/hamster/sorter/coverage/assets/0.4.4/stylesheet.css +0 -341
- data/spec/hamster/sorter/coverage/covered_percent +0 -1
- data/spec/hamster/sorter/coverage/index.html +0 -71
- data/spec/hamster/sorter/coverage/resultset.yml +0 -22
- data/spec/hamster/sorter/immutable_spec.rb +0 -12
- data/spec/hamster/stack/clear_spec.rb +0 -36
- data/spec/hamster/stack/construction_spec.rb +0 -43
- data/spec/hamster/stack/copying_spec.rb +0 -31
- data/spec/hamster/stack/empty_spec.rb +0 -31
- data/spec/hamster/stack/eql_spec.rb +0 -60
- data/spec/hamster/stack/immutable_spec.rb +0 -12
- data/spec/hamster/stack/inspect_spec.rb +0 -31
- data/spec/hamster/stack/peek_spec.rb +0 -40
- data/spec/hamster/stack/pop_spec.rb +0 -41
- data/spec/hamster/stack/push_spec.rb +0 -41
- data/spec/hamster/stack/size_spec.rb +0 -35
- data/spec/hamster/stack/to_a_spec.rb +0 -42
- data/spec/hamster/stack/to_ary.rb +0 -44
- data/spec/hamster/stack/to_list_spec.rb +0 -33
- data/spec/hamster/trie/remove_spec.rb +0 -117
- data/spec/hamster/tuple/copying_spec.rb +0 -24
- data/spec/hamster/tuple/eql_spec.rb +0 -61
- data/spec/hamster/tuple/first_spec.rb +0 -19
- data/spec/hamster/tuple/immutable_spec.rb +0 -12
- data/spec/hamster/tuple/inspect_spec.rb +0 -19
- data/spec/hamster/tuple/last_spec.rb +0 -19
- data/spec/hamster/tuple/to_a_spec.rb +0 -38
- data/spec/hamster/tuple/to_ary_spec.rb +0 -44
- data/spec/hamster/undefined/erase_spec.rb +0 -47
- data/spec/hamster/vector/add_spec.rb +0 -41
- data/spec/hamster/vector/any_spec.rb +0 -67
- data/spec/hamster/vector/clear_spec.rb +0 -36
- data/spec/hamster/vector/copying_spec.rb +0 -32
- data/spec/hamster/vector/each_spec.rb +0 -46
- data/spec/hamster/vector/each_with_index_spec.rb +0 -42
- data/spec/hamster/vector/empty_spec.rb +0 -35
- data/spec/hamster/vector/eql_spec.rb +0 -65
- data/spec/hamster/vector/filter_spec.rb +0 -63
- data/spec/hamster/vector/first_spec.rb +0 -35
- data/spec/hamster/vector/get_spec.rb +0 -81
- data/spec/hamster/vector/inspect_spec.rb +0 -31
- data/spec/hamster/vector/last_spec.rb +0 -32
- data/spec/hamster/vector/map_spec.rb +0 -64
- data/spec/hamster/vector/set_spec.rb +0 -153
- data/spec/hamster/vector/to_a_spec.rb +0 -42
- data/spec/hamster/vector/to_ary_spec.rb +0 -44
- data/tasks/bundler.rb +0 -2
- data/tasks/publish.rb +0 -12
- data/tasks/spec.rb +0 -13
data/lib/hamster/immutable.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
module Hamster
|
2
|
-
|
2
|
+
# @private
|
3
3
|
module Immutable
|
4
|
-
|
5
4
|
def self.included(klass)
|
6
5
|
klass.extend(ClassMethods)
|
7
6
|
klass.instance_eval do
|
@@ -9,8 +8,8 @@ module Hamster
|
|
9
8
|
end
|
10
9
|
end
|
11
10
|
|
11
|
+
# @private
|
12
12
|
module ClassMethods
|
13
|
-
|
14
13
|
def new(*args)
|
15
14
|
super.immutable!
|
16
15
|
end
|
@@ -31,20 +30,18 @@ module Hamster
|
|
31
30
|
METHOD
|
32
31
|
end
|
33
32
|
end
|
34
|
-
|
35
33
|
end
|
36
34
|
|
35
|
+
# @private
|
37
36
|
module MemoizeMethods
|
38
|
-
|
39
37
|
def immutable!
|
40
38
|
@__hamster_immutable_memory__ = Object.new
|
41
39
|
freeze
|
42
40
|
end
|
43
|
-
|
44
41
|
end
|
45
42
|
|
43
|
+
# @private
|
46
44
|
module InstanceMethods
|
47
|
-
|
48
45
|
def immutable!
|
49
46
|
freeze
|
50
47
|
end
|
@@ -73,9 +70,6 @@ module Hamster
|
|
73
70
|
def transform(&block)
|
74
71
|
__hamster_immutable_dup__.tap { |copy| copy.instance_eval(&block) }.immutable!
|
75
72
|
end
|
76
|
-
|
77
73
|
end
|
78
|
-
|
79
74
|
end
|
80
|
-
|
81
75
|
end
|
data/lib/hamster/list.rb
CHANGED
@@ -1,135 +1,337 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "thread"
|
2
|
+
require "atomic"
|
3
|
+
require "set"
|
3
4
|
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require 'hamster/hash'
|
10
|
-
require 'hamster/set'
|
5
|
+
require "hamster/core_ext/enumerable"
|
6
|
+
require "hamster/undefined"
|
7
|
+
require "hamster/enumerable"
|
8
|
+
require "hamster/hash"
|
9
|
+
require "hamster/set"
|
11
10
|
|
12
11
|
module Hamster
|
13
|
-
|
14
12
|
class << self
|
15
13
|
|
16
|
-
|
17
|
-
|
14
|
+
# Create a list containing the given items.
|
15
|
+
#
|
16
|
+
# @example
|
17
|
+
# list = Hamster.list(:a, :b, :c)
|
18
|
+
# # => Hamster::List[:a, :b, :c]
|
19
|
+
#
|
20
|
+
# @return [List]
|
18
21
|
def list(*items)
|
19
22
|
items.to_list
|
20
23
|
end
|
21
24
|
|
25
|
+
# Create a lazy, infinite list.
|
26
|
+
#
|
27
|
+
# The given block is called as necessary to return successive elements of the list.
|
28
|
+
#
|
29
|
+
# @example
|
30
|
+
# Hamster.stream { :hello }.take(3)
|
31
|
+
# # => Hamster::List[:hello, :hello, :hello]
|
32
|
+
#
|
33
|
+
# @return [List]
|
22
34
|
def stream(&block)
|
23
35
|
return EmptyList unless block_given?
|
24
|
-
|
25
|
-
end
|
26
|
-
|
36
|
+
LazyList.new { Cons.new(yield, stream(&block)) }
|
37
|
+
end
|
38
|
+
|
39
|
+
# Construct a list of consecutive integers.
|
40
|
+
#
|
41
|
+
# @example
|
42
|
+
# Hamster.interval(5,9)
|
43
|
+
# # => Hamster::List[5, 6, 7, 8, 9]
|
44
|
+
#
|
45
|
+
# @param from [Integer] Start value, inclusive
|
46
|
+
# @param to [Integer] End value, inclusive
|
47
|
+
# @return [List]
|
27
48
|
def interval(from, to)
|
28
49
|
return EmptyList if from > to
|
29
50
|
interval_exclusive(from, to.next)
|
30
51
|
end
|
31
|
-
def_delegator :self, :interval, :range
|
32
52
|
|
53
|
+
# Create an infinite list repeating the same item indefinitely
|
54
|
+
#
|
55
|
+
# @example
|
56
|
+
# Hamster.repeat(:chunky).take(4)
|
57
|
+
# => Hamster::List[:chunky, :chunky, :chunky, :chunky]
|
58
|
+
#
|
59
|
+
# @return [List]
|
33
60
|
def repeat(item)
|
34
|
-
|
61
|
+
LazyList.new { Cons.new(item, repeat(item)) }
|
35
62
|
end
|
36
63
|
|
64
|
+
# Create a list that contains a given item a fixed number of times
|
65
|
+
#
|
66
|
+
# @example
|
67
|
+
# Hamster.replicate(3).(:hamster)
|
68
|
+
# #=> Hamster::List[:hamster, :hamster, :hamster]
|
69
|
+
#
|
70
|
+
# @return [List]
|
37
71
|
def replicate(number, item)
|
38
72
|
repeat(item).take(number)
|
39
73
|
end
|
40
74
|
|
75
|
+
# Create an infinite list where each item is derived from the previous one,
|
76
|
+
# using the provided block
|
77
|
+
#
|
78
|
+
# @example
|
79
|
+
# Hamster.iterate(0) { |i| i.next }.take(5)
|
80
|
+
# # => Hamster::List[0, 1, 2, 3, 4]
|
81
|
+
#
|
82
|
+
# @param item [Object] Starting value
|
83
|
+
# @yieldparam [Object] The previous value
|
84
|
+
# @yieldreturn [Object] The next value
|
85
|
+
# @return [List]
|
41
86
|
def iterate(item, &block)
|
42
|
-
|
87
|
+
LazyList.new { Cons.new(item, iterate(yield(item), &block)) }
|
88
|
+
end
|
89
|
+
|
90
|
+
# Turn an Enumerator into a `Hamster::List`. The result is a lazy collection
|
91
|
+
# where the values are memoized as they are generated.
|
92
|
+
#
|
93
|
+
# If your code uses multiple threads, you need to make sure that the returned
|
94
|
+
# lazy collection is realized on a single thread only. Otherwise, a `FiberError`
|
95
|
+
# will be raised. After the collection is realized, it can be used from other
|
96
|
+
# threads as well.
|
97
|
+
#
|
98
|
+
# @example
|
99
|
+
# def rg; loop { yield rand(100) }; end
|
100
|
+
# Hamster.enumerate(to_enum(:rg)).take(10)
|
101
|
+
#
|
102
|
+
# @param enum [Enumerator] The object to iterate over
|
103
|
+
# @return [List]
|
104
|
+
def enumerate(enum)
|
105
|
+
LazyList.new do
|
106
|
+
begin
|
107
|
+
Cons.new(enum.next, enumerate(enum))
|
108
|
+
rescue StopIteration
|
109
|
+
EmptyList
|
110
|
+
end
|
111
|
+
end
|
43
112
|
end
|
44
113
|
|
45
114
|
private
|
46
115
|
|
47
116
|
def interval_exclusive(from, to)
|
48
117
|
return EmptyList if from == to
|
49
|
-
|
118
|
+
LazyList.new { Cons.new(from, interval_exclusive(from.next, to)) }
|
50
119
|
end
|
51
|
-
|
52
120
|
end
|
53
121
|
|
122
|
+
# A `List` can be constructed with {Hamster.list Hamster.list} or {List.[] List[]}.
|
123
|
+
# It consists of a *head* (the first element) and a *tail* (which itself is also
|
124
|
+
# a `List`, containing all the remaining elements).
|
125
|
+
#
|
126
|
+
# This is a singly linked list. Prepending to the list with {List#cons} runs
|
127
|
+
# in constant time. Traversing the list from front to back is efficient,
|
128
|
+
# however, indexed access runs in linear time because the list needs to be
|
129
|
+
# traversed to find the element.
|
130
|
+
#
|
54
131
|
module List
|
55
|
-
|
56
|
-
extend Forwardable
|
57
|
-
|
58
132
|
include Enumerable
|
59
133
|
|
134
|
+
# @private
|
60
135
|
CADR = /^c([ad]+)r$/
|
61
136
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
137
|
+
# Create a new `List` populated with the given items.
|
138
|
+
#
|
139
|
+
# @example
|
140
|
+
# list = Hamster::List[:a, :b, :c]
|
141
|
+
# # => Hamster::List[:a, :b, :c]
|
142
|
+
#
|
143
|
+
# @return [List]
|
144
|
+
def self.[](*items)
|
145
|
+
items.to_list
|
68
146
|
end
|
69
|
-
def_delegator :self, :size, :length
|
70
147
|
|
148
|
+
# Return the number of items in this `List`.
|
149
|
+
# @return [Integer]
|
150
|
+
def size
|
151
|
+
result, list = 0, self
|
152
|
+
until list.empty?
|
153
|
+
if list.cached_size?
|
154
|
+
return result + list.size
|
155
|
+
else
|
156
|
+
result += 1
|
157
|
+
end
|
158
|
+
list = list.tail
|
159
|
+
end
|
160
|
+
result
|
161
|
+
end
|
162
|
+
alias :length :size
|
163
|
+
|
164
|
+
# Create a new `List` with `item` added at the front.
|
165
|
+
#
|
166
|
+
# @example
|
167
|
+
# Hamster.list(:b, :c).cons(:a)
|
168
|
+
# # => Hamster::List[:a, :b, :c]
|
169
|
+
#
|
170
|
+
# @param item [Object] The item to add
|
171
|
+
# @return [List]
|
71
172
|
def cons(item)
|
72
|
-
|
73
|
-
end
|
74
|
-
|
75
|
-
|
173
|
+
Cons.new(item, self)
|
174
|
+
end
|
175
|
+
alias :add :cons
|
176
|
+
|
177
|
+
# Create a new `List` with `item` added at the end. This is much less efficient
|
178
|
+
# than adding items at the front.
|
179
|
+
#
|
180
|
+
# @example
|
181
|
+
# Hamster.list(:a, :b) << :c
|
182
|
+
# # => Hamster::List[:a, :b, :c]
|
183
|
+
#
|
184
|
+
# @param item [Object] The item to add
|
185
|
+
# @return [List]
|
186
|
+
def <<(item)
|
187
|
+
append(Hamster.list(item))
|
188
|
+
end
|
189
|
+
|
190
|
+
# Call the given block once for each item in the list, passing each
|
191
|
+
# item from first to last successively to the block.
|
192
|
+
#
|
193
|
+
# @return [self]
|
76
194
|
def each
|
77
|
-
return
|
195
|
+
return to_enum unless block_given?
|
78
196
|
list = self
|
79
|
-
|
197
|
+
until list.empty?
|
80
198
|
yield(list.head)
|
81
199
|
list = list.tail
|
82
200
|
end
|
83
201
|
end
|
84
202
|
|
203
|
+
# Return a lazy list in which each element is derived from the corresponding
|
204
|
+
# element in this `List`, transformed through the given block.
|
205
|
+
#
|
206
|
+
# @example
|
207
|
+
# Hamster.list(3, 2, 1).map { |e| e * e } # => Hamster::List[9, 4, 1]
|
208
|
+
#
|
209
|
+
# @return [List]
|
85
210
|
def map(&block)
|
86
|
-
return
|
87
|
-
|
211
|
+
return enum_for(:map) unless block_given?
|
212
|
+
LazyList.new do
|
88
213
|
next self if empty?
|
89
|
-
|
214
|
+
Cons.new(yield(head), tail.map(&block))
|
90
215
|
end
|
91
216
|
end
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
217
|
+
alias :collect :map
|
218
|
+
|
219
|
+
# Return a lazy list which is realized by transforming each item into a `List`,
|
220
|
+
# and flattening the resulting lists.
|
221
|
+
#
|
222
|
+
# @example
|
223
|
+
# Hamster.list(1, 2, 3).flat_map { |x| Hamster.list(x, 100) }
|
224
|
+
# # => Hamster::List[1, 100, 2, 100, 3, 100]
|
225
|
+
#
|
226
|
+
# @return [List]
|
227
|
+
def flat_map(&block)
|
228
|
+
return enum_for(:flat_map) unless block_given?
|
229
|
+
LazyList.new do
|
97
230
|
next self if empty?
|
98
|
-
|
99
|
-
tail.
|
231
|
+
head_list = Hamster.list(*yield(head))
|
232
|
+
next tail.flat_map(&block) if head_list.empty?
|
233
|
+
Cons.new(head_list.first, head_list.drop(1).append(tail.flat_map(&block)))
|
100
234
|
end
|
101
235
|
end
|
102
236
|
|
237
|
+
# Return a lazy list which contains all the items for which the given block
|
238
|
+
# returns true.
|
239
|
+
#
|
240
|
+
# @example
|
241
|
+
# Hamster.list("Bird", "Cow", "Elephant").select { |e| e.size >= 4 }
|
242
|
+
# # => Hamster::List["Bird", "Elephant"]
|
243
|
+
#
|
244
|
+
# @return [List]
|
245
|
+
def select(&block)
|
246
|
+
return enum_for(:select) unless block_given?
|
247
|
+
LazyList.new do
|
248
|
+
list = self
|
249
|
+
while true
|
250
|
+
break list if list.empty?
|
251
|
+
break Cons.new(list.head, list.tail.select(&block)) if yield(list.head)
|
252
|
+
list = list.tail
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
alias :find_all :select
|
257
|
+
alias :keep_if :select
|
258
|
+
|
259
|
+
# Return a lazy list which contains all elements up to, but not including, the
|
260
|
+
# first element for which the block returns `nil` or `false`.
|
261
|
+
#
|
262
|
+
# @example
|
263
|
+
# Hamster.list(1, 3, 5, 7, 6, 4, 2).take_while { |e| e < 5 }
|
264
|
+
# # => Hamster::List[1, 3]
|
265
|
+
#
|
266
|
+
# @return [List, Enumerator]
|
103
267
|
def take_while(&block)
|
104
|
-
return
|
105
|
-
|
268
|
+
return enum_for(:take_while) unless block_given?
|
269
|
+
LazyList.new do
|
106
270
|
next self if empty?
|
107
|
-
next
|
271
|
+
next Cons.new(head, tail.take_while(&block)) if yield(head)
|
108
272
|
EmptyList
|
109
273
|
end
|
110
274
|
end
|
111
275
|
|
276
|
+
# Return a lazy list which contains all elements starting from the
|
277
|
+
# first element for which the block returns `nil` or `false`.
|
278
|
+
#
|
279
|
+
# @example
|
280
|
+
# Hamster.list(1, 3, 5, 7, 6, 4, 2).drop_while { |e| e < 5 }
|
281
|
+
# # => Hamster::List[5, 7, 6, 4, 2]
|
282
|
+
#
|
283
|
+
# @return [List, Enumerator]
|
112
284
|
def drop_while(&block)
|
113
|
-
return
|
114
|
-
|
285
|
+
return enum_for(:drop_while) unless block_given?
|
286
|
+
LazyList.new do
|
115
287
|
list = self
|
116
|
-
while !list.empty? && yield(list.head)
|
117
|
-
list = list.tail
|
118
|
-
end
|
288
|
+
list = list.tail while !list.empty? && yield(list.head)
|
119
289
|
list
|
120
290
|
end
|
121
291
|
end
|
122
292
|
|
293
|
+
# Return a lazy list containing the first `number` items from this `List`.
|
294
|
+
#
|
295
|
+
# @example
|
296
|
+
# Hamster.list(1, 3, 5, 7, 6, 4, 2).take(3)
|
297
|
+
# # => Hamster::List[1, 3, 5]
|
298
|
+
#
|
299
|
+
# @param number [Integer] The number of items to retain
|
300
|
+
# @return [List]
|
123
301
|
def take(number)
|
124
|
-
|
302
|
+
LazyList.new do
|
303
|
+
next self if empty?
|
304
|
+
next Cons.new(head, tail.take(number - 1)) if number > 0
|
305
|
+
EmptyList
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
# Return a lazy list containing all but the last item from this `List`.
|
310
|
+
#
|
311
|
+
# @example
|
312
|
+
# Hamster.list("A", "B", "C").pop # => Hamster::List["A", "B"]
|
313
|
+
#
|
314
|
+
# @return [List]
|
315
|
+
def pop
|
316
|
+
LazyList.new do
|
125
317
|
next self if empty?
|
126
|
-
|
318
|
+
new_size = size - 1
|
319
|
+
next Cons.new(head, tail.take(new_size - 1)) if new_size >= 1
|
127
320
|
EmptyList
|
128
321
|
end
|
129
322
|
end
|
130
323
|
|
324
|
+
# Return a lazy list containing all items after the first `number` items from
|
325
|
+
# this `List`.
|
326
|
+
#
|
327
|
+
# @example
|
328
|
+
# Hamster.list(1, 3, 5, 7, 6, 4, 2).drop(3)
|
329
|
+
# # => Hamster::List[7, 6, 4, 2]
|
330
|
+
#
|
331
|
+
# @param number [Integer] The number of items to skip over
|
332
|
+
# @return [List]
|
131
333
|
def drop(number)
|
132
|
-
|
334
|
+
LazyList.new do
|
133
335
|
list = self
|
134
336
|
while !list.empty? && number > 0
|
135
337
|
number -= 1
|
@@ -139,226 +341,688 @@ module Hamster
|
|
139
341
|
end
|
140
342
|
end
|
141
343
|
|
344
|
+
# Return a lazy list with all items from this `List`, followed by all items from
|
345
|
+
# `other`.
|
346
|
+
#
|
347
|
+
# @example
|
348
|
+
# Hamster.list(1, 2, 3).append(Hamster.list(4, 5))
|
349
|
+
# # => Hamster::List[1, 2, 3, 4, 5]
|
350
|
+
#
|
351
|
+
# @param other [List] The list to add onto the end of this one
|
352
|
+
# @return [List]
|
142
353
|
def append(other)
|
143
|
-
|
354
|
+
LazyList.new do
|
144
355
|
next other if empty?
|
145
|
-
|
356
|
+
Cons.new(head, tail.append(other))
|
146
357
|
end
|
147
358
|
end
|
148
|
-
|
149
|
-
|
150
|
-
def_delegator :self, :append, :+
|
359
|
+
alias :concat :append
|
360
|
+
alias :+ :append
|
151
361
|
|
362
|
+
# Return a `List` with the same items, but in reverse order.
|
363
|
+
#
|
364
|
+
# @example
|
365
|
+
# Hamster.list("A", "B", "C").reverse # => Hamster::List["C", "B", "A"]
|
366
|
+
#
|
367
|
+
# @return [List]
|
152
368
|
def reverse
|
153
|
-
|
369
|
+
LazyList.new { reduce(EmptyList) { |list, item| list.cons(item) }}
|
370
|
+
end
|
371
|
+
|
372
|
+
# Gather the corresponding elements from this `List` and `others` (that is,
|
373
|
+
# the elements with the same indices) into new 2-element lists. Return a
|
374
|
+
# lazy list of these 2-element lists.
|
375
|
+
#
|
376
|
+
#
|
377
|
+
# @example
|
378
|
+
# Hamster.list("A", "B", "C").zip(Hamster.list(1, 2, 3))
|
379
|
+
# # => Hamster::List[Hamster::List["A", 1], Hamster::List["B", 2], Hamster::List["C", 3]]
|
380
|
+
#
|
381
|
+
# @param others [List] The list to zip together with this one
|
382
|
+
# @return [List]
|
383
|
+
def zip(others)
|
384
|
+
LazyList.new do
|
385
|
+
next self if empty? && others.empty?
|
386
|
+
Cons.new(Cons.new(head, Cons.new(others.head)), tail.zip(others.tail))
|
387
|
+
end
|
154
388
|
end
|
155
389
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
390
|
+
# Gather the first element of each nested list into a new `List`, then the second
|
391
|
+
# element of each nested list, then the third, and so on. In other words, if each
|
392
|
+
# nested list is a "row", return a lazy list of "columns" instead.
|
393
|
+
#
|
394
|
+
# Although the returned list is lazy, each returned nested list (each "column")
|
395
|
+
# is strict. So while each nested list in the input can be infinite, the parent
|
396
|
+
# `List` must not be, or trying to realize the first element in the output will
|
397
|
+
# cause an infinite loop.
|
398
|
+
#
|
399
|
+
# @example
|
400
|
+
# # First let's create some infinite lists
|
401
|
+
# list1 = Hamster.iterate(1, &:next)
|
402
|
+
# list2 = Hamster.iterate(2) { |n| n * 2 }
|
403
|
+
# list3 = Hamster.iterate(3) { |n| n * 3 }
|
404
|
+
#
|
405
|
+
# # Now we transpose our 3 infinite "rows" into an infinite series of 3-element "columns"
|
406
|
+
# Hamster.list(list1, list2, list3).transpose.take(4)
|
407
|
+
# # => Hamster::List[
|
408
|
+
# # Hamster::List[1, 2, 3],
|
409
|
+
# # Hamster::List[2, 4, 9],
|
410
|
+
# # Hamster::List[3, 8, 27],
|
411
|
+
# # Hamster::List[4, 16, 81]]
|
412
|
+
#
|
413
|
+
# @return [List]
|
414
|
+
def transpose
|
415
|
+
return EmptyList if empty?
|
416
|
+
LazyList.new do
|
417
|
+
next EmptyList if any? { |list| list.empty? }
|
418
|
+
heads, tails = EmptyList, EmptyList
|
419
|
+
reverse_each { |list| heads, tails = heads.cons(list.head), tails.cons(list.tail) }
|
420
|
+
Cons.new(heads, tails.transpose)
|
160
421
|
end
|
161
422
|
end
|
162
423
|
|
424
|
+
# Concatenate an infinite series of copies of this `List` together (into a
|
425
|
+
# new lazy list). Or, if empty, just return an empty list.
|
426
|
+
#
|
427
|
+
# @example
|
428
|
+
# Hamster.list(1, 2, 3).cycle.take(10)
|
429
|
+
# # => Hamster::List[1, 2, 3, 1, 2, 3, 1, 2, 3, 1]
|
430
|
+
#
|
431
|
+
# @return [List]
|
163
432
|
def cycle
|
164
|
-
|
433
|
+
LazyList.new do
|
165
434
|
next self if empty?
|
166
|
-
|
435
|
+
Cons.new(head, tail.append(cycle))
|
167
436
|
end
|
168
437
|
end
|
169
438
|
|
439
|
+
# Return a new `List` with the same elements, but rotated so that the one at
|
440
|
+
# index `count` is the first element of the new list. If `count` is positive,
|
441
|
+
# the elements will be shifted left, and those shifted past the lowest position
|
442
|
+
# will be moved to the end. If `count` is negative, the elements will be shifted
|
443
|
+
# right, and those shifted past the last position will be moved to the beginning.
|
444
|
+
#
|
445
|
+
# @example
|
446
|
+
# l = Hamster.list("A", "B", "C", "D", "E", "F")
|
447
|
+
# l.rotate(2) # => Hamster::List["C", "D", "E", "F", "A", "B"]
|
448
|
+
# l.rotate(-1) # => Hamster::List["F", "A", "B", "C", "D", "E"]
|
449
|
+
#
|
450
|
+
# @param count [Integer] The number of positions to shift items by
|
451
|
+
# @return [Vector]
|
452
|
+
def rotate(count = 1)
|
453
|
+
raise TypeError, "expected Integer" if not count.is_a?(Integer)
|
454
|
+
return self if empty? || (count % size) == 0
|
455
|
+
count = (count >= 0) ? count % size : (size - (~count % size) - 1)
|
456
|
+
drop(count).append(take(count))
|
457
|
+
end
|
458
|
+
|
459
|
+
# Return 2 `List`s, one of the first `number` items, and another of all the
|
460
|
+
# remaining items.
|
461
|
+
#
|
462
|
+
# @example
|
463
|
+
# Hamster.list("a", "b", "c", "d").split(2)
|
464
|
+
# # => [Hamster::List["a", "b"], Hamster::List["c", "d"]]
|
465
|
+
#
|
466
|
+
# @param number [Integer] The index at which to split this list
|
467
|
+
# @return [Array]
|
170
468
|
def split_at(number)
|
171
|
-
|
469
|
+
[take(number), drop(number)].freeze
|
172
470
|
end
|
173
471
|
|
472
|
+
# Return 2 `List`s, one up to (but not including) the first item for which the
|
473
|
+
# block returns `nil` or `false`, and another of all the remaining items.
|
474
|
+
#
|
475
|
+
# @example
|
476
|
+
# Hamster.list(4, 3, 5, 2, 1).span { |x| x > 2 }
|
477
|
+
# # => [Hamster::List[4, 3, 5], Hamster::List[2, 1]]
|
478
|
+
#
|
479
|
+
# @return [Array]
|
174
480
|
def span(&block)
|
175
|
-
return
|
176
|
-
|
177
|
-
|
178
|
-
|
481
|
+
return [self, EmptyList].freeze unless block_given?
|
482
|
+
splitter = Splitter.new(self, block)
|
483
|
+
mutex = Mutex.new
|
484
|
+
[Splitter::Left.new(splitter, splitter.left, mutex),
|
485
|
+
Splitter::Right.new(splitter, mutex)].freeze
|
486
|
+
end
|
487
|
+
|
488
|
+
# Return 2 `List`s, one up to (but not including) the first item for which the
|
489
|
+
# block returns true, and another of all the remaining items.
|
490
|
+
#
|
491
|
+
# @example
|
492
|
+
# Hamster.list(1, 3, 4, 2, 5).break { |x| x > 3 }
|
493
|
+
# # => [Hamster::List[1, 3], Hamster::List[4, 2, 5]]
|
494
|
+
#
|
495
|
+
# @return [Array]
|
179
496
|
def break(&block)
|
180
497
|
return span unless block_given?
|
181
498
|
span { |item| !yield(item) }
|
182
499
|
end
|
183
500
|
|
501
|
+
# Return an empty `List`.
|
502
|
+
# @return [List]
|
184
503
|
def clear
|
185
504
|
EmptyList
|
186
505
|
end
|
187
506
|
|
507
|
+
# Return a `List` with the same items, but sorted either in their natural order,
|
508
|
+
# or using an optional comparator block. The block must take 2 parameters, and
|
509
|
+
# return 0, 1, or -1 if the first one is equal, greater than, or less than the
|
510
|
+
# second (respectively).
|
511
|
+
#
|
512
|
+
# @return [List]
|
188
513
|
def sort(&comparator)
|
189
|
-
|
514
|
+
LazyList.new { super(&comparator).to_list }
|
190
515
|
end
|
191
516
|
|
517
|
+
# Return a new `List` with the same items, but sorted. The sort order will be
|
518
|
+
# determined by mapping the items through the given block to obtain sort keys,
|
519
|
+
# and then sorting the keys according to their natural sort order.
|
520
|
+
#
|
521
|
+
# @return [List]
|
192
522
|
def sort_by(&transformer)
|
193
523
|
return sort unless block_given?
|
194
|
-
|
195
|
-
end
|
196
|
-
|
197
|
-
def join(sep = "")
|
198
|
-
return "" if empty?
|
199
|
-
sep = sep.to_s
|
200
|
-
tail.reduce(head.to_s.dup) { |result, item| result << sep << item.to_s }
|
524
|
+
LazyList.new { super(&transformer).to_list }
|
201
525
|
end
|
202
526
|
|
527
|
+
# Return a new `List` with `sep` inserted between each of the existing elements.
|
528
|
+
#
|
529
|
+
# @example
|
530
|
+
# Hamster.list("one", "two", "three").intersperse(" ")
|
531
|
+
# # => Hamster::List["one", " ", "two", " ", "three"]
|
532
|
+
#
|
533
|
+
# @return [List]
|
203
534
|
def intersperse(sep)
|
204
|
-
|
535
|
+
LazyList.new do
|
205
536
|
next self if tail.empty?
|
206
|
-
|
537
|
+
Cons.new(head, Cons.new(sep, tail.intersperse(sep)))
|
207
538
|
end
|
208
539
|
end
|
209
540
|
|
210
|
-
|
211
|
-
|
541
|
+
# Return a lazy list with the same items, but all duplicates removed.
|
542
|
+
# Use `#hash` and `#eql?` to determine which items are duplicates.
|
543
|
+
#
|
544
|
+
# @example
|
545
|
+
# Hamster.list(:a, :b, :a, :c, :b).uniq # => Hamster::List[:a, :b, :c]
|
546
|
+
#
|
547
|
+
# @return [List]
|
548
|
+
def uniq(items = ::Set.new)
|
549
|
+
LazyList.new do
|
212
550
|
next self if empty?
|
213
551
|
next tail.uniq(items) if items.include?(head)
|
214
|
-
|
552
|
+
Cons.new(head, tail.uniq(items.add(head)))
|
215
553
|
end
|
216
554
|
end
|
217
|
-
def_delegator :self, :uniq, :nub
|
218
|
-
def_delegator :self, :uniq, :remove_duplicates
|
219
555
|
|
220
|
-
|
221
|
-
|
556
|
+
# Return a `List` with all the elements from both this list and `other`,
|
557
|
+
# with all duplicates removed.
|
558
|
+
#
|
559
|
+
# @example
|
560
|
+
# Hamster.list(1, 2).union(Hamster.list(2, 3)) # => Hamster::List[1, 2, 3]
|
561
|
+
#
|
562
|
+
# @param other [List] The list to merge with
|
563
|
+
# @return [List]
|
564
|
+
def union(other, items = ::Set.new)
|
565
|
+
LazyList.new do
|
566
|
+
next other.uniq(items) if empty?
|
567
|
+
next tail.union(other, items) if items.include?(head)
|
568
|
+
Cons.new(head, tail.union(other, items.add(head)))
|
569
|
+
end
|
222
570
|
end
|
223
|
-
|
571
|
+
alias :| :union
|
224
572
|
|
573
|
+
# Return a lazy list with all elements except the last one.
|
574
|
+
#
|
575
|
+
# @example
|
576
|
+
# Hamster.list("a", "b", "c").init # => Hamster::List["a", "b"]
|
577
|
+
#
|
578
|
+
# @return [List]
|
225
579
|
def init
|
226
580
|
return EmptyList if tail.empty?
|
227
|
-
|
581
|
+
LazyList.new { Cons.new(head, tail.init) }
|
228
582
|
end
|
229
583
|
|
584
|
+
# Return the last item in this list.
|
585
|
+
# @return [Object]
|
230
586
|
def last
|
231
587
|
list = self
|
232
|
-
|
233
|
-
list = list.tail
|
234
|
-
end
|
588
|
+
list = list.tail until list.tail.empty?
|
235
589
|
list.head
|
236
590
|
end
|
237
591
|
|
592
|
+
# Return a lazy list of all suffixes of this list.
|
593
|
+
#
|
594
|
+
# @example
|
595
|
+
# Hamster.list(1,2,3).tails
|
596
|
+
# # => Hamster::List[
|
597
|
+
# # Hamster::List[1, 2, 3],
|
598
|
+
# # Hamster::List[2, 3],
|
599
|
+
# # Hamster::List[3]]
|
600
|
+
#
|
601
|
+
# @return [List]
|
238
602
|
def tails
|
239
|
-
|
240
|
-
next
|
241
|
-
|
603
|
+
LazyList.new do
|
604
|
+
next self if empty?
|
605
|
+
Cons.new(self, tail.tails)
|
242
606
|
end
|
243
607
|
end
|
244
608
|
|
609
|
+
# Return a lazy list of all prefixes of this list.
|
610
|
+
#
|
611
|
+
# @example
|
612
|
+
# Hamster.list(1,2,3).inits
|
613
|
+
# # => Hamster::List[
|
614
|
+
# # Hamster::List[1],
|
615
|
+
# # Hamster::List[1, 2],
|
616
|
+
# # Hamster::List[1, 2, 3]]
|
617
|
+
#
|
618
|
+
# @return [List]
|
245
619
|
def inits
|
246
|
-
|
247
|
-
next
|
248
|
-
|
620
|
+
LazyList.new do
|
621
|
+
next self if empty?
|
622
|
+
Cons.new(Hamster.list(head), tail.inits.map { |list| list.cons(head) })
|
249
623
|
end
|
250
624
|
end
|
251
625
|
|
252
|
-
|
253
|
-
|
254
|
-
|
626
|
+
# Return a lazy list of all combinations of length `n` of items from this `List`.
|
627
|
+
#
|
628
|
+
# @example
|
629
|
+
# Hamster.list(1,2,3).combination(2)
|
630
|
+
# # => Hamster::List[
|
631
|
+
# # Hamster::List[1, 2],
|
632
|
+
# # Hamster::List[1, 3],
|
633
|
+
# # Hamster::List[2, 3]]
|
634
|
+
#
|
635
|
+
# @return [List]
|
636
|
+
def combination(n)
|
637
|
+
return Cons.new(EmptyList) if n == 0
|
638
|
+
LazyList.new do
|
255
639
|
next self if empty?
|
256
|
-
tail.
|
640
|
+
tail.combination(n - 1).map { |list| list.cons(head) }.append(tail.combination(n))
|
257
641
|
end
|
258
642
|
end
|
259
|
-
def_delegator :self, :combinations, :combination
|
260
643
|
|
644
|
+
# Split the items in this list in groups of `number`. Return a list of lists.
|
645
|
+
#
|
646
|
+
# @example
|
647
|
+
# Hamster.list(*("a".."o")).chunk(5)
|
648
|
+
# # => Hamster::List[
|
649
|
+
# # Hamster::List["a", "b", "c", "d", "e"],
|
650
|
+
# # Hamster::List["f", "g", "h", "i", "j"],
|
651
|
+
# # Hamster::List["k", "l", "m", "n", "o"]]
|
652
|
+
#
|
653
|
+
# @return [List]
|
261
654
|
def chunk(number)
|
262
|
-
|
655
|
+
LazyList.new do
|
263
656
|
next self if empty?
|
264
657
|
first, remainder = split_at(number)
|
265
|
-
|
658
|
+
Cons.new(first, remainder.chunk(number))
|
266
659
|
end
|
267
660
|
end
|
268
661
|
|
662
|
+
# Split the items in this list in groups of `number`, and yield each group
|
663
|
+
# to the block (as a `List`).
|
664
|
+
# @return [self]
|
269
665
|
def each_chunk(number, &block)
|
666
|
+
return enum_for(:each_chunk, number) unless block_given?
|
270
667
|
chunk(number).each(&block)
|
668
|
+
self
|
271
669
|
end
|
272
|
-
|
273
|
-
|
670
|
+
alias :each_slice :each_chunk
|
671
|
+
|
672
|
+
# Return a new `List` with all nested lists recursively "flattened out",
|
673
|
+
# that is, their elements inserted into the new `List` in the place where
|
674
|
+
# the nested list originally was.
|
675
|
+
#
|
676
|
+
# @example
|
677
|
+
# Hamster.list(Hamster.list(1, 2), Hamster.list(3, 4)).flatten
|
678
|
+
# # => Hamster::List[1, 2, 3, 4]
|
679
|
+
#
|
680
|
+
# @return [List]
|
274
681
|
def flatten
|
275
|
-
|
682
|
+
LazyList.new do
|
276
683
|
next self if empty?
|
277
684
|
next head.append(tail.flatten) if head.is_a?(List)
|
278
|
-
|
685
|
+
Cons.new(head, tail.flatten)
|
279
686
|
end
|
280
687
|
end
|
281
688
|
|
689
|
+
# Passes each item to the block, and gathers them into a {Hash} where the
|
690
|
+
# keys are return values from the block, and the values are `List`s of items
|
691
|
+
# for which the block returned that value.
|
692
|
+
#
|
693
|
+
# @return [Hash]
|
282
694
|
def group_by(&block)
|
283
|
-
|
284
|
-
reduce(EmptyHash) do |hash, item|
|
285
|
-
key = yield(item)
|
286
|
-
hash.put(key, (hash.get(key) || EmptyList).cons(item))
|
287
|
-
end
|
695
|
+
group_by_with(EmptyList, &block)
|
288
696
|
end
|
289
|
-
|
697
|
+
alias :group :group_by
|
290
698
|
|
699
|
+
# Retrieve the item at `index`. Negative indices count back from the end of
|
700
|
+
# the list (-1 is the last item). If `index` is invalid (either too high or
|
701
|
+
# too low), return `nil`.
|
702
|
+
#
|
703
|
+
# @param index [Integer] The index to retrieve
|
704
|
+
# @return [Object]
|
291
705
|
def at(index)
|
292
|
-
|
706
|
+
index += size if index < 0
|
707
|
+
return nil if index < 0
|
708
|
+
node = self
|
709
|
+
while index > 0
|
710
|
+
node = node.tail
|
711
|
+
index -= 1
|
712
|
+
end
|
713
|
+
node.head
|
714
|
+
end
|
715
|
+
|
716
|
+
# Element reference. Return the item at a specific index, or a specified,
|
717
|
+
# contiguous range of items (as a new list).
|
718
|
+
#
|
719
|
+
# @overload list[index]
|
720
|
+
# Return the item at `index`.
|
721
|
+
# @param index [Integer] The index to retrieve.
|
722
|
+
# @overload list[start, length]
|
723
|
+
# Return a sublist starting at index `start` and continuing for `length` elements.
|
724
|
+
# @param start [Integer] The index to start retrieving items from.
|
725
|
+
# @param length [Integer] The number of items to retrieve.
|
726
|
+
# @overload list[range]
|
727
|
+
# Return a sublist specified by the given `range` of indices.
|
728
|
+
# @param range [Range] The range of indices to retrieve.
|
729
|
+
#
|
730
|
+
# @return [Object]
|
731
|
+
def [](arg, length = (missing_length = true))
|
732
|
+
if missing_length
|
733
|
+
if arg.is_a?(Range)
|
734
|
+
from, to = arg.begin, arg.end
|
735
|
+
from += size if from < 0
|
736
|
+
return nil if from < 0
|
737
|
+
to += size if to < 0
|
738
|
+
to += 1 if !arg.exclude_end?
|
739
|
+
length = to - from
|
740
|
+
length = 0 if length < 0
|
741
|
+
list = self
|
742
|
+
while from > 0
|
743
|
+
return nil if list.empty?
|
744
|
+
list = list.tail
|
745
|
+
from -= 1
|
746
|
+
end
|
747
|
+
list.take(length)
|
748
|
+
else
|
749
|
+
at(arg)
|
750
|
+
end
|
751
|
+
else
|
752
|
+
return nil if length < 0
|
753
|
+
arg += size if arg < 0
|
754
|
+
return nil if arg < 0
|
755
|
+
list = self
|
756
|
+
while arg > 0
|
757
|
+
return nil if list.empty?
|
758
|
+
list = list.tail
|
759
|
+
arg -= 1
|
760
|
+
end
|
761
|
+
list.take(length)
|
762
|
+
end
|
293
763
|
end
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
764
|
+
alias :slice :[]
|
765
|
+
|
766
|
+
# Return a `List` of indices where the given object is found, or where the given
|
767
|
+
# block returns true.
|
768
|
+
#
|
769
|
+
# @overload indices(obj)
|
770
|
+
# Return a `List` of indices where `obj` is found. Use `#==` for testing equality.
|
771
|
+
# @overload indices { |item| ... }
|
772
|
+
# Pass each item successively to the block. Return a list of indices where the
|
773
|
+
# block returns true.
|
774
|
+
#
|
775
|
+
# @return [List]
|
776
|
+
def indices(object = Undefined, i = 0, &block)
|
777
|
+
return indices { |item| item == object } if not block_given?
|
778
|
+
return EmptyList if empty?
|
779
|
+
LazyList.new do
|
780
|
+
node = self
|
781
|
+
while true
|
782
|
+
break Cons.new(i, node.tail.indices(Undefined, i + 1, &block)) if yield(node.head)
|
783
|
+
node = node.tail
|
784
|
+
break EmptyList if node.empty?
|
785
|
+
i += 1
|
786
|
+
end
|
787
|
+
end
|
298
788
|
end
|
299
|
-
def_delegator :self, :slice, :[]
|
300
789
|
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
790
|
+
# Merge all the nested lists into a single list, using the given comparator
|
791
|
+
# block to determine the order which items should be shifted out of the nested
|
792
|
+
# lists and into the output list. The comparator should take 2 parameters and
|
793
|
+
# return 0, 1, or -1 if the first parameter is (respectively) equal to, greater
|
794
|
+
# than, or less than the second parameter. Whichever nested list's `#head` is
|
795
|
+
# determined to be "lowest" according to the comparator will be the first in
|
796
|
+
# the merged `List`.
|
797
|
+
#
|
798
|
+
# @example
|
799
|
+
# list_1 = Hamster::List[1, -3, -5]
|
800
|
+
# list_2 = Hamster::List[-2, 4, 6]
|
801
|
+
# Hamster::List[list_1, list_2].merge { |a,b| a.abs <=> b.abs }
|
802
|
+
# # => Hamster::List[1, -2, -3, 4, -5, 6]
|
803
|
+
#
|
804
|
+
# @return [List]
|
805
|
+
def merge(&comparator)
|
806
|
+
return merge_by unless block_given?
|
807
|
+
LazyList.new do
|
808
|
+
sorted = reject(&:empty?).sort do |a, b|
|
809
|
+
yield(a.head, b.head)
|
810
|
+
end
|
811
|
+
next EmptyList if sorted.empty?
|
812
|
+
Cons.new(sorted.head.head, sorted.tail.cons(sorted.head.tail).merge(&comparator))
|
310
813
|
end
|
311
814
|
end
|
312
815
|
|
313
|
-
|
314
|
-
|
816
|
+
# Merge all the nested lists into a single list, using sort keys generated
|
817
|
+
# by mapping the items in the nested lists through the given block to determine the
|
818
|
+
# order which items should be shifted out of the nested lists and into the output
|
819
|
+
# list. Whichever nested list's `#head` has the "lowest" sort key (according to
|
820
|
+
# their natural order) will be the first in the merged `List`.
|
821
|
+
#
|
822
|
+
# @example
|
823
|
+
# list_1 = Hamster::List[1, -3, -5]
|
824
|
+
# list_2 = Hamster::List[-2, 4, 6]
|
825
|
+
# Hamster::List[list_1, list_2].merge_by { |x| x.abs }
|
826
|
+
# # => Hamster::List[1, -2, -3, 4, -5, 6]
|
827
|
+
#
|
828
|
+
# @return [List]
|
829
|
+
def merge_by(&transformer)
|
830
|
+
return merge_by { |item| item } unless block_given?
|
831
|
+
LazyList.new do
|
832
|
+
sorted = reject(&:empty?).sort_by do |list|
|
833
|
+
yield(list.head)
|
834
|
+
end
|
835
|
+
next EmptyList if sorted.empty?
|
836
|
+
Cons.new(sorted.head.head, sorted.tail.cons(sorted.head.tail).merge_by(&transformer))
|
837
|
+
end
|
315
838
|
end
|
316
839
|
|
317
|
-
|
318
|
-
|
319
|
-
|
840
|
+
# Return a randomly chosen element from this list.
|
841
|
+
# @return [Object]
|
842
|
+
def sample
|
843
|
+
at(rand(size))
|
844
|
+
end
|
845
|
+
|
846
|
+
# Return a new `List` with the given items inserted before the item at `index`.
|
847
|
+
#
|
848
|
+
# @example
|
849
|
+
# Hamster.list("A", "D", "E").insert(1, "B", "C") # => Hamster::List["A", "B", "C", "D", "E"]
|
850
|
+
#
|
851
|
+
# @param index [Integer] The index where the new items should go
|
852
|
+
# @param items [Array] The items to add
|
853
|
+
# @return [List]
|
854
|
+
def insert(index, *items)
|
855
|
+
if index == 0
|
856
|
+
return items.to_list.append(self)
|
857
|
+
elsif index > 0
|
858
|
+
LazyList.new do
|
859
|
+
Cons.new(head, tail.insert(index-1, *items))
|
860
|
+
end
|
861
|
+
else
|
862
|
+
raise IndexError if index < -size
|
863
|
+
insert(index + size, *items)
|
864
|
+
end
|
320
865
|
end
|
321
866
|
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
867
|
+
# Return a lazy list with all elements equal to `obj` removed. `#==` is used
|
868
|
+
# for testing equality.
|
869
|
+
#
|
870
|
+
# @example
|
871
|
+
# Hamster.list(:a, :b, :a, :a, :c).delete(:a) # => Hamster::List[:b, :c]
|
872
|
+
#
|
873
|
+
# @param obj [Object] The object to remove.
|
874
|
+
# @return [List]
|
875
|
+
def delete(obj)
|
876
|
+
list = self
|
877
|
+
list = list.tail while list.head == obj && !list.empty?
|
878
|
+
return EmptyList if list.empty?
|
879
|
+
LazyList.new { Cons.new(list.head, list.tail.delete(obj)) }
|
880
|
+
end
|
881
|
+
|
882
|
+
# Return a lazy list containing the same items, minus the one at `index`.
|
883
|
+
# If `index` is negative, it counts back from the end of the list.
|
884
|
+
#
|
885
|
+
# @example
|
886
|
+
# Hamster.list(1, 2, 3).delete_at(1) # => Hamster::List[1, 3]
|
887
|
+
# Hamster.list(1, 2, 3).delete_at(-1) # => Hamster::List[1, 2]
|
888
|
+
#
|
889
|
+
# @param index [Integer] The index of the item to remove
|
890
|
+
# @return [List]
|
891
|
+
def delete_at(index)
|
892
|
+
if index == 0
|
893
|
+
tail
|
894
|
+
elsif index < 0
|
895
|
+
index += size if index < 0
|
896
|
+
return self if index < 0
|
897
|
+
delete_at(index)
|
898
|
+
else
|
899
|
+
LazyList.new { Cons.new(head, tail.delete_at(index - 1)) }
|
328
900
|
end
|
329
901
|
end
|
330
902
|
|
331
|
-
|
332
|
-
|
903
|
+
# Replace a range of indexes with the given object.
|
904
|
+
#
|
905
|
+
# @overload fill(obj)
|
906
|
+
# Return a new `List` of the same size, with every item set to `obj`.
|
907
|
+
# @overload fill(obj, start)
|
908
|
+
# Return a new `List` with all indexes from `start` to the end of the
|
909
|
+
# list set to `obj`.
|
910
|
+
# @overload fill(obj, start, length)
|
911
|
+
# Return a new `List` with `length` indexes, beginning from `start`,
|
912
|
+
# set to `obj`.
|
913
|
+
#
|
914
|
+
# @example
|
915
|
+
# list = Hamster.list("a", "b", "c", "d")
|
916
|
+
# list.fill("x") # => Hamster::List["x", "x", "x", "x"]
|
917
|
+
# list.fill("z", 2) # => Hamster::List["a", "b", "z", "z"]
|
918
|
+
# list.fill("y", 0, 2) # => Hamster::List["y", "y", "c", "d"]
|
919
|
+
#
|
920
|
+
# @return [List]
|
921
|
+
def fill(obj, index = 0, length = nil)
|
922
|
+
if index == 0
|
923
|
+
length ||= size
|
924
|
+
if length > 0
|
925
|
+
LazyList.new do
|
926
|
+
Cons.new(obj, tail.fill(obj, 0, length-1))
|
927
|
+
end
|
928
|
+
else
|
929
|
+
self
|
930
|
+
end
|
931
|
+
elsif index > 0
|
932
|
+
LazyList.new do
|
933
|
+
Cons.new(head, tail.fill(obj, index-1, length))
|
934
|
+
end
|
935
|
+
else
|
936
|
+
raise IndexError if index < -size
|
937
|
+
fill(obj, index + size, length)
|
938
|
+
end
|
333
939
|
end
|
334
940
|
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
941
|
+
# Yields all permutations of length `n` of the items in the list, and then
|
942
|
+
# returns `self`. If no length `n` is specified, permutations of the entire
|
943
|
+
# list will be yielded.
|
944
|
+
#
|
945
|
+
# There is no guarantee about which order the permutations will be yielded in.
|
946
|
+
#
|
947
|
+
# If no block is given, an `Enumerator` is returned instead.
|
948
|
+
#
|
949
|
+
# @example
|
950
|
+
# Hamster.list(1, 2, 3).permutation.to_a
|
951
|
+
# # => [Hamster::List[1, 2, 3],
|
952
|
+
# # Hamster::List[2, 1, 3],
|
953
|
+
# # Hamster::List[2, 3, 1],
|
954
|
+
# # Hamster::List[1, 3, 2],
|
955
|
+
# # Hamster::List[3, 1, 2],
|
956
|
+
# # Hamster::List[3, 2, 1]]
|
957
|
+
#
|
958
|
+
# @return [self, Enumerator]
|
959
|
+
def permutation(length = size, &block)
|
960
|
+
return enum_for(:permutation, length) if not block_given?
|
961
|
+
if length == 0
|
962
|
+
yield EmptyList
|
963
|
+
elsif length == 1
|
964
|
+
each { |obj| yield Cons.new(obj, EmptyList) }
|
965
|
+
elsif not empty?
|
966
|
+
if length < size
|
967
|
+
tail.permutation(length, &block)
|
968
|
+
end
|
339
969
|
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
970
|
+
tail.permutation(length-1) do |p|
|
971
|
+
0.upto(length-1) do |i|
|
972
|
+
left,right = p.split_at(i)
|
973
|
+
yield left.append(right.cons(head))
|
974
|
+
end
|
345
975
|
end
|
346
|
-
next EmptyList if sorted.empty?
|
347
|
-
Sequence.new(sorted.head.head, sorted.tail.cons(sorted.head.tail).merge(&comparator))
|
348
976
|
end
|
977
|
+
self
|
349
978
|
end
|
350
979
|
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
980
|
+
# Yield every non-empty sublist to the given block. (The entire `List` also
|
981
|
+
# counts as one sublist.)
|
982
|
+
#
|
983
|
+
# @example
|
984
|
+
# Hamster.list(1, 2, 3).subsequences { |list| p list }
|
985
|
+
# # prints:
|
986
|
+
# # Hamster::List[1]
|
987
|
+
# # Hamster::List[1, 2]
|
988
|
+
# # Hamster::List[1, 2, 3]
|
989
|
+
# # Hamster::List[2]
|
990
|
+
# # Hamster::List[2, 3]
|
991
|
+
# # Hamster::List[3]
|
992
|
+
#
|
993
|
+
# @yield [sublist] One or more contiguous elements from this list
|
994
|
+
# @return [self]
|
995
|
+
def subsequences(&block)
|
996
|
+
return enum_for(:subsequences) if not block_given?
|
997
|
+
if not empty?
|
998
|
+
1.upto(size) do |n|
|
999
|
+
yield take(n)
|
356
1000
|
end
|
357
|
-
|
358
|
-
Sequence.new(sorted.head.head, sorted.tail.cons(sorted.head.tail).merge_by(&transformer))
|
1001
|
+
tail.subsequences(&block)
|
359
1002
|
end
|
1003
|
+
self
|
360
1004
|
end
|
361
1005
|
|
1006
|
+
# Return 2 `List`s, the first containing all the elements for which the block
|
1007
|
+
# evaluates to true, the second containing the rest.
|
1008
|
+
#
|
1009
|
+
# @example
|
1010
|
+
# Hamster.list(1, 2, 3, 4, 5, 6).partition { |x| x.even? }
|
1011
|
+
# # => [Hamster::List[2, 4, 6], Hamster::List[1, 3, 5]]
|
1012
|
+
#
|
1013
|
+
# @return [List]
|
1014
|
+
def partition(&block)
|
1015
|
+
return enum_for(:partition) if not block_given?
|
1016
|
+
partitioner = Partitioner.new(self, block)
|
1017
|
+
mutex = Mutex.new
|
1018
|
+
[Partitioned.new(partitioner, partitioner.left, mutex),
|
1019
|
+
Partitioned.new(partitioner, partitioner.right, mutex)].freeze
|
1020
|
+
end
|
1021
|
+
|
1022
|
+
# Return true if `other` has the same type and contents as this `Hash`.
|
1023
|
+
#
|
1024
|
+
# @param other [Object] The collection to compare with
|
1025
|
+
# @return [Boolean]
|
362
1026
|
def eql?(other)
|
363
1027
|
list = self
|
364
1028
|
loop do
|
@@ -371,57 +1035,96 @@ module Hamster
|
|
371
1035
|
other = other.tail
|
372
1036
|
end
|
373
1037
|
end
|
374
|
-
def_delegator :self, :eql?, :==
|
375
1038
|
|
1039
|
+
# See `Object#hash`
|
1040
|
+
# @return [Integer]
|
376
1041
|
def hash
|
377
1042
|
reduce(0) { |hash, item| (hash << 5) - hash + item.hash }
|
378
1043
|
end
|
379
1044
|
|
1045
|
+
# Return `self`.
|
1046
|
+
# @return [List]
|
380
1047
|
def dup
|
381
1048
|
self
|
382
1049
|
end
|
383
|
-
|
1050
|
+
alias :clone :dup
|
384
1051
|
|
1052
|
+
# Return `self`.
|
1053
|
+
# @return [List]
|
385
1054
|
def to_list
|
386
1055
|
self
|
387
1056
|
end
|
388
1057
|
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
1058
|
+
# Return the contents of this `List` as a programmer-readable `String`. If all the
|
1059
|
+
# items in the list are serializable as Ruby literal strings, the returned string can
|
1060
|
+
# be passed to `eval` to reconstitute an equivalent `List`.
|
1061
|
+
#
|
1062
|
+
# @return [String]
|
393
1063
|
def inspect
|
394
|
-
|
1064
|
+
result = "Hamster::List["
|
1065
|
+
each_with_index { |obj, i| result << ', ' if i > 0; result << obj.inspect }
|
1066
|
+
result << "]"
|
1067
|
+
end
|
1068
|
+
|
1069
|
+
# Allows this `List` to be printed at the `pry` console, or using `pp` (from the
|
1070
|
+
# Ruby standard library), in a way which takes the amount of horizontal space on
|
1071
|
+
# the screen into account, and which indents nested structures to make them easier
|
1072
|
+
# to read.
|
1073
|
+
#
|
1074
|
+
# @private
|
1075
|
+
def pretty_print(pp)
|
1076
|
+
pp.group(1, "Hamster::List[", "]") do
|
1077
|
+
pp.breakable ''
|
1078
|
+
pp.seplist(self) { |obj| obj.pretty_print(pp) }
|
1079
|
+
end
|
395
1080
|
end
|
396
1081
|
|
1082
|
+
# @private
|
397
1083
|
def respond_to?(name, include_private = false)
|
398
|
-
super ||
|
1084
|
+
super || !!name.to_s.match(CADR)
|
1085
|
+
end
|
1086
|
+
|
1087
|
+
# Return `true` if the size of this list can be obtained in constant time (without
|
1088
|
+
# traversing the list).
|
1089
|
+
# @return [Integer]
|
1090
|
+
def cached_size?
|
1091
|
+
false
|
399
1092
|
end
|
400
1093
|
|
401
1094
|
private
|
402
1095
|
|
403
1096
|
def method_missing(name, *args, &block)
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
1097
|
+
if name.to_s.match(CADR)
|
1098
|
+
# Perform compositions of car and cdr operations. Their names consist of a 'c',
|
1099
|
+
# followed by at least one 'a' or 'd', and finally an 'r'. The series of 'a's and
|
1100
|
+
# 'd's in the method name identify the series of car and cdr operations performed.
|
1101
|
+
# The order in which the 'a's and 'd's appear is the inverse of the order in which
|
1102
|
+
# the corresponding operations are performed.
|
1103
|
+
code = "def #{name}; self."
|
1104
|
+
code << Regexp.last_match[1].reverse.chars.map do |char|
|
1105
|
+
{'a' => 'head', 'd' => 'tail'}[char]
|
1106
|
+
end.join('.')
|
1107
|
+
code << '; end'
|
1108
|
+
List.class_eval(code)
|
1109
|
+
send(name, *args, &block)
|
1110
|
+
else
|
1111
|
+
super
|
418
1112
|
end
|
419
1113
|
end
|
420
|
-
|
421
1114
|
end
|
422
1115
|
|
423
|
-
|
424
|
-
|
1116
|
+
# The basic building block for constructing lists
|
1117
|
+
#
|
1118
|
+
# A Cons, also known as a "cons cell", has a "head" and a "tail", where
|
1119
|
+
# the head is an element in the list, and the tail is a reference to the
|
1120
|
+
# rest of the list. This way a singly linked list can be constructed, with
|
1121
|
+
# each `Cons` holding a single element and a pointer to the next
|
1122
|
+
# `Cons`.
|
1123
|
+
#
|
1124
|
+
# The last `Cons` instance in the chain has the {EmptyList} as its tail.
|
1125
|
+
#
|
1126
|
+
# @private
|
1127
|
+
class Cons
|
425
1128
|
include List
|
426
1129
|
|
427
1130
|
attr_reader :head, :tail
|
@@ -429,63 +1132,292 @@ module Hamster
|
|
429
1132
|
def initialize(head, tail = EmptyList)
|
430
1133
|
@head = head
|
431
1134
|
@tail = tail
|
1135
|
+
@size = tail.cached_size? ? tail.size + 1 : nil
|
432
1136
|
end
|
433
1137
|
|
434
1138
|
def empty?
|
435
1139
|
false
|
436
1140
|
end
|
437
1141
|
|
1142
|
+
def size
|
1143
|
+
@size ||= super
|
1144
|
+
end
|
1145
|
+
alias :length :size
|
1146
|
+
|
1147
|
+
def cached_size?
|
1148
|
+
@size != nil
|
1149
|
+
end
|
438
1150
|
end
|
439
1151
|
|
440
|
-
|
1152
|
+
# A `LazyList` takes a block that returns a `List`, i.e. an object that responds
|
1153
|
+
# to `#head`, `#tail` and `#empty?`. The list is only realized (i.e. the block is
|
1154
|
+
# only called) when one of these operations is performed.
|
1155
|
+
#
|
1156
|
+
# By returning a `Cons` that in turn has a {LazyList} as its tail, one can
|
1157
|
+
# construct infinite lazy lists.
|
1158
|
+
#
|
1159
|
+
# @private
|
1160
|
+
class LazyList
|
1161
|
+
include List
|
1162
|
+
|
1163
|
+
def initialize(&block)
|
1164
|
+
@head = block # doubles as storage for block while yet unrealized
|
1165
|
+
@tail = nil
|
1166
|
+
@atomic = Atomic.new(0) # haven't yet run block
|
1167
|
+
@size = nil
|
1168
|
+
end
|
1169
|
+
|
1170
|
+
def head
|
1171
|
+
realize if @atomic.get != 2
|
1172
|
+
@head
|
1173
|
+
end
|
1174
|
+
alias :first :head
|
1175
|
+
|
1176
|
+
def tail
|
1177
|
+
realize if @atomic.get != 2
|
1178
|
+
@tail
|
1179
|
+
end
|
441
1180
|
|
442
|
-
|
1181
|
+
def empty?
|
1182
|
+
realize if @atomic.get != 2
|
1183
|
+
@size == 0
|
1184
|
+
end
|
1185
|
+
|
1186
|
+
def size
|
1187
|
+
@size ||= super
|
1188
|
+
end
|
1189
|
+
alias :length :size
|
1190
|
+
|
1191
|
+
def cached_size?
|
1192
|
+
@size != nil
|
1193
|
+
end
|
443
1194
|
|
1195
|
+
private
|
1196
|
+
|
1197
|
+
QUEUE = ConditionVariable.new
|
1198
|
+
MUTEX = Mutex.new
|
1199
|
+
|
1200
|
+
def realize
|
1201
|
+
while true
|
1202
|
+
# try to "claim" the right to run the block which realizes target
|
1203
|
+
if @atomic.compare_and_swap(0,1) # full memory barrier here
|
1204
|
+
begin
|
1205
|
+
list = @head.call
|
1206
|
+
if list.empty?
|
1207
|
+
@head, @tail, @size = nil, self, 0
|
1208
|
+
else
|
1209
|
+
@head, @tail = list.head, list.tail
|
1210
|
+
end
|
1211
|
+
rescue
|
1212
|
+
@atomic.set(0)
|
1213
|
+
MUTEX.synchronize { QUEUE.broadcast }
|
1214
|
+
raise
|
1215
|
+
end
|
1216
|
+
@atomic.set(2)
|
1217
|
+
MUTEX.synchronize { QUEUE.broadcast }
|
1218
|
+
return
|
1219
|
+
end
|
1220
|
+
# we failed to "claim" it, another thread must be running it
|
1221
|
+
if @atomic.get == 1 # another thread is running the block
|
1222
|
+
MUTEX.synchronize do
|
1223
|
+
# check value of @atomic again, in case another thread already changed it
|
1224
|
+
# *and* went past the call to QUEUE.broadcast before we got here
|
1225
|
+
QUEUE.wait(MUTEX) if @atomic.get == 1
|
1226
|
+
end
|
1227
|
+
elsif @atomic.get == 2 # another thread finished the block
|
1228
|
+
return
|
1229
|
+
end
|
1230
|
+
end
|
1231
|
+
end
|
1232
|
+
end
|
1233
|
+
|
1234
|
+
# Common behavior for other classes which implement various kinds of lazy lists
|
1235
|
+
# @private
|
1236
|
+
class Realizable
|
444
1237
|
include List
|
445
1238
|
|
446
|
-
def initialize
|
447
|
-
@
|
448
|
-
@lock = Mutex.new
|
1239
|
+
def initialize
|
1240
|
+
@head, @tail, @size = Undefined, Undefined, nil
|
449
1241
|
end
|
450
1242
|
|
451
|
-
|
452
|
-
|
453
|
-
|
1243
|
+
def head
|
1244
|
+
realize if @head == Undefined
|
1245
|
+
@head
|
1246
|
+
end
|
1247
|
+
alias :first :head
|
454
1248
|
|
455
|
-
|
1249
|
+
def tail
|
1250
|
+
realize if @tail == Undefined
|
1251
|
+
@tail
|
1252
|
+
end
|
1253
|
+
|
1254
|
+
def empty?
|
1255
|
+
realize if @head == Undefined
|
1256
|
+
@size == 0
|
1257
|
+
end
|
456
1258
|
|
457
|
-
def
|
458
|
-
@
|
459
|
-
|
460
|
-
|
461
|
-
|
1259
|
+
def size
|
1260
|
+
@size ||= super
|
1261
|
+
end
|
1262
|
+
alias :length :size
|
1263
|
+
|
1264
|
+
def cached_size?
|
1265
|
+
@size != nil
|
1266
|
+
end
|
1267
|
+
|
1268
|
+
def realized?
|
1269
|
+
@head != Undefined
|
1270
|
+
end
|
1271
|
+
end
|
1272
|
+
|
1273
|
+
# This class can divide a collection into 2 lazy lists, one of items
|
1274
|
+
# for which the block returns true, and another for false
|
1275
|
+
# At the same time, it guarantees the block will only be called ONCE for each item
|
1276
|
+
#
|
1277
|
+
# @private
|
1278
|
+
class Partitioner
|
1279
|
+
attr_reader :left, :right
|
1280
|
+
def initialize(list, block)
|
1281
|
+
@list, @block, @left, @right = list, block, [], []
|
1282
|
+
end
|
1283
|
+
|
1284
|
+
def next_item
|
1285
|
+
unless @list.empty?
|
1286
|
+
item = @list.head
|
1287
|
+
(@block.call(item) ? @left : @right) << item
|
1288
|
+
@list = @list.tail
|
1289
|
+
end
|
1290
|
+
end
|
1291
|
+
|
1292
|
+
def done?
|
1293
|
+
@list.empty?
|
1294
|
+
end
|
1295
|
+
end
|
1296
|
+
|
1297
|
+
# One of the lazy lists which gets its items from a Partitioner
|
1298
|
+
# @private
|
1299
|
+
class Partitioned < Realizable
|
1300
|
+
def initialize(partitioner, buffer, mutex)
|
1301
|
+
super()
|
1302
|
+
@partitioner, @buffer, @mutex = partitioner, buffer, mutex
|
1303
|
+
end
|
1304
|
+
|
1305
|
+
def realize
|
1306
|
+
@mutex.synchronize do
|
1307
|
+
return if @head != Undefined # another thread got ahead of us
|
1308
|
+
while true
|
1309
|
+
if !@buffer.empty?
|
1310
|
+
@head = @buffer.shift
|
1311
|
+
@tail = Partitioned.new(@partitioner, @buffer, @mutex)
|
1312
|
+
# don't hold onto references
|
1313
|
+
# tail will keep references alive until end of list is reached
|
1314
|
+
@partitioner, @buffer, @mutex = nil, nil, nil
|
1315
|
+
return
|
1316
|
+
elsif @partitioner.done?
|
1317
|
+
@head, @size, @tail = nil, 0, self
|
1318
|
+
@partitioner, @buffer, @mutex = nil, nil, nil # allow them to be GC'd
|
1319
|
+
return
|
1320
|
+
else
|
1321
|
+
@partitioner.next_item
|
1322
|
+
end
|
462
1323
|
end
|
463
1324
|
end
|
464
|
-
@target
|
465
1325
|
end
|
1326
|
+
end
|
466
1327
|
|
467
|
-
|
1328
|
+
# This class can divide a list up into 2 lazy lists, one for the prefix of elements
|
1329
|
+
# for which the block returns true, and another for all the elements after that
|
1330
|
+
# It guarantees that the block will only be called ONCE for each item
|
1331
|
+
#
|
1332
|
+
# @private
|
1333
|
+
class Splitter
|
1334
|
+
attr_reader :left, :right
|
1335
|
+
def initialize(list, block)
|
1336
|
+
@list, @block, @left, @right = list, block, [], EmptyList
|
1337
|
+
end
|
1338
|
+
|
1339
|
+
def next_item
|
1340
|
+
unless @list.empty?
|
1341
|
+
item = @list.head
|
1342
|
+
if @block.call(item)
|
1343
|
+
@left << item
|
1344
|
+
@list = @list.tail
|
1345
|
+
else
|
1346
|
+
@right = @list
|
1347
|
+
@list = EmptyList
|
1348
|
+
end
|
1349
|
+
end
|
1350
|
+
end
|
1351
|
+
|
1352
|
+
def done?
|
1353
|
+
@list.empty?
|
1354
|
+
end
|
1355
|
+
|
1356
|
+
# @private
|
1357
|
+
class Left < Realizable
|
1358
|
+
def initialize(splitter, buffer, mutex)
|
1359
|
+
super()
|
1360
|
+
@splitter, @buffer, @mutex = splitter, buffer, mutex
|
1361
|
+
end
|
468
1362
|
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
1363
|
+
def realize
|
1364
|
+
@mutex.synchronize do
|
1365
|
+
return if @head != Undefined # another thread got ahead of us
|
1366
|
+
while true
|
1367
|
+
if !@buffer.empty?
|
1368
|
+
@head = @buffer.shift
|
1369
|
+
@tail = Left.new(@splitter, @buffer, @mutex)
|
1370
|
+
@splitter, @buffer, @mutex = nil, nil, nil
|
1371
|
+
return
|
1372
|
+
elsif @splitter.done?
|
1373
|
+
@head, @size, @tail = nil, 0, self
|
1374
|
+
@splitter, @buffer, @mutex = nil, nil, nil
|
1375
|
+
return
|
1376
|
+
else
|
1377
|
+
@splitter.next_item
|
1378
|
+
end
|
1379
|
+
end
|
1380
|
+
end
|
473
1381
|
end
|
474
|
-
list
|
475
1382
|
end
|
476
1383
|
|
1384
|
+
# @private
|
1385
|
+
class Right < Realizable
|
1386
|
+
def initialize(splitter, mutex)
|
1387
|
+
super()
|
1388
|
+
@splitter, @mutex = splitter, mutex
|
1389
|
+
end
|
1390
|
+
|
1391
|
+
def realize
|
1392
|
+
@mutex.synchronize do
|
1393
|
+
return if @head != Undefined
|
1394
|
+
@splitter.next_item until @splitter.done?
|
1395
|
+
if @splitter.right.empty?
|
1396
|
+
@head, @size, @tail = nil, 0, self
|
1397
|
+
else
|
1398
|
+
@head, @tail = @splitter.right.head, @splitter.right.tail
|
1399
|
+
end
|
1400
|
+
@splitter, @mutex = nil, nil
|
1401
|
+
end
|
1402
|
+
end
|
1403
|
+
end
|
477
1404
|
end
|
478
1405
|
|
1406
|
+
# A list without any elements. This is a singleton, since all empty lists are equivalent.
|
1407
|
+
#
|
479
1408
|
module EmptyList
|
480
|
-
|
481
1409
|
class << self
|
482
|
-
|
483
1410
|
include List
|
484
1411
|
|
1412
|
+
# There is no first item in an empty list, so return `nil`.
|
1413
|
+
# @return [nil]
|
485
1414
|
def head
|
486
1415
|
nil
|
487
1416
|
end
|
1417
|
+
alias :first :head
|
488
1418
|
|
1419
|
+
# There are no subsequent elements, so return an empty list.
|
1420
|
+
# @return [self]
|
489
1421
|
def tail
|
490
1422
|
self
|
491
1423
|
end
|
@@ -494,8 +1426,16 @@ module Hamster
|
|
494
1426
|
true
|
495
1427
|
end
|
496
1428
|
|
497
|
-
|
1429
|
+
# Return the number of items in this `List`.
|
1430
|
+
# @return [Integer]
|
1431
|
+
def size
|
1432
|
+
0
|
1433
|
+
end
|
1434
|
+
alias :length :size
|
498
1435
|
|
1436
|
+
def cached_size?
|
1437
|
+
true
|
1438
|
+
end
|
1439
|
+
end
|
499
1440
|
end
|
500
|
-
|
501
1441
|
end
|