farce 0.0.1.alpha2-java
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/CODE_OF_CONDUCT.md +26 -0
- data/CONTRIBUTING.md +71 -0
- data/MIT-LICENSE +20 -0
- data/README.md +1524 -0
- data/SECURITY.md +10 -0
- data/docs/benchmarks.md +185 -0
- data/docs/gems/dry-types.md +290 -0
- data/docs/gems/msgpack.md +70 -0
- data/docs/gems/ractor-shim.md +63 -0
- data/docs/modes.md +628 -0
- data/docs/scopes.md +649 -0
- data/docs/variants.md +346 -0
- data/lib/farce/_yard/internal.rb +13 -0
- data/lib/farce/_yard/macros.rb +61 -0
- data/lib/farce/_yard/ractor.rb +46 -0
- data/lib/farce/abstract/atom.rb +186 -0
- data/lib/farce/abstract/bounded_map.rb +232 -0
- data/lib/farce/abstract/collection.rb +151 -0
- data/lib/farce/abstract/concurrent_map.rb +381 -0
- data/lib/farce/abstract/counter.rb +193 -0
- data/lib/farce/abstract/duplicable_map.rb +229 -0
- data/lib/farce/abstract/exchanger.rb +26 -0
- data/lib/farce/abstract/flag.rb +71 -0
- data/lib/farce/abstract/lazy.rb +115 -0
- data/lib/farce/abstract/lease.rb +104 -0
- data/lib/farce/abstract/lease_map.rb +261 -0
- data/lib/farce/abstract/lease_pool.rb +91 -0
- data/lib/farce/abstract/lfu_map.rb +20 -0
- data/lib/farce/abstract/lru_map.rb +25 -0
- data/lib/farce/abstract/map.rb +345 -0
- data/lib/farce/abstract/molecule.rb +245 -0
- data/lib/farce/abstract/port.rb +74 -0
- data/lib/farce/abstract/priority_queue.rb +117 -0
- data/lib/farce/abstract/queue.rb +269 -0
- data/lib/farce/abstract/scheduler.rb +111 -0
- data/lib/farce/abstract/set.rb +910 -0
- data/lib/farce/abstract/sorted_set.rb +172 -0
- data/lib/farce/abstract/timer_queue.rb +136 -0
- data/lib/farce/abstract/tree_map.rb +269 -0
- data/lib/farce/abstract/value.rb +68 -0
- data/lib/farce/abstract/vector.rb +1126 -0
- data/lib/farce/abstract/weak_atom.rb +32 -0
- data/lib/farce/abstract/weak_key_map.rb +12 -0
- data/lib/farce/abstract/weak_map.rb +13 -0
- data/lib/farce/abstract/weak_set.rb +12 -0
- data/lib/farce/abstract/weak_value_map.rb +12 -0
- data/lib/farce/abstract.rb +17 -0
- data/lib/farce/atom.rb +293 -0
- data/lib/farce/class_mirror.rb +87 -0
- data/lib/farce/clock.rb +121 -0
- data/lib/farce/config.rb +229 -0
- data/lib/farce/counter.rb +71 -0
- data/lib/farce/deduper.rb +122 -0
- data/lib/farce/engine/jruby/bounded_map.rb +314 -0
- data/lib/farce/engine/jruby/fiber_scheduler.jar +0 -0
- data/lib/farce/engine/jruby/fiber_scheduler.rb +119 -0
- data/lib/farce/engine/jruby/lease_waiting.rb +19 -0
- data/lib/farce/engine/jruby/map.rb +505 -0
- data/lib/farce/engine/jruby/mutable_numeric_copy.rb +42 -0
- data/lib/farce/engine/jruby/signal.rb +147 -0
- data/lib/farce/engine/jruby.rb +63 -0
- data/lib/farce/engine/jvm/concurrent_weak_registry.rb +55 -0
- data/lib/farce/engine/jvm/counter.rb +102 -0
- data/lib/farce/engine/jvm/extension.rb +32 -0
- data/lib/farce/engine/jvm/farce.jar +0 -0
- data/lib/farce/engine/jvm/flag.rb +79 -0
- data/lib/farce/engine/jvm/priority_queue.rb +217 -0
- data/lib/farce/engine/jvm/tree_map.rb +350 -0
- data/lib/farce/engine/jvm/types.rb +180 -0
- data/lib/farce/engine/jvm.rb +19 -0
- data/lib/farce/engine/ruby/3.4/fiber_scheduler.rb +20 -0
- data/lib/farce/engine/ruby/3.4/port.rb +186 -0
- data/lib/farce/engine/ruby/3.4/ractor_methods.rb +26 -0
- data/lib/farce/engine/ruby/3.4/ractor_selector.rb +92 -0
- data/lib/farce/engine/ruby/3.4/vault.rb +56 -0
- data/lib/farce/engine/ruby/4.0/port.rb +19 -0
- data/lib/farce/engine/ruby/4.0/ractor_methods.rb +20 -0
- data/lib/farce/engine/ruby/4.0/ractor_selector.rb +108 -0
- data/lib/farce/engine/ruby/4.0/vault.rb +74 -0
- data/lib/farce/engine/ruby/4.1/port.rb +21 -0
- data/lib/farce/engine/ruby/4.1/ractor_methods.rb +22 -0
- data/lib/farce/engine/ruby/4.1/ractor_selector.rb +25 -0
- data/lib/farce/engine/ruby/4.1/vault.rb +5 -0
- data/lib/farce/engine/ruby/fiber_scheduler.rb +32 -0
- data/lib/farce/engine/ruby/key_lock_map.rb +28 -0
- data/lib/farce/engine/ruby/shared/lease.rb +26 -0
- data/lib/farce/engine/ruby/shared/lease_pool.rb +24 -0
- data/lib/farce/engine/ruby/shared/main_scheduler.rb +9 -0
- data/lib/farce/engine/ruby/shared/parallel_scheduler.rb +9 -0
- data/lib/farce/engine/ruby/shared/proxy_owner.rb +31 -0
- data/lib/farce/engine/ruby/shared/ractor_methods.rb +34 -0
- data/lib/farce/engine/ruby/shared/ractor_selector.rb +328 -0
- data/lib/farce/engine/ruby/shared/strict_map.rb +13 -0
- data/lib/farce/engine/ruby/shared/unshared_vector.rb +14 -0
- data/lib/farce/engine/ruby/shared/vault.rb +144 -0
- data/lib/farce/engine/ruby/shared/vault_weak_map.rb +336 -0
- data/lib/farce/engine/ruby/shared/weak_atom.rb +54 -0
- data/lib/farce/engine/ruby/shared/weak_map.rb +413 -0
- data/lib/farce/engine/ruby.rb +130 -0
- data/lib/farce/engine/shared/atom.rb +10 -0
- data/lib/farce/engine/shared/exchanger.rb +130 -0
- data/lib/farce/engine/shared/identity_key.rb +22 -0
- data/lib/farce/engine/shared/lease.rb +10 -0
- data/lib/farce/engine/shared/lease_pool.rb +10 -0
- data/lib/farce/engine/shared/main_scheduler.rb +20 -0
- data/lib/farce/engine/shared/map_key_coordination.rb +226 -0
- data/lib/farce/engine/shared/parallel_scheduler.rb +9 -0
- data/lib/farce/engine/shared/port.rb +44 -0
- data/lib/farce/engine/shared/portable_bounded_map.rb +619 -0
- data/lib/farce/engine/shared/proxy_owner.rb +43 -0
- data/lib/farce/engine/shared/queue.rb +233 -0
- data/lib/farce/engine/shared/ractor_methods.rb +73 -0
- data/lib/farce/engine/shared/rebindable.rb +15 -0
- data/lib/farce/engine/shared/strict_atom.rb +73 -0
- data/lib/farce/engine/shared/strict_map.rb +117 -0
- data/lib/farce/engine/shared/strict_queue_values.rb +27 -0
- data/lib/farce/engine/shared/strict_tree_map.rb +56 -0
- data/lib/farce/engine/shared/transaction_map_backend.rb +20 -0
- data/lib/farce/engine/shared/trie.rb +317 -0
- data/lib/farce/engine/shared/trie_builder.rb +199 -0
- data/lib/farce/engine/shared/unshareable.rb +14 -0
- data/lib/farce/engine/shared/unshared_atom.rb +256 -0
- data/lib/farce/engine/shared/unshared_priority_queue.rb +9 -0
- data/lib/farce/engine/shared/unshared_queue.rb +18 -0
- data/lib/farce/engine/shared/unshared_signal.rb +21 -0
- data/lib/farce/engine/shared/unshared_vector.rb +377 -0
- data/lib/farce/engine/shared/unshared_weak_atom.rb +30 -0
- data/lib/farce/engine/shared/unshared_weak_map.rb +445 -0
- data/lib/farce/engine/shared/vault.rb +31 -0
- data/lib/farce/engine/shared/vector.rb +83 -0
- data/lib/farce/engine/shared/weak_atom/base.rb +189 -0
- data/lib/farce/engine/shared/weak_atom.rb +20 -0
- data/lib/farce/engine/shared/weak_map/cell.rb +99 -0
- data/lib/farce/engine/shared/weak_map/index.rb +249 -0
- data/lib/farce/engine/shared/weak_map/lock.rb +80 -0
- data/lib/farce/engine/shared/weak_map/reference.rb +33 -0
- data/lib/farce/engine/shared.rb +63 -0
- data/lib/farce/engine/truffleruby/fiber_scheduler.rb +13 -0
- data/lib/farce/engine/truffleruby/lock.rb +121 -0
- data/lib/farce/engine/truffleruby/map.rb +656 -0
- data/lib/farce/engine/truffleruby/native/counter.rb +105 -0
- data/lib/farce/engine/truffleruby/native/flag.rb +77 -0
- data/lib/farce/engine/truffleruby/native/ordered_array_support.rb +67 -0
- data/lib/farce/engine/truffleruby/native/priority_queue.rb +388 -0
- data/lib/farce/engine/truffleruby/native/tree_map.rb +51 -0
- data/lib/farce/engine/truffleruby/native/unsafe_tree_map.rb +350 -0
- data/lib/farce/engine/truffleruby/signal.rb +77 -0
- data/lib/farce/engine/truffleruby.rb +148 -0
- data/lib/farce/envelope.rb +335 -0
- data/lib/farce/error.rb +35 -0
- data/lib/farce/exchanger.rb +41 -0
- data/lib/farce/flag.rb +27 -0
- data/lib/farce/integrations/active_support/blank.rb +68 -0
- data/lib/farce/integrations/active_support/clock.rb +17 -0
- data/lib/farce/integrations/active_support/duplicable.rb +78 -0
- data/lib/farce/integrations/active_support/map.rb +175 -0
- data/lib/farce/integrations/active_support/set.rb +60 -0
- data/lib/farce/integrations/active_support/value_serialization.rb +17 -0
- data/lib/farce/integrations/active_support/vector.rb +231 -0
- data/lib/farce/integrations/active_support.rb +9 -0
- data/lib/farce/integrations/activesupport.rb +5 -0
- data/lib/farce/integrations/bson.rb +108 -0
- data/lib/farce/integrations/cbor.rb +51 -0
- data/lib/farce/integrations/concurrent.rb +112 -0
- data/lib/farce/integrations/dry-types.rb +5 -0
- data/lib/farce/integrations/dry_types.rb +694 -0
- data/lib/farce/integrations/json.rb +7 -0
- data/lib/farce/integrations/msgpack.rb +112 -0
- data/lib/farce/integrations/oj.rb +69 -0
- data/lib/farce/integrations/psych.rb +191 -0
- data/lib/farce/integrations/ractor-sharing.rb +5 -0
- data/lib/farce/integrations/ractor-tmvar.rb +5 -0
- data/lib/farce/integrations/ractor_sharing.rb +172 -0
- data/lib/farce/integrations/ractor_tmvar.rb +64 -0
- data/lib/farce/integrations/shared/to_json.rb +42 -0
- data/lib/farce/integrations/sorted_set.rb +11 -0
- data/lib/farce/integrations/weakref.rb +38 -0
- data/lib/farce/integrations/yajl.rb +10 -0
- data/lib/farce/integrations.rb +156 -0
- data/lib/farce/internal/_frozen_config.rb +11 -0
- data/lib/farce/internal/autoloads.rb +47 -0
- data/lib/farce/internal/blocking_priority_queue.rb +122 -0
- data/lib/farce/internal/converter.rb +106 -0
- data/lib/farce/internal/copyable.rb +31 -0
- data/lib/farce/internal/delegation.rb +20 -0
- data/lib/farce/internal/external_transaction.rb +59 -0
- data/lib/farce/internal/fake_ractor.rb +179 -0
- data/lib/farce/internal/freeze.rb +118 -0
- data/lib/farce/internal/inspect.rb +157 -0
- data/lib/farce/internal/key_lock_map.rb +29 -0
- data/lib/farce/internal/key_normalizer.rb +289 -0
- data/lib/farce/internal/lease_initialization.rb +115 -0
- data/lib/farce/internal/lease_map.rb +441 -0
- data/lib/farce/internal/lease_pool_state.rb +228 -0
- data/lib/farce/internal/lease_state.rb +342 -0
- data/lib/farce/internal/lease_waiting.rb +13 -0
- data/lib/farce/internal/managed_queue.rb +26 -0
- data/lib/farce/internal/map_value_modes.rb +227 -0
- data/lib/farce/internal/marshal_support.rb +227 -0
- data/lib/farce/internal/mixin.rb +20 -0
- data/lib/farce/internal/mutable_ordered_key_lock_map.rb +63 -0
- data/lib/farce/internal/noncopyable.rb +17 -0
- data/lib/farce/internal/ordered_key_lock_map.rb +69 -0
- data/lib/farce/internal/pool_supervisor.rb +41 -0
- data/lib/farce/internal/pool_worker.rb +61 -0
- data/lib/farce/internal/portable_transaction/reservation_entry.rb +29 -0
- data/lib/farce/internal/portable_transaction/strong_map_entry.rb +137 -0
- data/lib/farce/internal/portable_transaction/strong_map_size_entry.rb +44 -0
- data/lib/farce/internal/portable_transaction/tree_entry.rb +64 -0
- data/lib/farce/internal/portable_transaction.rb +164 -0
- data/lib/farce/internal/proxy_owner_notifications.rb +29 -0
- data/lib/farce/internal/reservation_waiting.rb +24 -0
- data/lib/farce/internal/scheduled_task.rb +48 -0
- data/lib/farce/internal/scheduler_io.rb +171 -0
- data/lib/farce/internal/scheduler_lifecycle.rb +314 -0
- data/lib/farce/internal/select_scheduler.rb +235 -0
- data/lib/farce/internal/storage.rb +162 -0
- data/lib/farce/internal/strict_lease.rb +30 -0
- data/lib/farce/internal/strict_lease_map.rb +20 -0
- data/lib/farce/internal/strict_lease_pool.rb +29 -0
- data/lib/farce/internal/thread_pool.rb +166 -0
- data/lib/farce/internal/transaction_conflict.rb +9 -0
- data/lib/farce/internal/transaction_freeze_guard.rb +30 -0
- data/lib/farce/internal/transaction_map_snapshot.rb +123 -0
- data/lib/farce/internal/undefined.rb +22 -0
- data/lib/farce/internal/unshared_lease.rb +29 -0
- data/lib/farce/internal/unshared_lease_pool.rb +34 -0
- data/lib/farce/internal/unshared_queue_waiting.rb +28 -0
- data/lib/farce/internal/value_serialization.rb +13 -0
- data/lib/farce/internal/weak_map_value_modes.rb +58 -0
- data/lib/farce/internal/weak_mode_manager.rb +26 -0
- data/lib/farce/internal.rb +129 -0
- data/lib/farce/lazy.rb +100 -0
- data/lib/farce/lazy_ref.rb +40 -0
- data/lib/farce/lease.rb +28 -0
- data/lib/farce/lease_map.rb +34 -0
- data/lib/farce/lease_pool.rb +29 -0
- data/lib/farce/lfu_map.rb +53 -0
- data/lib/farce/local/atom.rb +23 -0
- data/lib/farce/local/counter.rb +88 -0
- data/lib/farce/local/flag.rb +65 -0
- data/lib/farce/local/lazy.rb +38 -0
- data/lib/farce/local/lazy_ref.rb +36 -0
- data/lib/farce/local/lease.rb +77 -0
- data/lib/farce/local/lease_map.rb +80 -0
- data/lib/farce/local/lease_pool.rb +38 -0
- data/lib/farce/local/lfu_map.rb +55 -0
- data/lib/farce/local/lru_map.rb +62 -0
- data/lib/farce/local/map.rb +47 -0
- data/lib/farce/local/molecule.rb +45 -0
- data/lib/farce/local/priority_queue.rb +53 -0
- data/lib/farce/local/queue.rb +32 -0
- data/lib/farce/local/scoped.rb +166 -0
- data/lib/farce/local/set.rb +18 -0
- data/lib/farce/local/sorted_set.rb +50 -0
- data/lib/farce/local/timer_queue.rb +41 -0
- data/lib/farce/local/tree_map.rb +47 -0
- data/lib/farce/local/vector.rb +30 -0
- data/lib/farce/local/weak_atom.rb +23 -0
- data/lib/farce/local/weak_key_map.rb +39 -0
- data/lib/farce/local/weak_map.rb +39 -0
- data/lib/farce/local/weak_set.rb +18 -0
- data/lib/farce/local/weak_value_map.rb +39 -0
- data/lib/farce/local.rb +35 -0
- data/lib/farce/lock.rb +54 -0
- data/lib/farce/lru_map.rb +63 -0
- data/lib/farce/map.rb +58 -0
- data/lib/farce/mode_manager.rb +142 -0
- data/lib/farce/molecule.rb +60 -0
- data/lib/farce/mutable.rb +171 -0
- data/lib/farce/pool.rb +332 -0
- data/lib/farce/port.rb +134 -0
- data/lib/farce/priority_queue.rb +70 -0
- data/lib/farce/proxy/register.rb +101 -0
- data/lib/farce/proxy/supervisor.rb +137 -0
- data/lib/farce/proxy/wrapper.rb +49 -0
- data/lib/farce/proxy.rb +291 -0
- data/lib/farce/queue.rb +60 -0
- data/lib/farce/ractor.rb +269 -0
- data/lib/farce/read_write_lock.rb +256 -0
- data/lib/farce/reference.rb +158 -0
- data/lib/farce/resolv/dns.rb +42 -0
- data/lib/farce/resolv.rb +85 -0
- data/lib/farce/scheduler.rb +536 -0
- data/lib/farce/set.rb +39 -0
- data/lib/farce/shareable.rb +150 -0
- data/lib/farce/signal.rb +97 -0
- data/lib/farce/sorted_set.rb +36 -0
- data/lib/farce/strict/atom.rb +34 -0
- data/lib/farce/strict/counter.rb +10 -0
- data/lib/farce/strict/exchanger.rb +25 -0
- data/lib/farce/strict/flag.rb +10 -0
- data/lib/farce/strict/lazy.rb +26 -0
- data/lib/farce/strict/lazy_ref.rb +26 -0
- data/lib/farce/strict/lease.rb +27 -0
- data/lib/farce/strict/lease_map.rb +33 -0
- data/lib/farce/strict/lease_pool.rb +28 -0
- data/lib/farce/strict/lfu_map.rb +27 -0
- data/lib/farce/strict/lru_map.rb +28 -0
- data/lib/farce/strict/map.rb +54 -0
- data/lib/farce/strict/molecule.rb +16 -0
- data/lib/farce/strict/port.rb +40 -0
- data/lib/farce/strict/priority_queue.rb +20 -0
- data/lib/farce/strict/queue.rb +17 -0
- data/lib/farce/strict/set.rb +14 -0
- data/lib/farce/strict/sorted_set.rb +19 -0
- data/lib/farce/strict/timer_queue.rb +13 -0
- data/lib/farce/strict/tree_map.rb +27 -0
- data/lib/farce/strict/vector.rb +24 -0
- data/lib/farce/strict/weak_atom.rb +31 -0
- data/lib/farce/strict/weak_key_map.rb +49 -0
- data/lib/farce/strict/weak_map.rb +49 -0
- data/lib/farce/strict/weak_set.rb +14 -0
- data/lib/farce/strict/weak_value_map.rb +48 -0
- data/lib/farce/strict.rb +28 -0
- data/lib/farce/system.rb +40 -0
- data/lib/farce/thread_scheduler.rb +70 -0
- data/lib/farce/timer_queue.rb +66 -0
- data/lib/farce/transaction/atom.rb +73 -0
- data/lib/farce/transaction/map.rb +25 -0
- data/lib/farce/transaction/map_operations.rb +143 -0
- data/lib/farce/transaction/molecule.rb +90 -0
- data/lib/farce/transaction/mutable.rb +61 -0
- data/lib/farce/transaction/set.rb +17 -0
- data/lib/farce/transaction/set_operations.rb +48 -0
- data/lib/farce/transaction/sorted_set.rb +18 -0
- data/lib/farce/transaction/tree_map.rb +78 -0
- data/lib/farce/transaction/vector.rb +139 -0
- data/lib/farce/transaction/wrapper.rb +202 -0
- data/lib/farce/transaction.rb +343 -0
- data/lib/farce/tree_map.rb +56 -0
- data/lib/farce/unsafe/lfu_map.rb +36 -0
- data/lib/farce/unsafe/lru_map.rb +36 -0
- data/lib/farce/unsafe/tree_map.rb +21 -0
- data/lib/farce/unsafe.rb +29 -0
- data/lib/farce/unshareable.rb +67 -0
- data/lib/farce/unshared/atom.rb +24 -0
- data/lib/farce/unshared/counter.rb +10 -0
- data/lib/farce/unshared/flag.rb +10 -0
- data/lib/farce/unshared/lazy.rb +38 -0
- data/lib/farce/unshared/lazy_ref.rb +26 -0
- data/lib/farce/unshared/lease.rb +27 -0
- data/lib/farce/unshared/lease_map.rb +26 -0
- data/lib/farce/unshared/lease_pool.rb +25 -0
- data/lib/farce/unshared/lfu_map.rb +20 -0
- data/lib/farce/unshared/lru_map.rb +20 -0
- data/lib/farce/unshared/map.rb +49 -0
- data/lib/farce/unshared/molecule.rb +16 -0
- data/lib/farce/unshared/priority_queue.rb +16 -0
- data/lib/farce/unshared/queue.rb +27 -0
- data/lib/farce/unshared/set.rb +14 -0
- data/lib/farce/unshared/sorted_set.rb +28 -0
- data/lib/farce/unshared/timer_queue.rb +16 -0
- data/lib/farce/unshared/tree_map.rb +21 -0
- data/lib/farce/unshared/vector.rb +19 -0
- data/lib/farce/unshared/weak_atom.rb +31 -0
- data/lib/farce/unshared/weak_key_map.rb +44 -0
- data/lib/farce/unshared/weak_map.rb +44 -0
- data/lib/farce/unshared/weak_set.rb +14 -0
- data/lib/farce/unshared/weak_value_map.rb +43 -0
- data/lib/farce/unshared.rb +28 -0
- data/lib/farce/vector.rb +228 -0
- data/lib/farce/version.rb +8 -0
- data/lib/farce/walker/definitions.rb +186 -0
- data/lib/farce/walker/modification.rb +355 -0
- data/lib/farce/walker.rb +319 -0
- data/lib/farce/weak_atom.rb +121 -0
- data/lib/farce/weak_key_map.rb +31 -0
- data/lib/farce/weak_map.rb +33 -0
- data/lib/farce/weak_ref.rb +67 -0
- data/lib/farce/weak_set.rb +82 -0
- data/lib/farce/weak_value.rb +195 -0
- data/lib/farce/weak_value_map.rb +32 -0
- data/lib/farce.rb +519 -0
- metadata +420 -0
|
@@ -0,0 +1,1126 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Abstract
|
|
7
|
+
# @abstract Superclass for concurrent indexed collections.
|
|
8
|
+
# Negative indexes count from the end. Assignments beyond the end fill gaps with nil.
|
|
9
|
+
# Atomic updates reserve the entire vector. Reads through {#[]} do not wait for updates.
|
|
10
|
+
# Timeouts are finite, non-negative seconds. Nil waits indefinitely for access.
|
|
11
|
+
class Vector < Collection
|
|
12
|
+
include Internal::MarshalSupport::Vector
|
|
13
|
+
|
|
14
|
+
# @api private
|
|
15
|
+
def transaction_wrapper(transaction) = Transaction::Vector.new(transaction, self, internal_vector)
|
|
16
|
+
|
|
17
|
+
# Iterate over live entries, up to the length when enumeration starts.
|
|
18
|
+
# Changes can affect entries not yet visited. Indexes beyond the starting length are not visited.
|
|
19
|
+
# Each entry is read separately. The block runs without holding a collection lock.
|
|
20
|
+
# @yield [value] Called for each entry. Returns an Enumerator without a block.
|
|
21
|
+
# @yieldparam value [BasicObject] The current value.
|
|
22
|
+
# @yieldreturn [void] The result is ignored.
|
|
23
|
+
# @return [self, Enumerator]
|
|
24
|
+
def each
|
|
25
|
+
return enum_for(__method__) { size } unless block_given?
|
|
26
|
+
|
|
27
|
+
internal_vector.each { yield logical_value(it) }
|
|
28
|
+
self
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Iterate over indexes up to the length when enumeration starts.
|
|
32
|
+
# @yield [index] Called for each index. Returns an Enumerator without a block.
|
|
33
|
+
# @yieldparam index [Integer] The current index.
|
|
34
|
+
# @yieldreturn [void] The result is ignored.
|
|
35
|
+
# @return [self, Enumerator]
|
|
36
|
+
def each_index(&)
|
|
37
|
+
return enum_for(__method__) { size } unless block_given?
|
|
38
|
+
|
|
39
|
+
size.times(&)
|
|
40
|
+
self
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Iterate over live entries from the last index when enumeration starts.
|
|
44
|
+
# Replacements and removals can affect entries not yet visited. The block runs without a collection lock.
|
|
45
|
+
# @yield [value] Called for each entry. Returns an Enumerator without a block.
|
|
46
|
+
# @yieldparam value [BasicObject] The current value.
|
|
47
|
+
# @yieldreturn [void] The result is ignored.
|
|
48
|
+
# @return [self, Enumerator]
|
|
49
|
+
def reverse_each
|
|
50
|
+
return enum_for(__method__) { size } unless block_given?
|
|
51
|
+
|
|
52
|
+
internal_vector.reverse_each { yield logical_value(it) }
|
|
53
|
+
self
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Return a new Array containing a logical snapshot of the values.
|
|
57
|
+
# @return [Array<BasicObject>] A new Array of logical values.
|
|
58
|
+
def to_a = internal_vector.snapshot.map! { logical_value(it) }
|
|
59
|
+
|
|
60
|
+
# (see #to_a)
|
|
61
|
+
def deconstruct = to_a
|
|
62
|
+
|
|
63
|
+
# Convert pair-like entries to a Hash. Vector entries are accepted as pairs.
|
|
64
|
+
# @yield [value] Optionally transform each entry into a key-value pair.
|
|
65
|
+
# @yieldparam value [BasicObject] The current entry.
|
|
66
|
+
# @yieldreturn [Array, Vector] A two-element key-value pair.
|
|
67
|
+
# @return [Hash] The converted pairs. Without a block, entries must be pair-like.
|
|
68
|
+
def to_h = to_a.to_h { normalize_hash_pair(block_given? ? yield(it) : it) }
|
|
69
|
+
|
|
70
|
+
# Recursively retrieve a nested value.
|
|
71
|
+
# @param index [Integer] The initial index. Negative indexes count from the end.
|
|
72
|
+
# @param identifiers [Array<BasicObject>] Indexes or keys passed to the nested value's `dig` method.
|
|
73
|
+
# @return [BasicObject, nil] The nested value, or nil if an intermediate value is nil.
|
|
74
|
+
def dig(index, *identifiers)
|
|
75
|
+
value = at(index)
|
|
76
|
+
return value if identifiers.empty?
|
|
77
|
+
return if value.nil?
|
|
78
|
+
raise TypeError, "#{value.class} does not have #dig method" unless value.respond_to?(:dig)
|
|
79
|
+
value.dig(*identifiers)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Find the first pair whose first value equals key.
|
|
83
|
+
# @param key [BasicObject] The value to compare with each pair's first entry.
|
|
84
|
+
# @return [Array, Vector, nil] The first matching pair, or nil if none matches.
|
|
85
|
+
def assoc(key) = find_pair(key, 0)
|
|
86
|
+
|
|
87
|
+
# Find the first pair whose second value equals value.
|
|
88
|
+
# @param value [BasicObject] The value to compare with each pair's second entry.
|
|
89
|
+
# @return [Array, Vector, nil] The first matching pair, or nil if none matches.
|
|
90
|
+
def rassoc(value) = find_pair(value, 1)
|
|
91
|
+
|
|
92
|
+
# (see #[])
|
|
93
|
+
def at(index) = self[index]
|
|
94
|
+
|
|
95
|
+
# Fetch a value by index, with Array-compatible fallback behavior.
|
|
96
|
+
# @param index [Integer] The index. Negative indexes count from the end.
|
|
97
|
+
# @param fallback [Array<BasicObject>] At most one default value for a missing index.
|
|
98
|
+
# @yield [index] Called for a missing index. Takes precedence over the default value.
|
|
99
|
+
# @yieldparam index [BasicObject] The original index argument, before integer conversion.
|
|
100
|
+
# @yieldreturn [BasicObject] The fallback value.
|
|
101
|
+
# @return [BasicObject] The entry, default value, or block result.
|
|
102
|
+
# @raise [IndexError] If the index is absent and neither a default nor a block is supplied.
|
|
103
|
+
def fetch(index, *fallback)
|
|
104
|
+
original_index = index
|
|
105
|
+
index = convert_vector_index(index)
|
|
106
|
+
|
|
107
|
+
if fallback.length > 1
|
|
108
|
+
raise ArgumentError, "wrong number of arguments (given #{fallback.length + 1}, expected 1..2)"
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
warn("block supersedes default value argument") if !fallback.empty? && block_given?
|
|
112
|
+
|
|
113
|
+
return logical_value(internal_vector.fetch(index)) if fallback.empty? && !block_given?
|
|
114
|
+
|
|
115
|
+
stored = internal_vector.fetch(index) do
|
|
116
|
+
return yield(original_index) if block_given?
|
|
117
|
+
return fallback.first
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
logical_value(stored)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Fetch several values. Missing indexes are passed to the block.
|
|
124
|
+
# @param indexes [Array<Integer>] The indexes to fetch.
|
|
125
|
+
# @yield [index] Called for each missing index when a block is supplied.
|
|
126
|
+
# @yieldparam index [BasicObject] The original missing index argument.
|
|
127
|
+
# @yieldreturn [BasicObject] The fallback value.
|
|
128
|
+
# @return [Vector] The requested entries and fallback values.
|
|
129
|
+
# @raise [IndexError] If an index is absent and no block is supplied.
|
|
130
|
+
def fetch_values(*indexes)
|
|
131
|
+
values = if block_given?
|
|
132
|
+
indexes.map { |index| internal_vector.fetch(index) { derived_storage(yield(index)) } }
|
|
133
|
+
else
|
|
134
|
+
indexes.map { internal_vector.fetch(it) }
|
|
135
|
+
end
|
|
136
|
+
build_derived_vector(values)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Select values at indexes and ranges.
|
|
140
|
+
# @overload values_at(*indexes)
|
|
141
|
+
# @param indexes [Array<Integer, Range>] The indexes and ranges to select.
|
|
142
|
+
# @return [Vector] The selected entries, with nil for missing positions.
|
|
143
|
+
def values_at(...) = build_derived_vector(internal_vector.snapshot.values_at(...))
|
|
144
|
+
|
|
145
|
+
# Return one value, or a Vector when a count is supplied.
|
|
146
|
+
# @param count [Integer] The maximum number of entries. Omit to return one entry.
|
|
147
|
+
# @return [BasicObject, Vector, nil] The first entry, nil if empty, or a Vector when count is supplied.
|
|
148
|
+
def first(count = UNDEFINED)
|
|
149
|
+
return self[0] if count.equal?(UNDEFINED)
|
|
150
|
+
|
|
151
|
+
snapshot = internal_vector.snapshot
|
|
152
|
+
build_derived_vector(snapshot.first(count))
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Return one value, or a Vector when a count is supplied.
|
|
156
|
+
# @param count [Integer] The maximum number of entries. Omit to return one entry.
|
|
157
|
+
# @return [BasicObject, Vector, nil] The last entry, nil if empty, or a Vector when count is supplied.
|
|
158
|
+
def last(count = UNDEFINED)
|
|
159
|
+
return self[-1] if count.equal?(UNDEFINED)
|
|
160
|
+
|
|
161
|
+
snapshot = internal_vector.snapshot
|
|
162
|
+
build_derived_vector(snapshot.last(count))
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Return an element or subsequence without changing the hot path for {#[]}.
|
|
166
|
+
# Range and start-length results are Vectors.
|
|
167
|
+
# @param index [Integer, Range] An index, range, or start index when length is supplied.
|
|
168
|
+
# @param length [Integer] The maximum length of a subsequence. Omit for a single index or range.
|
|
169
|
+
# @return [BasicObject, Vector, nil] A single entry, a Vector subsequence, or nil for an invalid slice.
|
|
170
|
+
def slice(index, length = UNDEFINED)
|
|
171
|
+
snapshot = internal_vector.snapshot
|
|
172
|
+
|
|
173
|
+
if length.equal?(UNDEFINED)
|
|
174
|
+
result = snapshot.slice(index)
|
|
175
|
+
return logical_value(result) unless index.is_a?(Range)
|
|
176
|
+
else
|
|
177
|
+
result = snapshot.slice(index, length)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
result && build_derived_vector(result)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Return whether a live entry equals value.
|
|
184
|
+
# @param value [BasicObject] The value to find using `==`.
|
|
185
|
+
# @return [Boolean] Whether a matching entry exists.
|
|
186
|
+
def include?(value)
|
|
187
|
+
each { return true if array_value_equal?(it, value) }
|
|
188
|
+
false
|
|
189
|
+
end
|
|
190
|
+
alias member? include?
|
|
191
|
+
|
|
192
|
+
# Return the first matching index.
|
|
193
|
+
# @param value [BasicObject] The value to find. Omit to use the block.
|
|
194
|
+
# @yield [entry] Test each entry when value is omitted.
|
|
195
|
+
# @yieldparam entry [BasicObject] The current entry.
|
|
196
|
+
# @yieldreturn [BasicObject] A truthy value for a match.
|
|
197
|
+
# @return [Integer, nil, Enumerator] The matching index, nil if absent, or an Enumerator without a value or block.
|
|
198
|
+
def index(value = UNDEFINED)
|
|
199
|
+
return enum_for(__method__) { size } if value.equal?(UNDEFINED) && !block_given? # rubocop:disable Lint/ToEnumArguments
|
|
200
|
+
|
|
201
|
+
warn("given block not used") if !value.equal?(UNDEFINED) && block_given?
|
|
202
|
+
each_with_index do |entry, index|
|
|
203
|
+
return index if value.equal?(UNDEFINED) ? yield(entry) : array_value_equal?(entry, value)
|
|
204
|
+
end
|
|
205
|
+
nil
|
|
206
|
+
end
|
|
207
|
+
alias find_index index
|
|
208
|
+
|
|
209
|
+
# Return the last matching index.
|
|
210
|
+
# @param value [BasicObject] The value to find. Omit to use the block.
|
|
211
|
+
# @yield [entry] Test each entry when value is omitted.
|
|
212
|
+
# @yieldparam entry [BasicObject] The current entry.
|
|
213
|
+
# @yieldreturn [BasicObject] A truthy value for a match.
|
|
214
|
+
# @return [Integer, nil, Enumerator] The matching index, nil if absent, or an Enumerator without a value or block.
|
|
215
|
+
def rindex(value = UNDEFINED)
|
|
216
|
+
return enum_for(__method__) { size } if value.equal?(UNDEFINED) && !block_given? # rubocop:disable Lint/ToEnumArguments
|
|
217
|
+
|
|
218
|
+
warn("given block not used") if !value.equal?(UNDEFINED) && block_given?
|
|
219
|
+
backend = internal_vector
|
|
220
|
+
index = backend.size
|
|
221
|
+
while index.positive?
|
|
222
|
+
index -= 1
|
|
223
|
+
found = true
|
|
224
|
+
stored = backend.fetch(index) { found = false }
|
|
225
|
+
next unless found
|
|
226
|
+
entry = logical_value(stored)
|
|
227
|
+
return index if value.equal?(UNDEFINED) ? yield(entry) : array_value_equal?(entry, value)
|
|
228
|
+
end
|
|
229
|
+
nil
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# Find a value by searching from the end.
|
|
233
|
+
# @param if_none [#call, nil] Called without arguments if no entry matches.
|
|
234
|
+
# @yield [value] Test entries from last to first.
|
|
235
|
+
# @yieldparam value [BasicObject] The current entry.
|
|
236
|
+
# @yieldreturn [BasicObject] A truthy value for a match.
|
|
237
|
+
# @return [BasicObject, nil, Enumerator] The matching entry, the fallback result, or an Enumerator without a
|
|
238
|
+
# block.
|
|
239
|
+
def rfind(if_none = nil)
|
|
240
|
+
return enum_for(__method__, if_none) { size } unless block_given?
|
|
241
|
+
|
|
242
|
+
reverse_each { return it if yield(it) }
|
|
243
|
+
if_none&.call
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
# Transform a snapshot into a Vector.
|
|
247
|
+
# @yield [value] Transform each entry. Returns an Enumerator without a block.
|
|
248
|
+
# @yieldparam value [BasicObject] The current value.
|
|
249
|
+
# @yieldreturn [BasicObject] The replacement value.
|
|
250
|
+
# @return [Vector, Enumerator]
|
|
251
|
+
def map
|
|
252
|
+
return enum_for(__method__) { size } unless block_given?
|
|
253
|
+
|
|
254
|
+
snapshot = internal_vector.snapshot
|
|
255
|
+
logical = []
|
|
256
|
+
mapped = snapshot.map do |stored|
|
|
257
|
+
value = logical_value(stored)
|
|
258
|
+
logical << value
|
|
259
|
+
yield value
|
|
260
|
+
end
|
|
261
|
+
build_derived_from_logical(mapped, snapshot, logical)
|
|
262
|
+
end
|
|
263
|
+
alias collect map
|
|
264
|
+
|
|
265
|
+
# Keep values accepted by a block.
|
|
266
|
+
# @yield [value] Test each entry. Returns an Enumerator without a block.
|
|
267
|
+
# @yieldparam value [BasicObject] The current value.
|
|
268
|
+
# @yieldreturn [BasicObject] A truthy value to retain the entry.
|
|
269
|
+
# @return [Vector, Enumerator]
|
|
270
|
+
def select
|
|
271
|
+
return enum_for(__method__) { size } unless block_given?
|
|
272
|
+
|
|
273
|
+
build_derived_vector(internal_vector.each.select { yield logical_value(it) })
|
|
274
|
+
end
|
|
275
|
+
alias filter select
|
|
276
|
+
alias find_all select
|
|
277
|
+
|
|
278
|
+
# Remove values accepted by a block.
|
|
279
|
+
# @yield [value] Test each entry. Returns an Enumerator without a block.
|
|
280
|
+
# @yieldparam value [BasicObject] The current value.
|
|
281
|
+
# @yieldreturn [BasicObject] A truthy value to exclude the entry.
|
|
282
|
+
# @return [Vector, Enumerator]
|
|
283
|
+
def reject
|
|
284
|
+
return enum_for(__method__) { size } unless block_given?
|
|
285
|
+
|
|
286
|
+
build_derived_vector(internal_vector.each.reject { yield logical_value(it) })
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
# Transform accepted values into a Vector.
|
|
290
|
+
# @yield [value] Transform each entry. Returns an Enumerator without a block.
|
|
291
|
+
# @yieldparam value [BasicObject] The current value.
|
|
292
|
+
# @yieldreturn [BasicObject] The replacement value. Nil and false results are omitted.
|
|
293
|
+
# @return [Vector, Enumerator]
|
|
294
|
+
def filter_map
|
|
295
|
+
return enum_for(__method__) { size } unless block_given?
|
|
296
|
+
|
|
297
|
+
snapshot = internal_vector.snapshot
|
|
298
|
+
logical = []
|
|
299
|
+
values = []
|
|
300
|
+
|
|
301
|
+
snapshot.each do |stored|
|
|
302
|
+
value = logical_value(stored)
|
|
303
|
+
logical << value
|
|
304
|
+
mapped = yield(value)
|
|
305
|
+
values << mapped if mapped
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
build_derived_from_logical(values, snapshot, logical)
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
# Transform and flatten one Array or Vector level.
|
|
312
|
+
# @yield [value] Transform each entry. Returns an Enumerator without a block.
|
|
313
|
+
# @yieldparam value [BasicObject] The current value.
|
|
314
|
+
# @yieldreturn [BasicObject] An Array or Vector to expand by one level, or a single value to retain.
|
|
315
|
+
# @return [Vector, Enumerator]
|
|
316
|
+
def flat_map
|
|
317
|
+
return enum_for(__method__) { size } unless block_given?
|
|
318
|
+
|
|
319
|
+
snapshot = internal_vector.snapshot
|
|
320
|
+
logical = []
|
|
321
|
+
values = []
|
|
322
|
+
snapshot.each do |stored|
|
|
323
|
+
value = logical_value(stored)
|
|
324
|
+
logical << value
|
|
325
|
+
mapped = yield(value)
|
|
326
|
+
converted = mapped.is_a?(Vector) ? mapped.to_a : Array.try_convert(mapped)
|
|
327
|
+
values.concat(converted || [mapped])
|
|
328
|
+
end
|
|
329
|
+
build_derived_from_logical(values, snapshot, logical)
|
|
330
|
+
end
|
|
331
|
+
alias collect_concat flat_map
|
|
332
|
+
|
|
333
|
+
# Remove nil values.
|
|
334
|
+
# @return [Vector] A new same-kind Vector containing the result.
|
|
335
|
+
def compact = build_derived_vector(internal_vector.each.compact)
|
|
336
|
+
|
|
337
|
+
# Remove duplicate values, retaining the first stored entry.
|
|
338
|
+
# @yield [value] Optionally compute a comparison key for each entry.
|
|
339
|
+
# @yieldparam value [BasicObject] The current value.
|
|
340
|
+
# @yieldreturn [BasicObject] The key compared using `hash` and `eql?`. Without a block, entries are compared
|
|
341
|
+
# directly.
|
|
342
|
+
# @return [Vector]
|
|
343
|
+
def uniq
|
|
344
|
+
snapshot = internal_vector.snapshot
|
|
345
|
+
selected = if block_given?
|
|
346
|
+
snapshot.uniq { yield logical_value(it) }
|
|
347
|
+
else
|
|
348
|
+
snapshot.uniq { logical_value(it) }
|
|
349
|
+
end
|
|
350
|
+
build_derived_vector(selected)
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
# Return a reversed snapshot.
|
|
354
|
+
# @return [Vector] A new same-kind Vector containing the result.
|
|
355
|
+
def reverse = build_derived_vector(internal_vector.snapshot.reverse)
|
|
356
|
+
|
|
357
|
+
# Return a rotated snapshot.
|
|
358
|
+
# @param count [Integer] The rotation distance. Negative values rotate right.
|
|
359
|
+
# @return [Vector] The rotated entries.
|
|
360
|
+
def rotate(count = 1) = build_derived_vector(internal_vector.snapshot.rotate(count))
|
|
361
|
+
|
|
362
|
+
# Return a sorted snapshot.
|
|
363
|
+
# @yield [left, right] Optionally compare two entries. Without a block, uses `<=>`.
|
|
364
|
+
# @yieldparam left [BasicObject] The left entry.
|
|
365
|
+
# @yieldparam right [BasicObject] The right entry.
|
|
366
|
+
# @yieldreturn [Numeric] A negative number, zero, or a positive number for less than, equal to, or greater than.
|
|
367
|
+
# @return [Vector] The sorted entries.
|
|
368
|
+
def sort(&block)
|
|
369
|
+
snapshot = internal_vector.snapshot
|
|
370
|
+
logical = snapshot.map { logical_value(it) }
|
|
371
|
+
sorted = block ? logical.sort(&block) : logical.sort
|
|
372
|
+
build_derived_from_logical(sorted, snapshot, logical)
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
# Sort a snapshot by block results.
|
|
376
|
+
# @yield [value] Compute a sort key. Returns an Enumerator without a block.
|
|
377
|
+
# @yieldparam value [BasicObject] The current value.
|
|
378
|
+
# @yieldreturn [BasicObject] The key used to order the entry.
|
|
379
|
+
# @return [Vector, Enumerator]
|
|
380
|
+
def sort_by
|
|
381
|
+
return enum_for(__method__) { size } unless block_given?
|
|
382
|
+
|
|
383
|
+
snapshot = internal_vector.snapshot
|
|
384
|
+
logical = snapshot.map { logical_value(it) }
|
|
385
|
+
build_derived_from_logical(logical.sort_by { yield it }, snapshot, logical)
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
# Return the first count entries.
|
|
389
|
+
# @param count [Integer] The non-negative number of entries to take.
|
|
390
|
+
# @return [Vector] The resulting entries.
|
|
391
|
+
def take(count) = build_derived_vector(internal_vector.each.take(count))
|
|
392
|
+
|
|
393
|
+
# Return all entries after count entries.
|
|
394
|
+
# @param count [Integer] The non-negative number of entries to drop.
|
|
395
|
+
# @return [Vector] The resulting entries.
|
|
396
|
+
def drop(count) = build_derived_vector(internal_vector.each.drop(count))
|
|
397
|
+
|
|
398
|
+
# Return entries before the first rejected value.
|
|
399
|
+
# @yield [value] Test each entry. Returns an Enumerator without a block.
|
|
400
|
+
# @yieldparam value [BasicObject] The current value.
|
|
401
|
+
# @yieldreturn [BasicObject] A truthy value to continue retaining entries.
|
|
402
|
+
# @return [Vector, Enumerator]
|
|
403
|
+
def take_while
|
|
404
|
+
return enum_for(__method__) { size } unless block_given?
|
|
405
|
+
build_derived_vector(internal_vector.each.take_while { yield logical_value(it) })
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
# Drop entries before the first rejected value.
|
|
409
|
+
# @yield [value] Test each entry. Returns an Enumerator without a block.
|
|
410
|
+
# @yieldparam value [BasicObject] The current value.
|
|
411
|
+
# @yieldreturn [BasicObject] A truthy value to continue dropping entries.
|
|
412
|
+
# @return [Vector, Enumerator]
|
|
413
|
+
def drop_while
|
|
414
|
+
return enum_for(__method__) { size } unless block_given?
|
|
415
|
+
build_derived_vector(internal_vector.each.drop_while { yield logical_value(it) })
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
# Return a shuffled snapshot.
|
|
419
|
+
# @param random [#rand] The random number generator.
|
|
420
|
+
# @return [Vector] The shuffled entries.
|
|
421
|
+
def shuffle(random: Random) = build_derived_vector(internal_vector.snapshot.shuffle(random:))
|
|
422
|
+
|
|
423
|
+
# Return one sample, or a Vector when count is supplied.
|
|
424
|
+
# @param count [Integer] The maximum sample size. Omit to return one entry.
|
|
425
|
+
# @param random [#rand] The random number generator.
|
|
426
|
+
# @return [BasicObject, Vector, nil] One entry, nil if empty, or a Vector when count is supplied.
|
|
427
|
+
def sample(count = UNDEFINED, random: Random)
|
|
428
|
+
snapshot = internal_vector.snapshot
|
|
429
|
+
return logical_value(snapshot.sample(random:)) if count.equal?(UNDEFINED)
|
|
430
|
+
build_derived_vector(snapshot.sample(count, random:))
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
# Concatenate a snapshot with another sequence.
|
|
434
|
+
# @param other [Vector, #to_ary] The other sequence.
|
|
435
|
+
# @return [Vector] The resulting entries.
|
|
436
|
+
def +(other)
|
|
437
|
+
snapshot = internal_vector.snapshot
|
|
438
|
+
appended = if other.equal?(self)
|
|
439
|
+
snapshot
|
|
440
|
+
else
|
|
441
|
+
reusable_operand_snapshot(other) || vector_operand(other).map { derived_storage(it) }
|
|
442
|
+
end
|
|
443
|
+
build_derived_vector(snapshot + appended)
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
# Repeat a snapshot, or join it when a String separator is supplied.
|
|
447
|
+
# @param other [Integer, #to_str] The non-negative repetition count or String separator.
|
|
448
|
+
# @return [Vector, String] The repeated entries, or the joined String for a separator.
|
|
449
|
+
def *(other)
|
|
450
|
+
separator = String.try_convert(other)
|
|
451
|
+
return join(separator) if separator
|
|
452
|
+
build_derived_vector(internal_vector.snapshot * other)
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
# Remove values present in another sequence.
|
|
456
|
+
# @param other [Vector, #to_ary] The other sequence.
|
|
457
|
+
# @return [Vector] The resulting entries.
|
|
458
|
+
def -(other) = derive_array_operation(:-, other)
|
|
459
|
+
|
|
460
|
+
# Intersect with another sequence.
|
|
461
|
+
# @param other [Vector, #to_ary] The other sequence.
|
|
462
|
+
# @return [Vector] The resulting entries.
|
|
463
|
+
def &(other) = derive_array_operation(:&, other)
|
|
464
|
+
|
|
465
|
+
# Union with another sequence.
|
|
466
|
+
# @param other [Vector, #to_ary] The other sequence.
|
|
467
|
+
# @return [Vector] The resulting entries.
|
|
468
|
+
def |(other) = derive_array_operation(:|, other)
|
|
469
|
+
|
|
470
|
+
# Remove values present in any supplied sequence.
|
|
471
|
+
# @param others [Array<Vector, #to_ary>] The other sequences.
|
|
472
|
+
# @return [Vector] The resulting entries.
|
|
473
|
+
def difference(*others) = derive_array_operation(:difference, *others)
|
|
474
|
+
|
|
475
|
+
# Intersect with every supplied sequence.
|
|
476
|
+
# @param others [Array<Vector, #to_ary>] The other sequences.
|
|
477
|
+
# @return [Vector] The resulting entries.
|
|
478
|
+
def intersection(*others) = derive_array_operation(:intersection, *others)
|
|
479
|
+
|
|
480
|
+
# Union with every supplied sequence.
|
|
481
|
+
# @param others [Array<Vector, #to_ary>] The other sequences.
|
|
482
|
+
# @return [Vector] The resulting entries.
|
|
483
|
+
def union(*others) = derive_array_operation(:union, *others)
|
|
484
|
+
|
|
485
|
+
# Return whether another sequence shares any value.
|
|
486
|
+
# @param other [Vector, #to_ary] The other sequence.
|
|
487
|
+
# @return [Boolean] Whether the sequences have an entry in common.
|
|
488
|
+
def intersect?(other) = to_a.intersect?(vector_operand(other))
|
|
489
|
+
|
|
490
|
+
# Binary-search the live entries and return the matching value.
|
|
491
|
+
# The entries must remain sorted. Concurrent writes can change the result.
|
|
492
|
+
# @yield [value] Test an entry in an already sorted vector. Returns an Enumerator without a block.
|
|
493
|
+
# @yieldparam value [BasicObject] The entry being tested.
|
|
494
|
+
# @yieldreturn [Boolean, Numeric, nil] A monotonic predicate or comparison result, following Array's binary-search
|
|
495
|
+
# contract.
|
|
496
|
+
# @return [BasicObject, nil, Enumerator] The matching entry, nil if absent, or an Enumerator.
|
|
497
|
+
def bsearch
|
|
498
|
+
return enum_for(__method__) { size } unless block_given?
|
|
499
|
+
|
|
500
|
+
candidate = nil
|
|
501
|
+
index = (0...size).bsearch do |position|
|
|
502
|
+
value = self[position]
|
|
503
|
+
result = yield(value)
|
|
504
|
+
candidate = value if result.equal?(true) || (result.is_a?(Numeric) && result.zero?)
|
|
505
|
+
result
|
|
506
|
+
end
|
|
507
|
+
candidate if index
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
# Binary-search the live entries and return the matching index.
|
|
511
|
+
# The entries must remain sorted. Concurrent writes can change the result.
|
|
512
|
+
# @yield [value] Test an entry in an already sorted vector. Returns an Enumerator without a block.
|
|
513
|
+
# @yieldparam value [BasicObject] The entry being tested.
|
|
514
|
+
# @yieldreturn [Boolean, Numeric, nil] A monotonic predicate or comparison result, following Array's binary-search
|
|
515
|
+
# contract.
|
|
516
|
+
# @return [Integer, nil, Enumerator] The matching index, nil if absent, or an Enumerator.
|
|
517
|
+
def bsearch_index
|
|
518
|
+
return enum_for(__method__) { size } unless block_given?
|
|
519
|
+
|
|
520
|
+
(0...size).bsearch { yield self[it] }
|
|
521
|
+
end
|
|
522
|
+
|
|
523
|
+
# Pack a logical snapshot according to format.
|
|
524
|
+
# @overload pack(format, buffer: nil)
|
|
525
|
+
# @param format [String] The Array packing directives.
|
|
526
|
+
# @param buffer [String, nil] An optional String to append the packed bytes to.
|
|
527
|
+
# @return [String] The packed bytes, using buffer when supplied.
|
|
528
|
+
def pack(format, **) = to_a.pack(format, **)
|
|
529
|
+
|
|
530
|
+
# Select values matched by pattern, optionally transforming them.
|
|
531
|
+
# @param pattern [#===] The pattern used to test each entry.
|
|
532
|
+
# @yield [value] Optionally transform each selected entry.
|
|
533
|
+
# @yieldparam value [BasicObject] The selected entry.
|
|
534
|
+
# @yieldreturn [BasicObject] The replacement value.
|
|
535
|
+
# @return [Vector] The selected entries or their block results.
|
|
536
|
+
def grep(pattern, &)
|
|
537
|
+
snapshot = internal_vector.snapshot
|
|
538
|
+
logical = snapshot.map { logical_value(it) }
|
|
539
|
+
result = block_given? ? logical.grep(pattern, &) : logical.grep(pattern)
|
|
540
|
+
build_derived_from_logical(result, snapshot, logical)
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
# Select values not matched by pattern, optionally transforming them.
|
|
544
|
+
# @param pattern [#===] The pattern used to test each entry.
|
|
545
|
+
# @yield [value] Optionally transform each selected entry.
|
|
546
|
+
# @yieldparam value [BasicObject] The selected entry.
|
|
547
|
+
# @yieldreturn [BasicObject] The replacement value.
|
|
548
|
+
# @return [Vector] The selected entries or their block results.
|
|
549
|
+
def grep_v(pattern, &)
|
|
550
|
+
snapshot = internal_vector.snapshot
|
|
551
|
+
logical = snapshot.map { logical_value(it) }
|
|
552
|
+
result = block_given? ? logical.grep_v(pattern, &) : logical.grep_v(pattern)
|
|
553
|
+
build_derived_from_logical(result, snapshot, logical)
|
|
554
|
+
end
|
|
555
|
+
|
|
556
|
+
# Split live entries into accepted and rejected Vectors, wrapped in a Vector.
|
|
557
|
+
# @yield [value] Classify each entry. Returns an Enumerator without a block.
|
|
558
|
+
# @yieldparam value [BasicObject] The current value.
|
|
559
|
+
# @yieldreturn [BasicObject] A truthy value for the accepted group, or a falsy value for the rejected group.
|
|
560
|
+
# @return [Vector, Enumerator] A Vector containing the accepted and rejected Vectors, or an Enumerator.
|
|
561
|
+
def partition
|
|
562
|
+
return enum_for(__method__) { size } unless block_given?
|
|
563
|
+
|
|
564
|
+
accepted, rejected = internal_vector.each.partition { yield logical_value(it) }
|
|
565
|
+
build_derived_values([build_derived_vector(accepted), build_derived_vector(rejected)])
|
|
566
|
+
end
|
|
567
|
+
|
|
568
|
+
# Group live entries into same-kind Vectors.
|
|
569
|
+
# @yield [value] Compute a grouping key. Returns an Enumerator without a block.
|
|
570
|
+
# @yieldparam value [BasicObject] The current value.
|
|
571
|
+
# @yieldreturn [BasicObject] The key for the entry's group.
|
|
572
|
+
# @return [Hash{BasicObject => Vector}, Enumerator] Keys mapped to same-kind Vector groups, or an Enumerator.
|
|
573
|
+
def group_by
|
|
574
|
+
return enum_for(__method__) { size } unless block_given?
|
|
575
|
+
|
|
576
|
+
internal_vector.each.group_by { yield logical_value(it) }
|
|
577
|
+
.transform_values { build_derived_vector(it) }
|
|
578
|
+
end
|
|
579
|
+
|
|
580
|
+
# Return minimum and maximum in a Vector.
|
|
581
|
+
# @yield [left, right] Optionally compare two entries. Without a block, uses `<=>`.
|
|
582
|
+
# @yieldparam left [BasicObject] The left entry.
|
|
583
|
+
# @yieldparam right [BasicObject] The right entry.
|
|
584
|
+
# @yieldreturn [Numeric] A negative number, zero, or a positive number for less than, equal to, or greater than.
|
|
585
|
+
# @return [Vector] The minimum and maximum, with two nil entries for an empty vector.
|
|
586
|
+
def minmax(&)
|
|
587
|
+
snapshot = internal_vector.snapshot
|
|
588
|
+
logical = snapshot.map { logical_value(it) }
|
|
589
|
+
build_derived_from_logical(logical.minmax(&), snapshot, logical)
|
|
590
|
+
end
|
|
591
|
+
|
|
592
|
+
# Return one minimum, or a Vector when count is supplied.
|
|
593
|
+
# @param count [Integer, nil] The maximum result size. Omit or pass nil to return one entry.
|
|
594
|
+
# @yield [left, right] Optionally compare two entries. Without a block, uses `<=>`.
|
|
595
|
+
# @yieldparam left [BasicObject] The left entry.
|
|
596
|
+
# @yieldparam right [BasicObject] The right entry.
|
|
597
|
+
# @yieldreturn [Numeric] A negative number, zero, or a positive number for less than, equal to, or greater than.
|
|
598
|
+
# @return [BasicObject, Vector, nil] One extreme entry, nil if empty, or a Vector when count is supplied.
|
|
599
|
+
def min(count = UNDEFINED, &)
|
|
600
|
+
count = normalized_extreme_count(count)
|
|
601
|
+
return super(&) if count.nil?
|
|
602
|
+
return build_derived_vector([]) if count.zero?
|
|
603
|
+
|
|
604
|
+
snapshot = internal_vector.snapshot
|
|
605
|
+
logical = snapshot.map { logical_value(it) }
|
|
606
|
+
build_derived_from_logical(logical.min(count, &), snapshot, logical)
|
|
607
|
+
end
|
|
608
|
+
|
|
609
|
+
# Return one maximum, or a Vector when count is supplied.
|
|
610
|
+
# @param count [Integer, nil] The maximum result size. Omit or pass nil to return one entry.
|
|
611
|
+
# @yield [left, right] Optionally compare two entries. Without a block, uses `<=>`.
|
|
612
|
+
# @yieldparam left [BasicObject] The left entry.
|
|
613
|
+
# @yieldparam right [BasicObject] The right entry.
|
|
614
|
+
# @yieldreturn [Numeric] A negative number, zero, or a positive number for less than, equal to, or greater than.
|
|
615
|
+
# @return [BasicObject, Vector, nil] One extreme entry, nil if empty, or a Vector when count is supplied.
|
|
616
|
+
def max(count = UNDEFINED, &)
|
|
617
|
+
count = normalized_extreme_count(count)
|
|
618
|
+
return super(&) if count.nil?
|
|
619
|
+
return build_derived_vector([]) if count.zero?
|
|
620
|
+
|
|
621
|
+
snapshot = internal_vector.snapshot
|
|
622
|
+
logical = snapshot.map { logical_value(it) }
|
|
623
|
+
build_derived_from_logical(logical.max(count, &), snapshot, logical)
|
|
624
|
+
end
|
|
625
|
+
|
|
626
|
+
# Return one block minimum, or a Vector when count is supplied.
|
|
627
|
+
# @param count [Integer, nil] The maximum result size. Omit or pass nil to return one entry.
|
|
628
|
+
# @yield [value] Compute a comparison key. Returns an Enumerator without a block.
|
|
629
|
+
# @yieldparam value [BasicObject] The current value.
|
|
630
|
+
# @yieldreturn [BasicObject] The key used to order the entry.
|
|
631
|
+
# @return [BasicObject, Vector, nil, Enumerator] One extreme entry, nil if empty, a Vector for count, or an
|
|
632
|
+
# Enumerator.
|
|
633
|
+
def min_by(count = UNDEFINED)
|
|
634
|
+
count = normalized_extreme_count(count)
|
|
635
|
+
unless block_given?
|
|
636
|
+
return enum_for(__method__) { size } if count.nil? # rubocop:disable Lint/ToEnumArguments
|
|
637
|
+
return enum_for(__method__, count) { size }
|
|
638
|
+
end
|
|
639
|
+
return super() { yield it } if count.nil?
|
|
640
|
+
return build_derived_vector([]) if count.zero?
|
|
641
|
+
|
|
642
|
+
snapshot = internal_vector.snapshot
|
|
643
|
+
logical = snapshot.map { logical_value(it) }
|
|
644
|
+
build_derived_from_logical(logical.min_by(count) { yield it }, snapshot, logical)
|
|
645
|
+
end
|
|
646
|
+
|
|
647
|
+
# Return one block maximum, or a Vector when count is supplied.
|
|
648
|
+
# @param count [Integer, nil] The maximum result size. Omit or pass nil to return one entry.
|
|
649
|
+
# @yield [value] Compute a comparison key. Returns an Enumerator without a block.
|
|
650
|
+
# @yieldparam value [BasicObject] The current value.
|
|
651
|
+
# @yieldreturn [BasicObject] The key used to order the entry.
|
|
652
|
+
# @return [BasicObject, Vector, nil, Enumerator] One extreme entry, nil if empty, a Vector for count, or an
|
|
653
|
+
# Enumerator.
|
|
654
|
+
def max_by(count = UNDEFINED)
|
|
655
|
+
count = normalized_extreme_count(count)
|
|
656
|
+
unless block_given?
|
|
657
|
+
return enum_for(__method__) { size } if count.nil? # rubocop:disable Lint/ToEnumArguments
|
|
658
|
+
return enum_for(__method__, count) { size }
|
|
659
|
+
end
|
|
660
|
+
return super() { yield it } if count.nil?
|
|
661
|
+
return build_derived_vector([]) if count.zero?
|
|
662
|
+
|
|
663
|
+
snapshot = internal_vector.snapshot
|
|
664
|
+
logical = snapshot.map { logical_value(it) }
|
|
665
|
+
build_derived_from_logical(logical.max_by(count) { yield it }, snapshot, logical)
|
|
666
|
+
end
|
|
667
|
+
|
|
668
|
+
# Return the block minimum and maximum in a Vector.
|
|
669
|
+
# @yield [value] Compute a comparison key. Returns an Enumerator without a block.
|
|
670
|
+
# @yieldparam value [BasicObject] The current value.
|
|
671
|
+
# @yieldreturn [BasicObject] The key used to order the entry.
|
|
672
|
+
# @return [Vector, Enumerator] The minimum and maximum entries, two nil entries if empty, or an Enumerator.
|
|
673
|
+
def minmax_by
|
|
674
|
+
return enum_for(__method__) { size } unless block_given?
|
|
675
|
+
|
|
676
|
+
snapshot = internal_vector.snapshot
|
|
677
|
+
logical = snapshot.map { logical_value(it) }
|
|
678
|
+
build_derived_from_logical(logical.minmax_by { yield it }, snapshot, logical)
|
|
679
|
+
end
|
|
680
|
+
|
|
681
|
+
# Yield same-kind windows from live iteration.
|
|
682
|
+
# @param count [Integer] The positive window size.
|
|
683
|
+
# @yield [window] Visit each window. Returns an Enumerator without a block.
|
|
684
|
+
# @yieldparam window [Vector] The current window.
|
|
685
|
+
# @yieldreturn [void] The result is ignored.
|
|
686
|
+
# @return [self, Enumerator]
|
|
687
|
+
def each_slice(count)
|
|
688
|
+
count = convert_vector_count(count)
|
|
689
|
+
raise ArgumentError, "invalid slice size" unless count.positive?
|
|
690
|
+
return enum_for(__method__, count) { (size + count - 1) / count } unless block_given?
|
|
691
|
+
|
|
692
|
+
internal_vector.each.each_slice(count) { yield build_derived_vector(it) }
|
|
693
|
+
self
|
|
694
|
+
end
|
|
695
|
+
|
|
696
|
+
# Yield same-kind overlapping windows from live iteration.
|
|
697
|
+
# @param count [Integer] The positive window size.
|
|
698
|
+
# @yield [window] Visit each window. Returns an Enumerator without a block.
|
|
699
|
+
# @yieldparam window [Vector] The current window.
|
|
700
|
+
# @yieldreturn [void] The result is ignored.
|
|
701
|
+
# @return [self, Enumerator]
|
|
702
|
+
def each_cons(count)
|
|
703
|
+
count = convert_vector_count(count)
|
|
704
|
+
raise ArgumentError, "invalid size" unless count.positive?
|
|
705
|
+
return enum_for(__method__, count) { [size - count + 1, 0].max } unless block_given?
|
|
706
|
+
|
|
707
|
+
internal_vector.each.each_cons(count) { yield build_derived_vector(it) }
|
|
708
|
+
self
|
|
709
|
+
end
|
|
710
|
+
|
|
711
|
+
# Group adjacent entries by a block-generated key. Group contents are Vectors.
|
|
712
|
+
# @yield [value] Compute a grouping key for each entry.
|
|
713
|
+
# @yieldparam value [BasicObject] The current value.
|
|
714
|
+
# @yieldreturn [BasicObject] The grouping key. Nil and `:_separator` omit the entry. `:_alone` isolates it.
|
|
715
|
+
# @return [Enumerator] Yields keys and Vector groups. Without a block, enumerates the grouping operation.
|
|
716
|
+
def chunk(&block)
|
|
717
|
+
return enum_for(__method__) { size } unless block
|
|
718
|
+
|
|
719
|
+
Enumerator.new do |yielder|
|
|
720
|
+
snapshot = internal_vector.snapshot
|
|
721
|
+
snapshot.chunk { block.call(logical_value(it)) }.each do |key, group|
|
|
722
|
+
yielder.yield(key, build_derived_vector(group))
|
|
723
|
+
end
|
|
724
|
+
end
|
|
725
|
+
end
|
|
726
|
+
|
|
727
|
+
# Group adjacent entries while the block accepts each pair.
|
|
728
|
+
# @yield [left, right] Test consecutive entries. A block is required.
|
|
729
|
+
# @yieldparam left [BasicObject] The preceding entry.
|
|
730
|
+
# @yieldparam right [BasicObject] The current entry.
|
|
731
|
+
# @yieldreturn [BasicObject] A truthy value to keep the entries in one group.
|
|
732
|
+
# @return [Enumerator] Yields same-kind Vector groups.
|
|
733
|
+
def chunk_while(&block)
|
|
734
|
+
raise ArgumentError, "no block given" unless block
|
|
735
|
+
|
|
736
|
+
Enumerator.new do |yielder|
|
|
737
|
+
snapshot = internal_vector.snapshot
|
|
738
|
+
snapshot.chunk_while { |left, right| block.call(logical_value(left), logical_value(right)) }
|
|
739
|
+
.each { yielder << build_derived_vector(it) }
|
|
740
|
+
end
|
|
741
|
+
end
|
|
742
|
+
|
|
743
|
+
# Group a snapshot before matching entries.
|
|
744
|
+
# @param arguments [Array<BasicObject>] One pattern for `===` matching, or no arguments when using a block.
|
|
745
|
+
# @yield [value] Test each entry when no pattern is supplied.
|
|
746
|
+
# @yieldparam value [BasicObject] The current entry.
|
|
747
|
+
# @yieldreturn [BasicObject] A truthy value to split at this entry.
|
|
748
|
+
# @return [Enumerator] Yields same-kind Vector groups.
|
|
749
|
+
def slice_before(*arguments, &block)
|
|
750
|
+
logical_grouping_enumerator(:slice_before, arguments, block)
|
|
751
|
+
end
|
|
752
|
+
|
|
753
|
+
# Group a snapshot after matching entries.
|
|
754
|
+
# @param arguments [Array<BasicObject>] One pattern for `===` matching, or no arguments when using a block.
|
|
755
|
+
# @yield [value] Test each entry when no pattern is supplied.
|
|
756
|
+
# @yieldparam value [BasicObject] The current entry.
|
|
757
|
+
# @yieldreturn [BasicObject] A truthy value to split at this entry.
|
|
758
|
+
# @return [Enumerator] Yields same-kind Vector groups.
|
|
759
|
+
def slice_after(*arguments, &block)
|
|
760
|
+
logical_grouping_enumerator(:slice_after, arguments, block)
|
|
761
|
+
end
|
|
762
|
+
|
|
763
|
+
# Group a snapshot between pairs accepted by the block.
|
|
764
|
+
# @yield [left, right] Test consecutive entries. A block is required.
|
|
765
|
+
# @yieldparam left [BasicObject] The preceding entry.
|
|
766
|
+
# @yieldparam right [BasicObject] The current entry.
|
|
767
|
+
# @yieldreturn [BasicObject] A truthy value to start a new group.
|
|
768
|
+
# @return [Enumerator] Yields same-kind Vector groups.
|
|
769
|
+
def slice_when(&block)
|
|
770
|
+
raise ArgumentError, "no block given" unless block
|
|
771
|
+
logical_grouping_enumerator(:slice_when, [], block)
|
|
772
|
+
end
|
|
773
|
+
|
|
774
|
+
# Zip values into Vector rows. With a block, yield rows and return nil.
|
|
775
|
+
# @param others [Array<Enumerable, #to_ary>] The sequences to combine with this vector.
|
|
776
|
+
# @yield [row] Optionally visit each combined row.
|
|
777
|
+
# @yieldparam row [Vector] One entry from each sequence, padded with nil for shorter sequences.
|
|
778
|
+
# @yieldreturn [void] The result is ignored.
|
|
779
|
+
# @return [Vector, nil] A Vector of Vector rows, or nil when a block is supplied.
|
|
780
|
+
def zip(*others)
|
|
781
|
+
snapshot = internal_vector.snapshot
|
|
782
|
+
operands = others.map do |other|
|
|
783
|
+
stored = other.equal?(self) ? snapshot : reusable_operand_snapshot(other)
|
|
784
|
+
stored ? [stored, true] : [zip_operand(other, snapshot.length), false]
|
|
785
|
+
end
|
|
786
|
+
build_row = lambda do |stored, index|
|
|
787
|
+
row = [stored]
|
|
788
|
+
operands.each do |values, prepared|
|
|
789
|
+
row << (prepared ? values[index] : derived_storage(values[index]))
|
|
790
|
+
end
|
|
791
|
+
build_derived_vector(row)
|
|
792
|
+
end
|
|
793
|
+
if block_given?
|
|
794
|
+
snapshot.each_with_index { |stored, index| yield build_row.call(stored, index) }
|
|
795
|
+
nil
|
|
796
|
+
else
|
|
797
|
+
rows = snapshot.each_with_index.map { |stored, index| build_row.call(stored, index) }
|
|
798
|
+
build_derived_values(rows)
|
|
799
|
+
end
|
|
800
|
+
end
|
|
801
|
+
|
|
802
|
+
# Materialize enumeration as a Vector rather than an Array.
|
|
803
|
+
# @return [Vector] A new same-kind Vector containing the result.
|
|
804
|
+
def entries = build_derived_vector(internal_vector.snapshot)
|
|
805
|
+
|
|
806
|
+
# Read an index without waiting for atomic-update access.
|
|
807
|
+
# @param index [Integer] The index. Negative indexes count from the end.
|
|
808
|
+
# @return [BasicObject, nil] The value, or nil for an index outside the vector.
|
|
809
|
+
def [](index) = internal_vector[index]
|
|
810
|
+
|
|
811
|
+
# Store a value, growing the vector if necessary.
|
|
812
|
+
# @param index [Integer] The index. Negative indexes count from the end.
|
|
813
|
+
# @param value [BasicObject] The value to store.
|
|
814
|
+
# @return [BasicObject] The assigned value.
|
|
815
|
+
def []=(index, value)
|
|
816
|
+
internal_vector[index] = value
|
|
817
|
+
end
|
|
818
|
+
|
|
819
|
+
# Read an index after acquiring atomic-update access.
|
|
820
|
+
# @param index [Integer] The index. Negative indexes count from the end.
|
|
821
|
+
# @param timeout [Numeric, nil] The maximum wait in seconds. Nil waits indefinitely.
|
|
822
|
+
# @return [BasicObject, nil] The value, or nil if absent or timed out.
|
|
823
|
+
def get(index, timeout: nil) = internal_vector.get(index, timeout:)
|
|
824
|
+
|
|
825
|
+
# Store a value after acquiring atomic-update access.
|
|
826
|
+
# @param index [Integer] The index. Negative indexes count from the end.
|
|
827
|
+
# @param value [BasicObject] The value to store.
|
|
828
|
+
# @param timeout [Numeric, nil] The maximum wait in seconds. Nil waits indefinitely.
|
|
829
|
+
# @return [BasicObject, false] The value, or false on timeout.
|
|
830
|
+
def store(index, value, timeout: nil) = internal_vector.store(index, value, timeout:)
|
|
831
|
+
|
|
832
|
+
# Append a single value.
|
|
833
|
+
# @param value [BasicObject] The value to append.
|
|
834
|
+
# @param timeout [Numeric, nil] The maximum wait in seconds. Nil waits indefinitely.
|
|
835
|
+
# @return [self, false] Self on success, or false on timeout.
|
|
836
|
+
def push(value, timeout: nil)
|
|
837
|
+
internal_vector.push(value, timeout:) ? self : false
|
|
838
|
+
end
|
|
839
|
+
|
|
840
|
+
# Append snapshots of one or more sequences and return this vector.
|
|
841
|
+
# Each append is synchronized separately. Other writers may interleave.
|
|
842
|
+
# Values use the vector's default transfer mode. Self-concatenation reuses
|
|
843
|
+
# existing storage and captures the original contents only once.
|
|
844
|
+
# @param sources [Array<Vector, #to_ary>] sequences to append
|
|
845
|
+
# @return [self]
|
|
846
|
+
def concat(*sources)
|
|
847
|
+
Internal::Freeze.check(self)
|
|
848
|
+
own_snapshot = internal_vector.snapshot if sources.any? { it.equal?(self) }
|
|
849
|
+
snapshots = sources.map do |source|
|
|
850
|
+
if source.equal?(self)
|
|
851
|
+
own_snapshot
|
|
852
|
+
else
|
|
853
|
+
reusable_operand_snapshot(source) || vector_operand(source).map { derived_storage(it) }
|
|
854
|
+
end
|
|
855
|
+
end
|
|
856
|
+
snapshots.each { |values| values.each { internal_vector.push(it) } }
|
|
857
|
+
self
|
|
858
|
+
end
|
|
859
|
+
|
|
860
|
+
# Append a single value without a timeout.
|
|
861
|
+
# @param value [BasicObject] The value to append.
|
|
862
|
+
# @return [self]
|
|
863
|
+
def <<(value) = push(value)
|
|
864
|
+
|
|
865
|
+
# Append one value using the same options as {#push}.
|
|
866
|
+
# @overload append(value, timeout: nil)
|
|
867
|
+
# @param value [BasicObject] The value to append.
|
|
868
|
+
# @param timeout [Numeric, nil] The maximum wait in seconds. Nil waits indefinitely.
|
|
869
|
+
# @return [self, false] Self on success, or false on timeout.
|
|
870
|
+
def append(...) = push(...)
|
|
871
|
+
|
|
872
|
+
# Remove and return the last value.
|
|
873
|
+
# This does not wait for an empty vector to become nonempty.
|
|
874
|
+
# @param timeout [Numeric, nil] The maximum wait in seconds. Nil waits indefinitely.
|
|
875
|
+
# @return [BasicObject, nil] The last value, or nil if empty or timed out.
|
|
876
|
+
def pop(timeout: nil) = internal_vector.pop(timeout:)
|
|
877
|
+
|
|
878
|
+
# Replace an index and return its previous value, growing the vector if necessary.
|
|
879
|
+
# @param index [Integer] The index. Negative indexes count from the end.
|
|
880
|
+
# @param replacement [BasicObject] The new value.
|
|
881
|
+
# @param timeout [Numeric, nil] The maximum wait in seconds. Nil waits indefinitely.
|
|
882
|
+
# @return [BasicObject, nil] The previous value, or nil if absent or timed out.
|
|
883
|
+
def swap(index, replacement, timeout: nil) = internal_vector.swap(index, replacement, timeout:)
|
|
884
|
+
|
|
885
|
+
# Compute and store a value only when the index is absent or contains nil.
|
|
886
|
+
# @param index [Integer] The index. Negative indexes count from the end.
|
|
887
|
+
# @param timeout [Numeric, nil] The maximum wait in seconds. Nil waits indefinitely.
|
|
888
|
+
# @yield Called without arguments to compute a value when the slot is absent or nil.
|
|
889
|
+
# @yieldreturn [BasicObject] The value to store.
|
|
890
|
+
# @return [BasicObject, nil] The existing or computed value, or nil on timeout.
|
|
891
|
+
def store_if_absent(index, timeout: nil, &) = internal_vector.store_if_absent(index, timeout:, &)
|
|
892
|
+
|
|
893
|
+
# Replace an existing index only if its value matches the expected value.
|
|
894
|
+
# This never grows the vector. Matching uses the configured comparison mode.
|
|
895
|
+
# @param index [Integer] The index. Negative indexes count from the end.
|
|
896
|
+
# @param expected [BasicObject] The value that must match the current entry.
|
|
897
|
+
# @param replacement [BasicObject] The value to store on a match.
|
|
898
|
+
# @param timeout [Numeric, nil] The maximum wait in seconds. Nil waits indefinitely.
|
|
899
|
+
# @return [Boolean] Whether the replacement succeeded. False on timeout.
|
|
900
|
+
def compare_and_set(index, expected, replacement, timeout: nil)
|
|
901
|
+
internal_vector.compare_and_set(index, expected, replacement, timeout:)
|
|
902
|
+
end
|
|
903
|
+
|
|
904
|
+
# Atomically replace an index with the block result, growing the vector if necessary.
|
|
905
|
+
# @param index [Integer] The index. Negative indexes count from the end.
|
|
906
|
+
# @param timeout [Numeric, nil] The maximum wait in seconds. Nil waits indefinitely.
|
|
907
|
+
# @yield [value] Compute the replacement while holding atomic-update access.
|
|
908
|
+
# @yieldparam value [BasicObject, nil] The current value, or nil if absent.
|
|
909
|
+
# @yieldreturn [BasicObject] The replacement value.
|
|
910
|
+
# @return [BasicObject, nil] The replacement value, or nil on timeout.
|
|
911
|
+
def update(index, timeout: nil, &) = internal_vector.update(index, timeout:, &)
|
|
912
|
+
|
|
913
|
+
# Store initial for an absent or nil index, otherwise replace it with the block result.
|
|
914
|
+
# @param index [Integer] The index. Negative indexes count from the end.
|
|
915
|
+
# @param initial [BasicObject] The value to store when the slot is absent or nil.
|
|
916
|
+
# @param timeout [Numeric, nil] The maximum wait in seconds. Nil waits indefinitely.
|
|
917
|
+
# @yield [value] Compute a replacement for an existing non-nil entry.
|
|
918
|
+
# @yieldparam value [BasicObject] The current non-nil value.
|
|
919
|
+
# @yieldreturn [BasicObject] The replacement value.
|
|
920
|
+
# @return [BasicObject, nil] The stored value, or nil on timeout.
|
|
921
|
+
def upsert(index, initial, timeout: nil, &) = internal_vector.upsert(index, initial, timeout:, &)
|
|
922
|
+
|
|
923
|
+
# Wait until a block condition matches the value at an index.
|
|
924
|
+
# Absent indexes are observed as nil.
|
|
925
|
+
# One timeout budget covers all checks and waits. The block is not interrupted.
|
|
926
|
+
# @yieldparam value [BasicObject, nil] the current value
|
|
927
|
+
# @yieldreturn [Boolean] whether the value matches
|
|
928
|
+
# @param index [Integer] the index to observe. Negative indexes count from the end.
|
|
929
|
+
# @param timeout [Numeric, nil] the total seconds available
|
|
930
|
+
# @return [BasicObject, nil] the matching value, or nil on timeout
|
|
931
|
+
# @raise [LocalJumpError] if no block is given
|
|
932
|
+
def wait_until(index, timeout: nil, &) = Internal.wait_until(self, index, timeout:, &)
|
|
933
|
+
|
|
934
|
+
# Wait while the block returns a truthy value.
|
|
935
|
+
# @yieldparam value [BasicObject, nil] the current value
|
|
936
|
+
# @yieldreturn [BasicObject] a truthy value to keep waiting, or nil or false to stop
|
|
937
|
+
# @param index [Integer] the index to observe. Negative indexes count from the end.
|
|
938
|
+
# @param timeout [Numeric, nil] the total seconds available
|
|
939
|
+
# @return [BasicObject, nil] the value when the condition becomes false, or nil on timeout
|
|
940
|
+
# @raise [LocalJumpError] if no block is given
|
|
941
|
+
def wait_while(index, timeout: nil)
|
|
942
|
+
raise LocalJumpError, "no block given" unless block_given?
|
|
943
|
+
wait_until(index, timeout:) { |value| !yield(value) }
|
|
944
|
+
end
|
|
945
|
+
|
|
946
|
+
# Wait while `object === value` is true.
|
|
947
|
+
# @param object [#===] the pattern to stop matching
|
|
948
|
+
# @param index [Integer] the index to observe. Negative indexes count from the end.
|
|
949
|
+
# @param timeout [Numeric, nil] the total seconds available
|
|
950
|
+
# @return [BasicObject, nil] the first nonmatching value, or nil on timeout
|
|
951
|
+
def wait_while_match(index, object, timeout: nil)
|
|
952
|
+
wait_while(index, timeout:) { |value| object === value } # rubocop:disable Style/CaseEquality
|
|
953
|
+
end
|
|
954
|
+
|
|
955
|
+
# Wait until the current value equals an object using the configured comparison mode.
|
|
956
|
+
# @param object [BasicObject, nil] the value to compare with the current value
|
|
957
|
+
# @param index [Integer] the index to observe. Negative indexes count from the end.
|
|
958
|
+
# @param timeout [Numeric, nil] the total seconds available
|
|
959
|
+
# @return [BasicObject, nil] the matching value, or nil on timeout
|
|
960
|
+
def wait_until_value(index, object, timeout: nil)
|
|
961
|
+
wait_until(index, timeout:) { |value| compare_by_identity? ? object.equal?(value) : object == value }
|
|
962
|
+
end
|
|
963
|
+
|
|
964
|
+
# Wait until `object === value` is true.
|
|
965
|
+
# @param object [#===] the pattern to match
|
|
966
|
+
# @param index [Integer] the index to observe. Negative indexes count from the end.
|
|
967
|
+
# @param timeout [Numeric, nil] the total seconds available
|
|
968
|
+
# @return [BasicObject, nil] the matching value, or nil on timeout
|
|
969
|
+
def wait_until_match(index, object, timeout: nil)
|
|
970
|
+
wait_until(index, timeout:) { |value| object === value } # rubocop:disable Style/CaseEquality
|
|
971
|
+
end
|
|
972
|
+
|
|
973
|
+
# Wait until an index no longer matches expected. Absent indexes are observed as nil.
|
|
974
|
+
# @param index [Integer] The index. Negative indexes count from the end.
|
|
975
|
+
# @param expected [BasicObject] The value to wait for the entry to stop matching.
|
|
976
|
+
# @param timeout [Numeric, nil] The maximum wait in seconds. Nil waits indefinitely.
|
|
977
|
+
# @return [BasicObject, nil] The changed value, or nil on timeout.
|
|
978
|
+
def wait_until_changed(index, expected, timeout: nil)
|
|
979
|
+
internal_vector.wait_until_changed(index, expected, timeout:)
|
|
980
|
+
end
|
|
981
|
+
|
|
982
|
+
# (see #wait_until_changed)
|
|
983
|
+
def wait_while_value(...) = wait_until_changed(...)
|
|
984
|
+
|
|
985
|
+
# Wait until an index contains a non-nil value.
|
|
986
|
+
# @param index [Integer] The index. Negative indexes count from the end.
|
|
987
|
+
# @param timeout [Numeric, nil] The maximum wait in seconds. Nil waits indefinitely.
|
|
988
|
+
# @return [BasicObject, nil] The non-nil value, or nil on timeout.
|
|
989
|
+
def wait_until_non_nil(index, timeout: nil) = internal_vector.wait_until_non_nil(index, timeout:)
|
|
990
|
+
|
|
991
|
+
# @return [Integer] The number of slots, including nil slots.
|
|
992
|
+
def size = internal_vector.size
|
|
993
|
+
|
|
994
|
+
# @return [Boolean] Whether values are compared by identity.
|
|
995
|
+
def compare_by_identity? = internal_vector.compare_by_identity?
|
|
996
|
+
|
|
997
|
+
# @return [Boolean] Whether stored values must be Ractor-shareable.
|
|
998
|
+
def shareable_values? = false
|
|
999
|
+
|
|
1000
|
+
# Remove all slots.
|
|
1001
|
+
# @return [self]
|
|
1002
|
+
def clear
|
|
1003
|
+
internal_vector.clear
|
|
1004
|
+
self
|
|
1005
|
+
end
|
|
1006
|
+
|
|
1007
|
+
protected
|
|
1008
|
+
|
|
1009
|
+
def internal_vector = @vector
|
|
1010
|
+
|
|
1011
|
+
# Convert a stored value into the value visible through the public API.
|
|
1012
|
+
def logical_value(value) = value
|
|
1013
|
+
|
|
1014
|
+
# Build a new same-kind Vector from already prepared stored values.
|
|
1015
|
+
def build_derived_vector(values)
|
|
1016
|
+
self.class.new(values, compare_by_identity: compare_by_identity?)
|
|
1017
|
+
end
|
|
1018
|
+
|
|
1019
|
+
def reusable_operand_snapshot(other)
|
|
1020
|
+
return unless other.instance_of?(self.class)
|
|
1021
|
+
other.internal_vector.snapshot
|
|
1022
|
+
end
|
|
1023
|
+
|
|
1024
|
+
private
|
|
1025
|
+
|
|
1026
|
+
def each_for_inspect(&) = internal_vector.each(&)
|
|
1027
|
+
|
|
1028
|
+
def build_derived_values(values) = build_derived_vector(values.map { derived_storage(it) })
|
|
1029
|
+
|
|
1030
|
+
def build_derived_from_logical(values, source_storage, source_values)
|
|
1031
|
+
retained = {}.compare_by_identity
|
|
1032
|
+
source_values.each_with_index { |value, index| retained[value] ||= source_storage[index] }
|
|
1033
|
+
storage = values.map do |value|
|
|
1034
|
+
retained.fetch(value) { derived_storage(value) }
|
|
1035
|
+
end
|
|
1036
|
+
build_derived_vector(storage)
|
|
1037
|
+
end
|
|
1038
|
+
|
|
1039
|
+
def derived_storage(value) = value
|
|
1040
|
+
|
|
1041
|
+
def derive_array_operation(operation, *others)
|
|
1042
|
+
snapshot = internal_vector.snapshot
|
|
1043
|
+
logical = snapshot.map { logical_value(it) }
|
|
1044
|
+
result = logical.public_send(operation, *others.map { vector_operand(it) })
|
|
1045
|
+
build_derived_from_logical(result, snapshot, logical)
|
|
1046
|
+
end
|
|
1047
|
+
|
|
1048
|
+
def vector_operand(value)
|
|
1049
|
+
return value.to_a if value.is_a?(Vector)
|
|
1050
|
+
converted = Array.try_convert(value)
|
|
1051
|
+
return converted if converted
|
|
1052
|
+
raise TypeError, "no implicit conversion of #{value.class} into Array"
|
|
1053
|
+
end
|
|
1054
|
+
|
|
1055
|
+
def zip_operand(value, length)
|
|
1056
|
+
converted = Array.try_convert(value)
|
|
1057
|
+
return converted if converted
|
|
1058
|
+
raise TypeError, "wrong argument type #{value.class} (must respond to :each)" unless value.respond_to?(:each)
|
|
1059
|
+
|
|
1060
|
+
enumerator = value.to_enum
|
|
1061
|
+
Array.new(length) do
|
|
1062
|
+
enumerator.next
|
|
1063
|
+
rescue StopIteration
|
|
1064
|
+
nil
|
|
1065
|
+
end
|
|
1066
|
+
end
|
|
1067
|
+
|
|
1068
|
+
def normalize_hash_pair(value) = value.is_a?(Vector) ? value.to_a : value
|
|
1069
|
+
|
|
1070
|
+
def find_pair(expected, index)
|
|
1071
|
+
each do |value|
|
|
1072
|
+
pair = if value.is_a?(Vector)
|
|
1073
|
+
value
|
|
1074
|
+
else
|
|
1075
|
+
Array.try_convert(value)
|
|
1076
|
+
end
|
|
1077
|
+
return pair if pair && pair.length > index && array_value_equal?(pair[index], expected)
|
|
1078
|
+
end
|
|
1079
|
+
nil
|
|
1080
|
+
end
|
|
1081
|
+
|
|
1082
|
+
def normalized_extreme_count(count)
|
|
1083
|
+
return if count.equal?(UNDEFINED) || count.nil?
|
|
1084
|
+
|
|
1085
|
+
count = convert_vector_count(count)
|
|
1086
|
+
raise ArgumentError, "negative size (#{count})" if count.negative?
|
|
1087
|
+
count
|
|
1088
|
+
end
|
|
1089
|
+
|
|
1090
|
+
def array_value_equal?(left, right) = left.equal?(right) || left == right
|
|
1091
|
+
|
|
1092
|
+
def logical_grouping_enumerator(method, arguments, block)
|
|
1093
|
+
# Ask an empty Array to validate argument and block combinations now.
|
|
1094
|
+
[].public_send(method, *arguments, &block)
|
|
1095
|
+
Enumerator.new do |yielder|
|
|
1096
|
+
snapshot = internal_vector.snapshot
|
|
1097
|
+
logical = snapshot.map { logical_value(it) }
|
|
1098
|
+
logical.public_send(method, *arguments, &block).each do |group|
|
|
1099
|
+
yielder << build_derived_from_logical(group, snapshot, logical)
|
|
1100
|
+
end
|
|
1101
|
+
end
|
|
1102
|
+
end
|
|
1103
|
+
|
|
1104
|
+
def convert_vector_count(value)
|
|
1105
|
+
return value if value.is_a?(Integer)
|
|
1106
|
+
raise TypeError, "no implicit conversion of #{value.class} into Integer" unless value.respond_to?(:to_int)
|
|
1107
|
+
converted = value.to_int
|
|
1108
|
+
return converted if converted.is_a?(Integer)
|
|
1109
|
+
raise TypeError, "can't convert #{value.class} to Integer"
|
|
1110
|
+
end
|
|
1111
|
+
|
|
1112
|
+
alias convert_vector_index convert_vector_count
|
|
1113
|
+
|
|
1114
|
+
def initialize_copy(other)
|
|
1115
|
+
super
|
|
1116
|
+
source = other.internal_vector
|
|
1117
|
+
copy = source.class.new(source.snapshot, compare_by_identity: source.compare_by_identity?)
|
|
1118
|
+
if is_a?(Local::Scoped)
|
|
1119
|
+
Internal::Storage.scope(scope)[self] = copy
|
|
1120
|
+
else
|
|
1121
|
+
@vector = copy
|
|
1122
|
+
end
|
|
1123
|
+
end
|
|
1124
|
+
end
|
|
1125
|
+
end
|
|
1126
|
+
end
|