farce 0.0.1.alpha2-x86-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,129 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
require "farce/internal/autoloads"
|
|
6
|
+
require "timeout"
|
|
7
|
+
|
|
8
|
+
experimental = Warning[:experimental]
|
|
9
|
+
|
|
10
|
+
# simplecov:disable
|
|
11
|
+
begin
|
|
12
|
+
Warning[:experimental] = false
|
|
13
|
+
IO::Buffer.new(0) if defined?(IO::Buffer)
|
|
14
|
+
Ractor.new {} if defined?(Ractor) # rubocop:disable Lint/EmptyBlock
|
|
15
|
+
ensure
|
|
16
|
+
Warning[:experimental] = experimental
|
|
17
|
+
end
|
|
18
|
+
# simplecov:enable
|
|
19
|
+
|
|
20
|
+
module Farce
|
|
21
|
+
# @!visibility private
|
|
22
|
+
module Internal # :nodoc: all
|
|
23
|
+
EMPTY_ARRAY = [].freeze
|
|
24
|
+
INTERRUPT_MASK = { Exception => :never }.freeze
|
|
25
|
+
MAP_KEEP = Object.new.freeze
|
|
26
|
+
MAP_DELETE = Object.new.freeze
|
|
27
|
+
|
|
28
|
+
# A non-main Ractor cannot call CONFIG.frozen if the main Ractor didn't do so before,
|
|
29
|
+
# as CONFIG is not shareable yet. We don't want to eagerly freeze it, otherwise a user can't change
|
|
30
|
+
# any configuration options after loading Farce.
|
|
31
|
+
#
|
|
32
|
+
# We can't do so via `Farce.on_main`, as creating the MainScheduler already needs the configuration.
|
|
33
|
+
# So we rely on the fact that autoloads run on the main Ractor.
|
|
34
|
+
autoload :FROZEN_CONFIG, "farce/internal/_frozen_config"
|
|
35
|
+
|
|
36
|
+
include Autoloads
|
|
37
|
+
extend self
|
|
38
|
+
|
|
39
|
+
# @api private
|
|
40
|
+
def marshal_protocol_method?(name) = MarshalSupport.protocol_method?(name)
|
|
41
|
+
|
|
42
|
+
# @api private
|
|
43
|
+
def marshal_shareable?(value) = Ractor.shareable?(value)
|
|
44
|
+
|
|
45
|
+
# Get the value from an options hash with only the `:self` key, and raise an error if there are any other keys.
|
|
46
|
+
def self_option(options, default = nil)
|
|
47
|
+
new_self = options.key?(:self) ? options.delete(:self) : (block_given? ? yield : default)
|
|
48
|
+
|
|
49
|
+
if options.any?
|
|
50
|
+
raise ArgumentError, "unknown keyword: #{options.keys.first.inspect}" if options.size == 1
|
|
51
|
+
raise ArgumentError, "unknown keywords: #{options.keys.map(&:inspect).join(", ")}"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
new_self
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def timeout_deadline(timeout)
|
|
58
|
+
return if timeout.nil?
|
|
59
|
+
|
|
60
|
+
timeout = Float(timeout)
|
|
61
|
+
unless timeout.finite? && !timeout.negative?
|
|
62
|
+
raise ArgumentError, "timeout must be a finite, non-negative number or nil"
|
|
63
|
+
end
|
|
64
|
+
Clock.now + timeout
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def remaining_timeout(deadline)
|
|
68
|
+
return unless deadline
|
|
69
|
+
remaining = deadline - Clock.now
|
|
70
|
+
remaining.negative? ? 0 : remaining
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Repeat with one timeout budget. Even a zero timeout permits the first check.
|
|
74
|
+
def with_timeout(timeout)
|
|
75
|
+
raise LocalJumpError, "no block given" unless block_given?
|
|
76
|
+
deadline = timeout_deadline(timeout)
|
|
77
|
+
loop do
|
|
78
|
+
yield remaining_timeout(deadline), deadline
|
|
79
|
+
return if deadline && Clock.now >= deadline
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def wait_until(receiver, *keys, timeout: nil)
|
|
84
|
+
raise LocalJumpError, "no block given" unless block_given?
|
|
85
|
+
with_timeout(timeout) do |_, deadline|
|
|
86
|
+
current = keys.empty? ? receiver.value : receiver[*keys]
|
|
87
|
+
return current if yield(current)
|
|
88
|
+
receiver.wait_until_changed(*keys, current, timeout: remaining_timeout(deadline)) { return }
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def garbage_collectable?(object)
|
|
93
|
+
case object
|
|
94
|
+
when Integer, Float, Complex, Rational, Symbol, true, false, nil then false
|
|
95
|
+
else true
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def walker_constants(object, inherit) = object.constants(inherit)
|
|
100
|
+
def storage_thread(thread) = thread
|
|
101
|
+
def prepare_mutable_numeric(_) = nil
|
|
102
|
+
def prepare_map_access(_klass, _kind) = nil
|
|
103
|
+
def finalize_engine = nil
|
|
104
|
+
|
|
105
|
+
def delegate(from, to, *methods)
|
|
106
|
+
methods.each do |method|
|
|
107
|
+
if to.is_a?(Module)
|
|
108
|
+
name = to.name
|
|
109
|
+
const = Object.const_get(name, false) if name && Object.const_defined?(name, false)
|
|
110
|
+
to = "::#{name}" if const.equal?(to)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
if to.is_a?(String) || to.is_a?(Symbol)
|
|
114
|
+
from.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
115
|
+
# simplecov:disable
|
|
116
|
+
def #{method}(...)
|
|
117
|
+
#{to}.#{method}(...)
|
|
118
|
+
end
|
|
119
|
+
# simplecov:enable
|
|
120
|
+
RUBY
|
|
121
|
+
else
|
|
122
|
+
from.define_method(method) do |*args, **kwargs, &block|
|
|
123
|
+
to.send(method, *args, **kwargs, &block)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
data/lib/farce/lazy.rb
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
# A ractor-shareable lazy value that is computed on demand.
|
|
7
|
+
# The factory runs once. Its result is transferred according to {#mode}.
|
|
8
|
+
# With the default `:copy` mode, each Ractor receives its own cached copy.
|
|
9
|
+
# The factory and its bound receiver must remain Ractor-shareable.
|
|
10
|
+
# Use {Strict::Lazy} for direct shareable results or {Unshared::Lazy} for local factories.
|
|
11
|
+
#
|
|
12
|
+
# You can use it to make the following, common Ruby idiom ractor-safe:
|
|
13
|
+
#
|
|
14
|
+
# ```ruby
|
|
15
|
+
# class MyClass
|
|
16
|
+
# def expensive_attribute = @expensive_attribute ||= compute_expensive_attribute
|
|
17
|
+
#
|
|
18
|
+
# private
|
|
19
|
+
#
|
|
20
|
+
# def compute_expensive_attribute
|
|
21
|
+
# sleep 0.5 # pretend like we're working
|
|
22
|
+
# 42
|
|
23
|
+
# end
|
|
24
|
+
# end
|
|
25
|
+
#
|
|
26
|
+
# # this will freeze the object without the expensive attribute being computed
|
|
27
|
+
# object = Ractor.make_shareable(MyClass.new)
|
|
28
|
+
#
|
|
29
|
+
# # this will fail
|
|
30
|
+
# Ractor.new(object) { it.expensive_attribute }
|
|
31
|
+
#
|
|
32
|
+
#
|
|
33
|
+
# object = MyClass.new
|
|
34
|
+
#
|
|
35
|
+
# # this will work, but compute the expensive attribute five times, and also deep-copy any other
|
|
36
|
+
# # unshareable data the object might hold
|
|
37
|
+
# 5.times { Ractor.new(object) { it.expensive_attribute } }
|
|
38
|
+
# ```
|
|
39
|
+
#
|
|
40
|
+
# You can use `Farce::Lazy` to make expensive attributes ractor-safe:
|
|
41
|
+
#
|
|
42
|
+
# ```ruby
|
|
43
|
+
# class MyClass
|
|
44
|
+
# include Farce::Shareable
|
|
45
|
+
#
|
|
46
|
+
# def initialize
|
|
47
|
+
# @expensive_attribute = Farce::Lazy.new do
|
|
48
|
+
# sleep 0.5 # pretend like we're working
|
|
49
|
+
# 42
|
|
50
|
+
# end
|
|
51
|
+
# super
|
|
52
|
+
# end
|
|
53
|
+
#
|
|
54
|
+
# def expensive_attribute = @expensive_attribute.value
|
|
55
|
+
# end
|
|
56
|
+
#
|
|
57
|
+
# object = MyClass.new
|
|
58
|
+
#
|
|
59
|
+
# # Will only compute the expensive attribute once, and return the same value to all Ractors.
|
|
60
|
+
# 5.times { Ractor.new(object) { it.expensive_attribute } }
|
|
61
|
+
# ```
|
|
62
|
+
class Lazy < Farce::Abstract::Lazy
|
|
63
|
+
include Shareable::Tracked
|
|
64
|
+
|
|
65
|
+
# @!macro modes
|
|
66
|
+
# @overload initialize(factory, mode: :copy)
|
|
67
|
+
# @param factory [Class, Proc, #call] the shareable factory for the value
|
|
68
|
+
# @param mode [Symbol] the transfer mode for the computed result
|
|
69
|
+
# @overload initialize(mode: :copy, self: nil)
|
|
70
|
+
# @param mode [Symbol] the transfer mode for the computed result
|
|
71
|
+
# @param self [BasicObject] the shareable receiver to bind to the block
|
|
72
|
+
# @yield computes the value on first access
|
|
73
|
+
# @yieldreturn [BasicObject] the result to transfer
|
|
74
|
+
def initialize(factory = nil, mode: :copy, **, &)
|
|
75
|
+
@manager = marshal_mode_manager(mode)
|
|
76
|
+
super(factory, **, &)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# @return [Symbol] the transfer mode for the computed result
|
|
80
|
+
def mode = @manager.mode
|
|
81
|
+
|
|
82
|
+
# Compute once and return the result according to the configured transfer mode.
|
|
83
|
+
# Repeated reads return the same value within the current Ractor.
|
|
84
|
+
# @return [BasicObject] the computed result
|
|
85
|
+
def value = @manager.unwrap(super)
|
|
86
|
+
|
|
87
|
+
# Resolve the slot before freezing it. This does not freeze the result.
|
|
88
|
+
# @return [self]
|
|
89
|
+
def freeze
|
|
90
|
+
value
|
|
91
|
+
internal_atom.freeze
|
|
92
|
+
super
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
private
|
|
96
|
+
|
|
97
|
+
def compute_value = @manager.wrap(super)
|
|
98
|
+
def display_value(inspector) = super(inspector, @manager)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
# @!parse
|
|
7
|
+
# # A {Reference} for a {Lazy} value.
|
|
8
|
+
# #
|
|
9
|
+
# # Results use the lazy value's transfer mode, which defaults to `:copy`.
|
|
10
|
+
# #
|
|
11
|
+
# # Calling `freeze` resolves and freezes the target. Checking `frozen?` before
|
|
12
|
+
# # the first successful freeze does not resolve it.
|
|
13
|
+
# #
|
|
14
|
+
# # @example
|
|
15
|
+
# # initialized = Farce::Counter.new
|
|
16
|
+
# #
|
|
17
|
+
# # lazy_ref = Farce::LazyRef.new do
|
|
18
|
+
# # initialized.increment
|
|
19
|
+
# # Farce::Map.new
|
|
20
|
+
# # end
|
|
21
|
+
# #
|
|
22
|
+
# # initialized.value # => 0
|
|
23
|
+
# # lazy_ref[:key] = :value
|
|
24
|
+
# # initialized.value # => 1
|
|
25
|
+
# class LazyRef < Farce::Reference
|
|
26
|
+
# # @!macro modes
|
|
27
|
+
# # @overload initialize(factory, mode: :copy)
|
|
28
|
+
# # @param mode [Symbol] the transfer mode for the computed result
|
|
29
|
+
# # @param [Class, Proc, #call] factory The factory to use for creating the value. Must be ractor-shareable.
|
|
30
|
+
# #
|
|
31
|
+
# # @overload initialize(self: nil, mode: :copy)
|
|
32
|
+
# # @param mode [Symbol] the transfer mode for the computed result
|
|
33
|
+
# # @yield The block to use for creating the value. Must be ractor-shareable.
|
|
34
|
+
# # @yieldreceiver [BasicObject] The `self` parameter provided, or `nil` if not provided.
|
|
35
|
+
# # @yieldreturn [BasicObject] The value to be returned by the lazy instance.
|
|
36
|
+
# # @param [BasicObject] self The `self` parameter to be provided to the block. Must be ractor-shareable.
|
|
37
|
+
# def initialize(...) = nil
|
|
38
|
+
# end
|
|
39
|
+
LazyRef = Reference[Lazy]
|
|
40
|
+
end
|
data/lib/farce/lease.rb
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
# A Ractor-shareable lease that moves one resource on checkout and checkin.
|
|
7
|
+
#
|
|
8
|
+
# @example Reusing an object across Ractors
|
|
9
|
+
# lease = Farce::Lease.new { [] }
|
|
10
|
+
# finished = Farce::Port.new
|
|
11
|
+
# Farce::Ractor.new(lease, finished) do |shared, result|
|
|
12
|
+
# size = shared.checkout do |items|
|
|
13
|
+
# items << :processed
|
|
14
|
+
# items.length
|
|
15
|
+
# end
|
|
16
|
+
# result << size
|
|
17
|
+
# end
|
|
18
|
+
#
|
|
19
|
+
# finished.receive # => 1
|
|
20
|
+
# lease.checkout { |items| items.dup } # => [:processed]
|
|
21
|
+
class Lease < Farce::Abstract::Lease
|
|
22
|
+
include Shareable::Unfreezable
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def new_internal_lease(resource) = Internal::Lease.new(resource)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
# A Ractor-shareable map that moves each resource on checkout and checkin.
|
|
7
|
+
#
|
|
8
|
+
# @example Updating independently leased resources
|
|
9
|
+
# leases = Farce::LeaseMap.new { { primary: [], replica: [] } }
|
|
10
|
+
# leases.checkout(:primary) { |items| items << :updated }
|
|
11
|
+
# leases.checkout(:primary, &:dup) # => [:updated]
|
|
12
|
+
#
|
|
13
|
+
# @example Automatically checking out resources as they are accessed
|
|
14
|
+
# leases = Farce::LeaseMap.new { { primary: [], replica: [] } }
|
|
15
|
+
#
|
|
16
|
+
# leases.auto_lease do
|
|
17
|
+
# leases[:primary] << :updated
|
|
18
|
+
# leases[:replica] << :replicated
|
|
19
|
+
# leases[:primary] << :verified # Reuses the same checkout
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
# # Both resources are checked back in when the block exits, even on an exception.
|
|
23
|
+
# leases.available?(:primary) # => true
|
|
24
|
+
# leases.checkout(:primary, &:dup) # => [:updated, :verified]
|
|
25
|
+
class LeaseMap < Farce::Abstract::LeaseMap
|
|
26
|
+
include Shareable::Unfreezable
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def new_internal_lease_map(mapping)
|
|
31
|
+
Internal::LeaseMap.new(mapping, lease_class: Farce::Lease, registry_class: Farce::Map)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
# A Ractor-shareable pool that moves resources on checkout and checkin.
|
|
7
|
+
#
|
|
8
|
+
# @example Reusing an object across Ractors
|
|
9
|
+
# pool = Farce::LeasePool.new(max_size: 2) { [] }
|
|
10
|
+
# result = Farce::Ractor.new(pool) do |shared|
|
|
11
|
+
# shared.checkout do |items|
|
|
12
|
+
# items << :worker
|
|
13
|
+
# items.length
|
|
14
|
+
# end
|
|
15
|
+
# end.value
|
|
16
|
+
#
|
|
17
|
+
# result # => 1
|
|
18
|
+
class LeasePool < Farce::Abstract::LeasePool
|
|
19
|
+
include Shareable::Unfreezable
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def prepare_factory(factory)
|
|
24
|
+
Ractor.shareable?(factory) ? factory : Ractor.shareable_proc(&factory)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def new_internal_pool(max_size) = Internal::LeasePool.new(max_size)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
# A Ractor-shareable bounded map that evicts the least frequently used entry.
|
|
7
|
+
# Equal-frequency victims are selected by recency. Transfer modes apply to values.
|
|
8
|
+
# Individual reads and writes increment frequency. Observation does not.
|
|
9
|
+
class LFUMap < Farce::Abstract::LFUMap
|
|
10
|
+
include Shareable::Delegated
|
|
11
|
+
|
|
12
|
+
# @!macro modes
|
|
13
|
+
# @param entries [Hash, Array<Array(BasicObject, BasicObject)>, Abstract::Map, #each, nil]
|
|
14
|
+
# Optional initial entries. Entries are stored sequentially and may be evicted.
|
|
15
|
+
# @param mode [Symbol] The default value transfer mode.
|
|
16
|
+
def initialize(entries = nil, mode: :copy, **)
|
|
17
|
+
@manager = marshal_mode_manager(mode)
|
|
18
|
+
super(entries, **)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# The default transfer mode for values.
|
|
22
|
+
# @return [Symbol]
|
|
23
|
+
def mode = @manager.mode
|
|
24
|
+
|
|
25
|
+
# Keys must be shareable, except equality-mode strings that can be snapshotted.
|
|
26
|
+
# @return [true]
|
|
27
|
+
def shareable_keys? = true
|
|
28
|
+
|
|
29
|
+
# Values are stored in Ractor-shareable representations.
|
|
30
|
+
# @return [true]
|
|
31
|
+
def shareable_values? = true
|
|
32
|
+
|
|
33
|
+
protected
|
|
34
|
+
|
|
35
|
+
def unwrap_value(value) = @manager.unwrap(value)
|
|
36
|
+
|
|
37
|
+
def wrap_value(value)
|
|
38
|
+
check_frozen!
|
|
39
|
+
@manager.wrap(value)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def each_for_inspect(&) = internal_map.each(&)
|
|
45
|
+
def inspect_value(inspector, value) = super(inspector, value, @manager)
|
|
46
|
+
def new_bounded_map(...) = Internal::StrictLFUMap.new(...)
|
|
47
|
+
def freeze_backend = internal_map
|
|
48
|
+
|
|
49
|
+
def new_key_locks(compare_keys_by_identity:)
|
|
50
|
+
Internal::KeyLockMap.new(registry_class: Farce::Strict::Map, compare_keys_by_identity:)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Local
|
|
7
|
+
# A shareable atomic reference with an independent mutable value in each scope.
|
|
8
|
+
#
|
|
9
|
+
# @!method initialize(value = nil, compare_by_identity: false, scope: :ractor)
|
|
10
|
+
# @!macro scopes
|
|
11
|
+
# @param value [BasicObject, nil] the initial value
|
|
12
|
+
# @param compare_by_identity [Boolean] whether comparisons use object identity instead of equality
|
|
13
|
+
# @param scope [Symbol] the scope of the atomic reference
|
|
14
|
+
# @return [Atom]
|
|
15
|
+
class Atom < Abstract::Atom
|
|
16
|
+
include Shareable::Tracked
|
|
17
|
+
include Scoped::Tracked
|
|
18
|
+
|
|
19
|
+
protected def internal_atom = scoped_value
|
|
20
|
+
private def new_scoped_value(...) = Internal::UnsharedAtom.new(...)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Local
|
|
7
|
+
# A shareable atomic counter with an independent value in each scope.
|
|
8
|
+
# Each scope starts at the initial integer. Reset affects only the current scope.
|
|
9
|
+
class Counter < Numeric
|
|
10
|
+
include Abstract::Counter
|
|
11
|
+
include Shareable::Tracked
|
|
12
|
+
include Scoped::Tracked
|
|
13
|
+
|
|
14
|
+
# The initial value used for new scopes and by {#reset}.
|
|
15
|
+
# @return [Integer]
|
|
16
|
+
attr_reader :initial
|
|
17
|
+
|
|
18
|
+
# @!macro scopes
|
|
19
|
+
# @param value [Numeric, String, #to_int] the initial value, converted to an Integer
|
|
20
|
+
# @param scope [Symbol] the scope of the counter
|
|
21
|
+
def initialize(value = 0, scope: :ractor)
|
|
22
|
+
raise FrozenError.new("can't initialize a frozen counter", receiver: self) if frozen?
|
|
23
|
+
@initial = Integer(value)
|
|
24
|
+
super(@initial, scope:)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Return the current integer value.
|
|
28
|
+
# @return [Integer]
|
|
29
|
+
def value = internal_counter.value
|
|
30
|
+
|
|
31
|
+
alias get value
|
|
32
|
+
|
|
33
|
+
# Store an integer value.
|
|
34
|
+
# @param value [Integer] the replacement value
|
|
35
|
+
# @return [Integer] the stored value
|
|
36
|
+
def store(value) = internal_counter.store(value)
|
|
37
|
+
|
|
38
|
+
alias value= store
|
|
39
|
+
|
|
40
|
+
# Replace the value and return the previous integer.
|
|
41
|
+
# @param value [Integer] the replacement value
|
|
42
|
+
# @return [Integer]
|
|
43
|
+
def swap(value) = internal_counter.swap(value)
|
|
44
|
+
|
|
45
|
+
# Replace the value atomically if it matches the expected integer.
|
|
46
|
+
# @param expected [Integer] the expected value
|
|
47
|
+
# @param replacement [Integer] the replacement value
|
|
48
|
+
# @return [Boolean] whether the value changed
|
|
49
|
+
def compare_and_set(expected, replacement) = internal_counter.compare_and_set(expected, replacement)
|
|
50
|
+
|
|
51
|
+
# Increment the counter atomically.
|
|
52
|
+
# @param by [Numeric, String, #to_int] the amount, converted to an Integer
|
|
53
|
+
# @return [self]
|
|
54
|
+
def increment(by = 1)
|
|
55
|
+
internal_counter.increment(by)
|
|
56
|
+
self
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Decrement the counter atomically.
|
|
60
|
+
# @param by [Numeric, String, #to_int] the amount, converted to an Integer
|
|
61
|
+
# @return [self]
|
|
62
|
+
def decrement(by = 1)
|
|
63
|
+
internal_counter.decrement(by)
|
|
64
|
+
self
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
alias subtract decrement
|
|
68
|
+
alias remove decrement
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def marshal_initialize(arguments, options, configuration)
|
|
73
|
+
@initial = Integer(arguments.first)
|
|
74
|
+
super
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def initialize_copy(other)
|
|
78
|
+
# Numeric#initialize_copy cannot copy mutable Numeric subclasses on JRuby.
|
|
79
|
+
@farce_freeze_state = Internal::Flag.new(false)
|
|
80
|
+
Internal::Storage.scope(scope)[self] = Internal::Counter.new(other.value)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def change_signal = internal_counter.change_signal
|
|
84
|
+
def internal_counter = scoped_value
|
|
85
|
+
def new_scoped_value(...) = Internal::Counter.new(...)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Local
|
|
7
|
+
# A shareable atomic boolean with an independent value in each scope.
|
|
8
|
+
# Only true and false are accepted. Read {#value} to test its state.
|
|
9
|
+
class Flag
|
|
10
|
+
include Abstract::Flag
|
|
11
|
+
include Shareable::Tracked
|
|
12
|
+
include Scoped::Tracked
|
|
13
|
+
|
|
14
|
+
# @!method initialize(value = false, scope: :ractor)
|
|
15
|
+
# @!macro scopes
|
|
16
|
+
# @param value [Boolean] the initial value
|
|
17
|
+
# @param scope [Symbol] the scope of the flag
|
|
18
|
+
# @raise [ArgumentError] if the value is not true or false
|
|
19
|
+
|
|
20
|
+
# @return [Boolean] the current value
|
|
21
|
+
def value = scoped_value.value
|
|
22
|
+
|
|
23
|
+
alias get value
|
|
24
|
+
|
|
25
|
+
# Set the flag to true.
|
|
26
|
+
# @return [true]
|
|
27
|
+
def set = scoped_value.set
|
|
28
|
+
|
|
29
|
+
# Set the flag to false.
|
|
30
|
+
# @return [false]
|
|
31
|
+
def unset = scoped_value.unset
|
|
32
|
+
|
|
33
|
+
# Store a boolean value.
|
|
34
|
+
# @param value [Boolean] the new value
|
|
35
|
+
# @return [Boolean] the new value
|
|
36
|
+
def store(value) = scoped_value.store(value)
|
|
37
|
+
|
|
38
|
+
alias value= store
|
|
39
|
+
|
|
40
|
+
# Replace the value and return its previous state.
|
|
41
|
+
# @param value [Boolean] the new value
|
|
42
|
+
# @return [Boolean] the previous value
|
|
43
|
+
def swap(value) = scoped_value.swap(value)
|
|
44
|
+
|
|
45
|
+
# Replace the value atomically if it matches the expected boolean.
|
|
46
|
+
# @param expected [Boolean] the expected value
|
|
47
|
+
# @param replacement [Boolean] the replacement value
|
|
48
|
+
# @return [Boolean] whether the value changed
|
|
49
|
+
def compare_and_set(expected, replacement) = scoped_value.compare_and_set(expected, replacement)
|
|
50
|
+
|
|
51
|
+
# Atomically invert the value.
|
|
52
|
+
# @return [Boolean] the new value
|
|
53
|
+
def toggle = scoped_value.toggle
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
def initialize_copy(other)
|
|
58
|
+
super
|
|
59
|
+
Internal::Storage.scope(scope)[self] = Internal::Flag.new(other.value)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def new_scoped_value(...) = Internal::Flag.new(...)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Local
|
|
7
|
+
# A shareable lazy value computed once per scope. Results may be mutable.
|
|
8
|
+
class Lazy < Abstract::Lazy
|
|
9
|
+
include Shareable::Unfreezable
|
|
10
|
+
include Scoped
|
|
11
|
+
|
|
12
|
+
# @!macro scopes
|
|
13
|
+
# @overload initialize(factory, scope: :ractor)
|
|
14
|
+
# @param factory [Class, Proc, #call] a shareable factory for each scope's value
|
|
15
|
+
# @param scope [Symbol] the scope of the lazy value
|
|
16
|
+
# @overload initialize(scope: :ractor, self: nil)
|
|
17
|
+
# @param scope [Symbol] the scope of the lazy value
|
|
18
|
+
# @param self [BasicObject] the shareable receiver to bind to the block
|
|
19
|
+
# @yield computes the value on first access in each scope
|
|
20
|
+
# @yieldreceiver [BasicObject] the self parameter, or nil if omitted
|
|
21
|
+
# @yieldreturn [BasicObject] the initial value for the scope, which may be mutable
|
|
22
|
+
# @return [Lazy]
|
|
23
|
+
def initialize(factory = nil, scope: :ractor, **, &)
|
|
24
|
+
@factory = prepare_factory(factory, **, &)
|
|
25
|
+
@state_key = Object.new.freeze
|
|
26
|
+
super(scope:)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def marshal_current_value = Internal::Storage.scope(scope)[@state_key]&.value
|
|
32
|
+
|
|
33
|
+
def eager_scoped_value? = false
|
|
34
|
+
def internal_atom = Internal::Storage.store_if_absent(@state_key, scope:) { new_scoped_value }
|
|
35
|
+
def new_scoped_value = Internal::UnsharedAtom.new
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Local
|
|
7
|
+
# @!parse
|
|
8
|
+
# # A {Reference} for a {Lazy Local::Lazy} value.
|
|
9
|
+
# # Freezing affects the current scope's target. Afterward, `frozen?` reflects
|
|
10
|
+
# # the current target and may initialize it when entering another scope.
|
|
11
|
+
# #
|
|
12
|
+
# # @example
|
|
13
|
+
# # # Delegate to a Ractor-local hash
|
|
14
|
+
# # lazy_ref = Farce::Local::LazyRef.new { {} }
|
|
15
|
+
# #
|
|
16
|
+
# # lazy_ref[:key] = :value
|
|
17
|
+
# # lazy_ref[:key] # => :value
|
|
18
|
+
# #
|
|
19
|
+
# # Ractor.new(lazy_ref) do |lazy_ref|
|
|
20
|
+
# # lazy_ref[:key] # => nil
|
|
21
|
+
# # end
|
|
22
|
+
# class LazyRef < Farce::Reference
|
|
23
|
+
# # @overload initialize(factory, scope: :ractor)
|
|
24
|
+
# # @param [Class, Proc, #call] factory The factory to use for creating the value. Must be ractor-shareable.
|
|
25
|
+
# # @param scope [Symbol] the scope of the lazy value
|
|
26
|
+
# #
|
|
27
|
+
# # @overload initialize(self: nil, scope: :ractor)
|
|
28
|
+
# # @yield The block to use for creating the value. Must be ractor-shareable.
|
|
29
|
+
# # @yieldreceiver [BasicObject] The `self` parameter provided, or `nil` if not provided.
|
|
30
|
+
# # @yieldreturn [BasicObject] The value to be returned by the lazy instance.
|
|
31
|
+
# # @param [BasicObject] self The `self` parameter to be provided to the block. Must be ractor-shareable.
|
|
32
|
+
# # @param scope [Symbol] the scope of the lazy value
|
|
33
|
+
# end
|
|
34
|
+
LazyRef = Reference[Farce::Local::Lazy]
|
|
35
|
+
end
|
|
36
|
+
end
|