farce 0.0.1.alpha2-x86_64-linux-gnu
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/ext/ext_helper.rb +20 -0
- data/ext/farce/README.md +21 -0
- data/ext/farce/atom.c +1023 -0
- data/ext/farce/bounded_map.c +1683 -0
- data/ext/farce/containers.h +77 -0
- data/ext/farce/counter.c +399 -0
- data/ext/farce/darwin.c +100 -0
- data/ext/farce/depend +12 -0
- data/ext/farce/dict.c +1523 -0
- data/ext/farce/dict.h +152 -0
- data/ext/farce/drivers.c +237 -0
- data/ext/farce/exchanger.c +299 -0
- data/ext/farce/extconf.rb +99 -0
- data/ext/farce/farce.c +359 -0
- data/ext/farce/flag.c +288 -0
- data/ext/farce/io.c +338 -0
- data/ext/farce/lock.c +510 -0
- data/ext/farce/map.c +2240 -0
- data/ext/farce/priority_queue.c +2056 -0
- data/ext/farce/queue.c +1059 -0
- data/ext/farce/reactor.c +820 -0
- data/ext/farce/reactor.h +103 -0
- data/ext/farce/shareable.h +31 -0
- data/ext/farce/signal.c +350 -0
- data/ext/farce/transaction.c +354 -0
- data/ext/farce/transaction.h +40 -0
- data/ext/farce/tree_map.c +1953 -0
- data/ext/farce/trie.c +2020 -0
- data/ext/farce/unshareable.c +155 -0
- data/ext/farce/unshared_io_pool.h +234 -0
- data/ext/farce/unshared_signal.c +263 -0
- data/ext/farce/unshared_wait.h +193 -0
- data/ext/farce/unsupported.c +6 -0
- data/ext/farce/vector.c +1195 -0
- data/ext/farce/weak_map.c +1714 -0
- data/ext/java/org/farce/BoundedMap.java +394 -0
- data/ext/java/org/farce/FiberScheduler.java +141 -0
- data/ext/java/org/farce/PriorityKey.java +45 -0
- data/ext/java/org/farce/PriorityQueue.java +373 -0
- data/ext/java/org/farce/QueueSignal.java +28 -0
- data/ext/rebind/README.md +14 -0
- data/ext/rebind/extconf.rb +10 -0
- data/ext/rebind/rebind.c +186 -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/farce.so +0 -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/rebind.so +0 -0
- data/lib/farce/engine/ruby/3.4/vault.rb +56 -0
- data/lib/farce/engine/ruby/4.0/farce.so +0 -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/rebind.so +0 -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 +468 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
# A Ractor-shareable atomic reference that retains its value weakly.
|
|
7
|
+
# Values support :raise (the default), :make_shareable, and :dedup.
|
|
8
|
+
# The value becomes nil after collection when no strong references remain.
|
|
9
|
+
# With :dedup, retain the canonical result returned by store or update.
|
|
10
|
+
# Keeping only the input alive may not keep the stored result alive.
|
|
11
|
+
# Assignment evaluates to the input rather than the canonical result.
|
|
12
|
+
# Comparisons observe the stored object without preparing their operands.
|
|
13
|
+
#
|
|
14
|
+
# @example Publishing the original object without keeping it alive
|
|
15
|
+
# value = []
|
|
16
|
+
# atom = Farce::WeakAtom.new(value, mode: :make_shareable)
|
|
17
|
+
# atom.value.equal?(value) # => true
|
|
18
|
+
# value = nil
|
|
19
|
+
# # After collection, atom.value returns nil.
|
|
20
|
+
class WeakAtom < Farce::Abstract::WeakAtom
|
|
21
|
+
include Shareable::Delegated
|
|
22
|
+
|
|
23
|
+
TIMED_OUT = Object.new.freeze
|
|
24
|
+
private_constant :TIMED_OUT
|
|
25
|
+
|
|
26
|
+
# @param value [BasicObject, nil] the initial value
|
|
27
|
+
# @param mode [Symbol] :raise, :make_shareable, or :dedup
|
|
28
|
+
# @param compare_by_identity [Boolean] whether comparisons use object identity
|
|
29
|
+
def initialize(value = nil, mode: :raise, compare_by_identity: false)
|
|
30
|
+
@manager = Internal::WeakModeManager.new(mode:)
|
|
31
|
+
super(@manager.wrap(value), compare_by_identity:)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# The default mode used to prepare replacement values.
|
|
35
|
+
# @return [Symbol]
|
|
36
|
+
def mode = @manager.mode
|
|
37
|
+
|
|
38
|
+
# (see Abstract::Atom#store)
|
|
39
|
+
# @param mode [Symbol, nil] the replacement's mode, or nil for the default
|
|
40
|
+
def store(new_value, mode: nil, timeout: nil, &)
|
|
41
|
+
check_frozen!
|
|
42
|
+
super(@manager.wrap(new_value, mode:), timeout:, &)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# (see Abstract::Atom#swap)
|
|
46
|
+
# @param mode [Symbol, nil] the replacement's mode, or nil for the default
|
|
47
|
+
def swap(new_value, mode: nil, timeout: nil, &)
|
|
48
|
+
check_frozen!
|
|
49
|
+
super(@manager.wrap(new_value, mode:), timeout:, &)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# (see Abstract::Atom#store_if_absent)
|
|
53
|
+
# @param mode [Symbol, nil] the result's mode, or nil for the default
|
|
54
|
+
def store_if_absent(mode: nil, timeout: nil)
|
|
55
|
+
raise LocalJumpError, "no block given" unless block_given?
|
|
56
|
+
@manager.validate_mode!(mode)
|
|
57
|
+
super(timeout:) do
|
|
58
|
+
value = yield
|
|
59
|
+
check_frozen!
|
|
60
|
+
@manager.wrap(value, mode:)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# (see Abstract::Atom#update)
|
|
65
|
+
# @param mode [Symbol, nil] the result's mode, or nil for the default
|
|
66
|
+
def update(mode: nil, timeout: nil)
|
|
67
|
+
raise LocalJumpError, "no block given" unless block_given?
|
|
68
|
+
@manager.validate_mode!(mode)
|
|
69
|
+
super(timeout:) do |current|
|
|
70
|
+
value = yield(current)
|
|
71
|
+
check_frozen!
|
|
72
|
+
@manager.wrap(value, mode:)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# (see Abstract::Atom#upsert)
|
|
77
|
+
# @param mode [Symbol, nil] the replacement's mode, or nil for the default
|
|
78
|
+
def upsert(initial, mode: nil, timeout: nil)
|
|
79
|
+
raise LocalJumpError, "no block given" unless block_given?
|
|
80
|
+
@manager.validate_mode!(mode)
|
|
81
|
+
@atom.update(timeout:) do |current|
|
|
82
|
+
value = nil.equal?(current) ? initial : yield(current)
|
|
83
|
+
check_frozen!
|
|
84
|
+
@manager.wrap(value, mode:)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# (see Abstract::Atom#compare_and_set)
|
|
89
|
+
# @param mode [Symbol, nil] the replacement's mode, or nil for the default
|
|
90
|
+
def compare_and_set(expected, replacement, mode: nil, timeout: nil)
|
|
91
|
+
@manager.validate_mode!(mode)
|
|
92
|
+
matched = false
|
|
93
|
+
@atom.update(timeout:) do |current|
|
|
94
|
+
next current unless values_equal?(current, expected)
|
|
95
|
+
check_frozen!
|
|
96
|
+
prepared = @manager.wrap(replacement, mode:)
|
|
97
|
+
matched = true
|
|
98
|
+
prepared
|
|
99
|
+
end
|
|
100
|
+
matched
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# (see Abstract::Atom#wait_until_changed)
|
|
104
|
+
def wait_until_changed(expected, timeout: nil, &fallback)
|
|
105
|
+
deadline = Internal.timeout_deadline(timeout)
|
|
106
|
+
while true
|
|
107
|
+
current = @atom.get(timeout: Internal.remaining_timeout(deadline)) { TIMED_OUT }
|
|
108
|
+
return fallback&.call if TIMED_OUT.equal?(current)
|
|
109
|
+
return current unless values_equal?(current, expected)
|
|
110
|
+
result = @atom.wait_until_changed(current, timeout: Internal.remaining_timeout(deadline)) { TIMED_OUT }
|
|
111
|
+
return fallback&.call if TIMED_OUT.equal?(result)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
private
|
|
116
|
+
|
|
117
|
+
def internal_atom_class = Internal::WeakAtom
|
|
118
|
+
def freeze_backend = @atom
|
|
119
|
+
def values_equal?(left, right) = @manager.same_value?(left, right, identity: compare_by_identity?)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
# A concurrent map with weak shareable keys and strongly retained values.
|
|
7
|
+
# Transfer modes apply only to values. Keys are stored directly.
|
|
8
|
+
# Entries disappear after their keys are collected. A value that references
|
|
9
|
+
# its key, including through an envelope, can keep that key alive.
|
|
10
|
+
#
|
|
11
|
+
# @example Associating mutable metadata with a shareable object
|
|
12
|
+
# owner = Object.new.freeze
|
|
13
|
+
# map = Farce::WeakKeyMap.new
|
|
14
|
+
# map[owner] = { visits: 1 }
|
|
15
|
+
# map.update(owner) { |metadata| { visits: metadata[:visits] + 1 } }
|
|
16
|
+
# map[owner] # => { visits: 2 }
|
|
17
|
+
#
|
|
18
|
+
# # The entry can disappear once its key is collected.
|
|
19
|
+
# owner = nil
|
|
20
|
+
class WeakKeyMap < Farce::Abstract::WeakKeyMap
|
|
21
|
+
include Internal::MapValueModes
|
|
22
|
+
include Shareable::Delegated
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def new_map(**) = Internal::StrictWeakKeyMap.new(**)
|
|
27
|
+
def freeze_backend = @map
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
Internal::KeyNormalizer.prepare_concurrent_class(Internal::StrictWeakKeyMap)
|
|
31
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
# A Ractor-shareable concurrent map with weak shareable keys and weak values.
|
|
7
|
+
# Entries disappear after a weakly held object is collected.
|
|
8
|
+
#
|
|
9
|
+
# Supported modes are `:raise` (the default), `:make_shareable`, and `:dedup`.
|
|
10
|
+
# Modes apply only to values. Keys must already be shareable.
|
|
11
|
+
#
|
|
12
|
+
# With `:dedup`, retain the canonical result returned by store or update,
|
|
13
|
+
# as it might differ from the input and could be immediately collected.
|
|
14
|
+
# Assignment evaluates to the input rather than the canonical result.
|
|
15
|
+
#
|
|
16
|
+
# @example Publishing a value without retaining it strongly
|
|
17
|
+
# key = Object.new.freeze
|
|
18
|
+
# value = []
|
|
19
|
+
# map = Farce::WeakMap.new(mode: :make_shareable)
|
|
20
|
+
# map[key] = value
|
|
21
|
+
# map[key].equal?(value) # => true
|
|
22
|
+
class WeakMap < Farce::Abstract::WeakMap
|
|
23
|
+
include Internal::WeakMapValueModes
|
|
24
|
+
include Shareable::Delegated
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def new_map(**) = Internal::StrictWeakMap.new(**)
|
|
29
|
+
def freeze_backend = @map
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
Internal::KeyNormalizer.prepare_concurrent_class(Internal::StrictWeakMap)
|
|
33
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
require "delegate"
|
|
6
|
+
|
|
7
|
+
module Farce
|
|
8
|
+
# Drop-in replacement for Ruby's WeakRef class that is Ractor-friendly.
|
|
9
|
+
#
|
|
10
|
+
# @example
|
|
11
|
+
# foo = Object.new # create a new object instance
|
|
12
|
+
# p foo.to_s # original's class
|
|
13
|
+
# foo = Farce::WeakRef.new(foo) # reassign foo with WeakRef instance
|
|
14
|
+
# p foo.to_s # should be same class
|
|
15
|
+
# GC.start # start the garbage collector
|
|
16
|
+
# p foo.to_s # should raise exception (recycled)
|
|
17
|
+
class WeakRef < Delegator
|
|
18
|
+
include Internal::MarshalSupport::WeakRef
|
|
19
|
+
|
|
20
|
+
recycled = allocate
|
|
21
|
+
recycled.instance_variable_set(:@value, WeakValue::RECYCLED)
|
|
22
|
+
|
|
23
|
+
class << recycled
|
|
24
|
+
undef marshal_dump
|
|
25
|
+
|
|
26
|
+
# @api private
|
|
27
|
+
def _dump(_) = "recycled"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @api private
|
|
31
|
+
RECYCLED = Kernel.instance_method(:freeze).bind_call(recycled)
|
|
32
|
+
|
|
33
|
+
# Alias for {WeakRefError} to mimic `::WeakRef::RefError`
|
|
34
|
+
RefError = WeakRefError
|
|
35
|
+
|
|
36
|
+
# @api private
|
|
37
|
+
def self._load(state)
|
|
38
|
+
raise TypeError, "invalid weak reference state" unless state == "recycled"
|
|
39
|
+
RECYCLED
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def initialize(value)
|
|
43
|
+
@value = WeakValue.new(value)
|
|
44
|
+
super
|
|
45
|
+
Kernel.instance_method(:freeze).bind_call(self)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# @api private
|
|
49
|
+
def __getobj__ = @value.value # :nodoc:
|
|
50
|
+
|
|
51
|
+
# @api private
|
|
52
|
+
def __setobj__(_) = nil # :nodoc:
|
|
53
|
+
|
|
54
|
+
# @return [Boolean] true if the referenced object is still alive and reachable
|
|
55
|
+
def weakref_alive? = @value.alive?
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
def respond_to_missing?(name, include_private = false)
|
|
60
|
+
return false if Internal.marshal_protocol_method?(name)
|
|
61
|
+
super
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def initialize_dup(other) = initialize_copy(other)
|
|
65
|
+
def initialize_clone(other, **) = initialize_copy(other)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
# A Ractor-shareable concurrent set that retains prepared elements weakly.
|
|
7
|
+
# Elements support :raise (the default), :make_shareable, and :dedup.
|
|
8
|
+
# Membership refers to the prepared element itself. Lookup and deletion do
|
|
9
|
+
# not freeze or deduplicate their arguments. Already-shareable elements pass
|
|
10
|
+
# through unchanged, as with other mode-backed containers.
|
|
11
|
+
#
|
|
12
|
+
# With :dedup, the stored canonical element can differ from the input.
|
|
13
|
+
# Keeping only the input alive may not keep that element alive. Callers are
|
|
14
|
+
# responsible for retaining elements they need. Both add and add? retain
|
|
15
|
+
# their usual set return values rather than returning the stored element.
|
|
16
|
+
#
|
|
17
|
+
# @example Tracking an object without keeping it alive
|
|
18
|
+
# resource = []
|
|
19
|
+
# set = Farce::WeakSet.new(mode: :make_shareable)
|
|
20
|
+
# set.add(resource)
|
|
21
|
+
# set.first.equal?(resource) # => true
|
|
22
|
+
# resource = nil
|
|
23
|
+
# # After collection, the set can become empty.
|
|
24
|
+
class WeakSet < Farce::Abstract::WeakSet
|
|
25
|
+
include Shareable::Delegated
|
|
26
|
+
|
|
27
|
+
# The default mode used to prepare elements for insertion.
|
|
28
|
+
# @return [Symbol] :raise, :make_shareable, or :dedup
|
|
29
|
+
def mode = @manager.mode
|
|
30
|
+
|
|
31
|
+
# (see Abstract::Set#include?)
|
|
32
|
+
def include?(element)
|
|
33
|
+
key = lookup_key(normalize_element(element))
|
|
34
|
+
!MISSING_KEY.equal?(key) && @map.key?(key)
|
|
35
|
+
end
|
|
36
|
+
alias member? include?
|
|
37
|
+
alias === include?
|
|
38
|
+
|
|
39
|
+
# (see Abstract::Set#delete)
|
|
40
|
+
def delete(element)
|
|
41
|
+
check_frozen!
|
|
42
|
+
key = lookup_key(normalize_element(element))
|
|
43
|
+
@map.delete(key) unless MISSING_KEY.equal?(key)
|
|
44
|
+
self
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# (see Abstract::Set#delete?)
|
|
48
|
+
def delete?(element) # rubocop:disable Naming/PredicateMethod
|
|
49
|
+
check_frozen!
|
|
50
|
+
key = lookup_key(normalize_element(element))
|
|
51
|
+
self unless MISSING_KEY.equal?(key) || !@map.delete(key)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
protected
|
|
55
|
+
|
|
56
|
+
# Canonical imports bypass normalization, but still prepare external elements.
|
|
57
|
+
def add_stored(key, value) = super(@manager.wrap(key), value)
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def initialize_value_mode(mode)
|
|
62
|
+
mode = :raise if UNDEFINED.equal?(mode)
|
|
63
|
+
@manager = Internal::WeakModeManager.new(mode:)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def add_normalized?(element, mode: UNDEFINED)
|
|
67
|
+
selected = UNDEFINED.equal?(mode) ? nil : mode
|
|
68
|
+
super(@manager.wrap(element, mode: selected))
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def lookup_key(element)
|
|
72
|
+
return element if Ractor.shareable?(element)
|
|
73
|
+
return MISSING_KEY if identity_membership?(element)
|
|
74
|
+
structural_key(element)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def new_map(entries = nil, **)
|
|
78
|
+
entries = entries&.map { |element, value| [@manager.wrap(element), value] }
|
|
79
|
+
Strict::WeakMap.new(entries, **)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
# A weak value is similar to a {WeakRef}, but does not delegate method calls to the referenced object.
|
|
7
|
+
# If a weak value is created for a shareable object, it will also be shareable.
|
|
8
|
+
# If {#freeze} is called, the referenced object will be made shareable (unless it has been garbage collected).
|
|
9
|
+
#
|
|
10
|
+
# @example
|
|
11
|
+
# object = Object.new
|
|
12
|
+
# weak = Farce::WeakValue.new(object)
|
|
13
|
+
# weak.value == object # => true
|
|
14
|
+
# weak.alive? # => true
|
|
15
|
+
#
|
|
16
|
+
# # Shareability traversal
|
|
17
|
+
# Ractor.shareable?(object) # => false
|
|
18
|
+
# Ractor.shareable?(weak) # => false
|
|
19
|
+
#
|
|
20
|
+
# Ractor.make_shareable(weak)
|
|
21
|
+
# Ractor.shareable?(weak) # => true
|
|
22
|
+
# Ractor.shareable?(object) # => true
|
|
23
|
+
#
|
|
24
|
+
# # lets assume that the object has been garbage collected
|
|
25
|
+
# object = nil
|
|
26
|
+
# GC.start
|
|
27
|
+
#
|
|
28
|
+
# weak.alive? # => false
|
|
29
|
+
# weak.value # WeakRefError: Invalid Reference - probably recycled
|
|
30
|
+
class WeakValue
|
|
31
|
+
include Internal::MarshalSupport::WeakValue
|
|
32
|
+
include Abstract::Value
|
|
33
|
+
include Internal::Inspect
|
|
34
|
+
|
|
35
|
+
MOVED = Object.new.freeze
|
|
36
|
+
private_constant :MOVED
|
|
37
|
+
|
|
38
|
+
nil_value = new
|
|
39
|
+
|
|
40
|
+
class << nil_value
|
|
41
|
+
undef marshal_dump
|
|
42
|
+
|
|
43
|
+
# @api private
|
|
44
|
+
def _dump(_) = "nil"
|
|
45
|
+
|
|
46
|
+
def dup = self
|
|
47
|
+
def clone(**) = self
|
|
48
|
+
def value = nil
|
|
49
|
+
def alive? = true
|
|
50
|
+
def moved? = false
|
|
51
|
+
def ractor_shareable? = true
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def _value = nil
|
|
56
|
+
def state_and_value = [:alive, nil]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
nil_value.instance_variable_set(:@mutex, nil)
|
|
60
|
+
|
|
61
|
+
NIL_VALUE = nil_value.freeze
|
|
62
|
+
private_constant :NIL_VALUE
|
|
63
|
+
|
|
64
|
+
recycled = new
|
|
65
|
+
class << recycled
|
|
66
|
+
undef marshal_dump
|
|
67
|
+
|
|
68
|
+
# @api private
|
|
69
|
+
def _dump(_) = "recycled"
|
|
70
|
+
|
|
71
|
+
def dup = self
|
|
72
|
+
def clone(**) = self
|
|
73
|
+
def alive? = false
|
|
74
|
+
def moved? = false
|
|
75
|
+
def ractor_shareable? = true
|
|
76
|
+
|
|
77
|
+
private
|
|
78
|
+
|
|
79
|
+
def _value = nil
|
|
80
|
+
def state_and_value = [:recycled, nil]
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# @api private
|
|
84
|
+
RECYCLED = recycled.freeze
|
|
85
|
+
|
|
86
|
+
# @param (see #initialize)
|
|
87
|
+
# @return [WeakValue] a new weak value wrapping the given object
|
|
88
|
+
# @see #initialize
|
|
89
|
+
def self.new(value) = value.nil? ? NIL_VALUE : super
|
|
90
|
+
|
|
91
|
+
# @api private
|
|
92
|
+
def self._load(state)
|
|
93
|
+
case state
|
|
94
|
+
when "nil" then NIL_VALUE
|
|
95
|
+
when "recycled" then RECYCLED
|
|
96
|
+
else raise TypeError, "invalid weak value state"
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# @param value [Object] the object to be weakly referenced
|
|
101
|
+
def initialize(value)
|
|
102
|
+
if Ractor.shareable?(value)
|
|
103
|
+
@atom = Strict::WeakAtom.new(value)
|
|
104
|
+
@mutex = nil
|
|
105
|
+
else
|
|
106
|
+
@atom = Unshared::WeakAtom.new(value)
|
|
107
|
+
@mutex = Mutex.new
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Checks whether the referenced object has avoided garbage collection and has not been moved.
|
|
112
|
+
# @return [Boolean] true if the weak value is still alive, false otherwise
|
|
113
|
+
def alive?
|
|
114
|
+
!_value.nil?
|
|
115
|
+
rescue Ractor::MovedError
|
|
116
|
+
false
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Freezes the weak value, making the referenced object shareable if it is still alive.
|
|
120
|
+
# Can be called after the value has been garbage collected or moved.
|
|
121
|
+
# Will raise however if the referenced object is still alive and cannot be made shareable.
|
|
122
|
+
# @return [self] the frozen weak value
|
|
123
|
+
def freeze
|
|
124
|
+
@mutex&.synchronize do
|
|
125
|
+
return self if frozen?
|
|
126
|
+
value = begin
|
|
127
|
+
Ractor.make_shareable(_value)
|
|
128
|
+
rescue Ractor::MovedError
|
|
129
|
+
MOVED
|
|
130
|
+
end
|
|
131
|
+
@atom = Strict::WeakAtom.new(value)
|
|
132
|
+
@mutex = nil
|
|
133
|
+
end
|
|
134
|
+
super
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Checks if the referenced object has been moved to another Ractor.
|
|
138
|
+
# @return [Boolean] true if the referenced object has been moved, false otherwise
|
|
139
|
+
def moved?
|
|
140
|
+
Ractor::MovedObject === _value
|
|
141
|
+
rescue Ractor::MovedError
|
|
142
|
+
true
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# @return [Boolean] true if the referenced object is shareable by Ractor, false otherwise
|
|
146
|
+
def ractor_shareable?
|
|
147
|
+
return false unless Ractor.shareable?(_value)
|
|
148
|
+
freeze && true
|
|
149
|
+
rescue Ractor::MovedError
|
|
150
|
+
freeze && true
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Retrieves the referenced object if it is still alive and has not been moved.
|
|
154
|
+
# Raises if it is no longer reachable.
|
|
155
|
+
# @return [BasicObject] the referenced object if it is still alive and has not been moved
|
|
156
|
+
# @raise [WeakRefError] if the referenced object is no longer reachable or has been moved
|
|
157
|
+
def value
|
|
158
|
+
value = _value
|
|
159
|
+
raise WeakRefError, "Invalid Reference - probably recycled" if value.nil?
|
|
160
|
+
value
|
|
161
|
+
rescue Ractor::MovedError
|
|
162
|
+
raise WeakRefError, "Invalid Reference - referenced object has been moved"
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# @api private
|
|
166
|
+
def inspect_with(inspector)
|
|
167
|
+
state, value = state_and_value
|
|
168
|
+
super do
|
|
169
|
+
inspector.attribute(:state, state)
|
|
170
|
+
inspector.attribute(:value, value) if state == :alive
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
private
|
|
175
|
+
|
|
176
|
+
def initialize_clone(other, freeze: nil)
|
|
177
|
+
super
|
|
178
|
+
self.freeze if freeze == true
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def _value
|
|
182
|
+
value = @atom.value
|
|
183
|
+
raise Ractor::MovedError, "referenced object has been moved" if MOVED.equal?(value)
|
|
184
|
+
value
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def state_and_value
|
|
188
|
+
value = _value
|
|
189
|
+
return :recycled if value.nil?
|
|
190
|
+
[:alive, value]
|
|
191
|
+
rescue Ractor::MovedError
|
|
192
|
+
:moved
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
# A Ractor-shareable concurrent map with strong shareable keys and weak values.
|
|
7
|
+
#
|
|
8
|
+
# Supported modes are `:raise` (the default), `:make_shareable`, and `:dedup`.
|
|
9
|
+
# Modes apply only to values. Keys must already be shareable.
|
|
10
|
+
# Entries disappear after a weakly held object is collected.
|
|
11
|
+
#
|
|
12
|
+
# With `:dedup`, retain the canonical result returned by store or update,
|
|
13
|
+
# as it might differ from the input and could be immediately collected.
|
|
14
|
+
# Assignment evaluates to the input rather than the canonical result.
|
|
15
|
+
#
|
|
16
|
+
# @example Publishing a value without retaining it strongly
|
|
17
|
+
# value = []
|
|
18
|
+
# map = Farce::WeakValueMap.new(mode: :make_shareable)
|
|
19
|
+
# map[:result] = value
|
|
20
|
+
# map[:result].equal?(value) # => true
|
|
21
|
+
class WeakValueMap < Farce::Abstract::WeakValueMap
|
|
22
|
+
include Internal::WeakMapValueModes
|
|
23
|
+
include Shareable::Delegated
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def new_map(**) = Internal::StrictWeakValueMap.new(**)
|
|
28
|
+
def freeze_backend = @map
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
Internal::KeyNormalizer.prepare_concurrent_class(Internal::StrictWeakValueMap)
|
|
32
|
+
end
|