farce 0 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/CODE_OF_CONDUCT.md +26 -0
- data/CONTRIBUTING.md +71 -0
- data/MIT-LICENSE +20 -0
- data/README.md +1525 -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/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 +435 -8
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Local
|
|
7
|
+
# A shareable lease with one independently initialized resource in each scope.
|
|
8
|
+
#
|
|
9
|
+
# @example Keeping an independent object in each Fiber
|
|
10
|
+
# lease = Farce::Local::Lease.new(scope: :fiber) { { name: :initial } }
|
|
11
|
+
# lease.checkout { |state| state[:name] = :parent }
|
|
12
|
+
#
|
|
13
|
+
# Fiber.new do
|
|
14
|
+
# lease.checkout { |state| state[:name] = :child }
|
|
15
|
+
# end.resume # => :child
|
|
16
|
+
#
|
|
17
|
+
# lease.checkout { |state| state[:name] } # => :parent
|
|
18
|
+
class Lease < Abstract::Lease
|
|
19
|
+
include Shareable::Unfreezable
|
|
20
|
+
include Scoped
|
|
21
|
+
|
|
22
|
+
# Create a lease that initializes once on first use in each scope.
|
|
23
|
+
# @!macro scopes
|
|
24
|
+
# @param scope [Symbol] the scope of the lease
|
|
25
|
+
# @yield builds the resource for each initialized scope
|
|
26
|
+
# @yieldreturn [BasicObject] the initial resource for that scope
|
|
27
|
+
def initialize(scope: :ractor, &initializer)
|
|
28
|
+
raise ArgumentError, "a resource constructor block is required" unless initializer
|
|
29
|
+
|
|
30
|
+
@initializer = Ractor.shareable?(initializer) ? initializer : Ractor.shareable_proc(&initializer)
|
|
31
|
+
super(scope:)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# (see Farce::Abstract::Lease#checkout)
|
|
35
|
+
def checkout(timeout: nil, &block)
|
|
36
|
+
deadline = timeout_deadline(timeout)
|
|
37
|
+
lease = scoped_lease(timeout: remaining_timeout(deadline))
|
|
38
|
+
raise TimeoutError, "lease checkout timed out" unless lease
|
|
39
|
+
|
|
40
|
+
timeout = remaining_timeout(deadline)
|
|
41
|
+
block ? lease.checkout(timeout:, &block) : lease.checkout(timeout:)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# (see Farce::Abstract::Lease#try_checkout)
|
|
45
|
+
def try_checkout(&block)
|
|
46
|
+
lease = scoped_lease(wait: false)
|
|
47
|
+
return unless lease
|
|
48
|
+
|
|
49
|
+
block ? lease.try_checkout(&block) : lease.try_checkout
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def eager_scoped_value? = false
|
|
55
|
+
def new_scoped_value = Internal::LeaseInitialization.new
|
|
56
|
+
def internal_lease = scoped_lease
|
|
57
|
+
def scoped_lease(**) = scoped_value.fetch(**) { Internal::UnsharedLease.new(@initializer.call) }
|
|
58
|
+
|
|
59
|
+
def timeout_deadline(timeout)
|
|
60
|
+
return if timeout.nil?
|
|
61
|
+
|
|
62
|
+
timeout = Float(timeout)
|
|
63
|
+
unless timeout.finite? && !timeout.negative?
|
|
64
|
+
raise ArgumentError, "timeout must be a finite, non-negative number or nil"
|
|
65
|
+
end
|
|
66
|
+
Clock.now + timeout
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def remaining_timeout(deadline)
|
|
70
|
+
return unless deadline
|
|
71
|
+
|
|
72
|
+
remaining = deadline - Clock.now
|
|
73
|
+
remaining.positive? ? remaining : 0
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Local
|
|
7
|
+
# A shareable lease map with independently initialized resources in each scope.
|
|
8
|
+
#
|
|
9
|
+
# @example Keeping independent resources in each Fiber
|
|
10
|
+
# leases = Farce::Local::LeaseMap.new(scope: :fiber) { { jobs: [] } }
|
|
11
|
+
# leases.checkout(:jobs) { |jobs| jobs << :parent }
|
|
12
|
+
# Fiber.new { leases.checkout(:jobs, &:dup) }.resume # => []
|
|
13
|
+
# leases.checkout(:jobs, &:dup) # => [:parent]
|
|
14
|
+
class LeaseMap < Abstract::LeaseMap
|
|
15
|
+
include Shareable::Unfreezable
|
|
16
|
+
include Scoped
|
|
17
|
+
|
|
18
|
+
# Create a map that initializes once on first use in each scope.
|
|
19
|
+
# @!macro scopes
|
|
20
|
+
# @param scope [Symbol] the scope of the lease map
|
|
21
|
+
# @yield builds the initial mapping for each initialized scope
|
|
22
|
+
# @yieldreturn [Hash, Farce::Abstract::Map, #each] the initial mapping for that scope
|
|
23
|
+
def initialize(scope: :ractor, normalize_keys: nil, &initializer)
|
|
24
|
+
raise ArgumentError, "a resource constructor block is required" unless initializer
|
|
25
|
+
|
|
26
|
+
@initializer = Ractor.shareable?(initializer) ? initializer : Ractor.shareable_proc(&initializer)
|
|
27
|
+
super(scope:, normalize_keys:)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def eager_scoped_value? = false
|
|
33
|
+
def new_scoped_value = Internal::LeaseInitialization.new
|
|
34
|
+
def internal_lease_map = scoped_lease_map
|
|
35
|
+
|
|
36
|
+
def checkout_canonical(key, missing_key:, timeout: nil, &)
|
|
37
|
+
deadline = timeout_deadline(timeout)
|
|
38
|
+
map = scoped_lease_map(timeout: remaining_timeout(deadline))
|
|
39
|
+
raise TimeoutError, "lease checkout timed out" unless map
|
|
40
|
+
|
|
41
|
+
map.checkout(key, timeout: remaining_timeout(deadline), receiver: self, missing_key:, &)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def try_checkout_canonical(key, missing_key:, &)
|
|
45
|
+
map = scoped_lease_map(wait: false)
|
|
46
|
+
return unless map
|
|
47
|
+
|
|
48
|
+
map.try_checkout(key, receiver: self, missing_key:, &)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def scoped_lease_map(**)
|
|
52
|
+
scoped_value.fetch(**) do
|
|
53
|
+
mapping = prepare_initial_resources(@initializer.call, @key_normalizer)
|
|
54
|
+
Internal::LeaseMap.new(
|
|
55
|
+
mapping,
|
|
56
|
+
lease_class: Farce::Unshared::Lease,
|
|
57
|
+
registry_class: Farce::Unshared::Map,
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def timeout_deadline(timeout)
|
|
63
|
+
return if timeout.nil?
|
|
64
|
+
|
|
65
|
+
timeout = Float(timeout)
|
|
66
|
+
unless timeout.finite? && !timeout.negative?
|
|
67
|
+
raise ArgumentError, "timeout must be a finite, non-negative number or nil"
|
|
68
|
+
end
|
|
69
|
+
Clock.now + timeout
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def remaining_timeout(deadline)
|
|
73
|
+
return unless deadline
|
|
74
|
+
|
|
75
|
+
remaining = deadline - Clock.now
|
|
76
|
+
remaining.positive? ? remaining : 0
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
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 pool with independent capacity and resources in each scope.
|
|
8
|
+
#
|
|
9
|
+
# @example Keeping separate pools in each Fiber
|
|
10
|
+
# pool = Farce::Local::LeasePool.new(scope: :fiber, max_size: 1) { [] }
|
|
11
|
+
# pool.checkout { |items| items << :parent }
|
|
12
|
+
#
|
|
13
|
+
# Fiber.new { pool.checkout(&:dup) }.resume # => []
|
|
14
|
+
# pool.checkout(&:dup) # => [:parent]
|
|
15
|
+
class LeasePool < Abstract::LeasePool
|
|
16
|
+
include Shareable::Unfreezable
|
|
17
|
+
include Scoped
|
|
18
|
+
|
|
19
|
+
# Construct an empty pool in each scope.
|
|
20
|
+
# @!macro scopes
|
|
21
|
+
# @param scope [Symbol] the scope of the pool
|
|
22
|
+
# @param max_size [Integer] the maximum number of resources in each scope
|
|
23
|
+
# @yield builds a resource in the requesting scope
|
|
24
|
+
# @yieldreturn [BasicObject] a new resource
|
|
25
|
+
def initialize(max_size:, scope: :ractor, &factory)
|
|
26
|
+
validate_configuration!(max_size, factory)
|
|
27
|
+
@max_size = max_size
|
|
28
|
+
@factory = Ractor.shareable?(factory) ? factory : Ractor.shareable_proc(&factory)
|
|
29
|
+
super(scope:, max_size:)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def new_scoped_value(max_size:) = Internal::UnsharedLeasePool.new(max_size)
|
|
35
|
+
def internal_pool = scoped_value
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Local
|
|
7
|
+
# A shareable LFU map with independent mutable storage and capacity in each scope.
|
|
8
|
+
#
|
|
9
|
+
# @!method initialize(entries = nil, max_size:, scope: :ractor, **options)
|
|
10
|
+
# @!macro scopes
|
|
11
|
+
# @param entries [Hash, Array<Array(BasicObject, BasicObject)>, Abstract::Map, #each, nil]
|
|
12
|
+
# Initial entries for each new scope. Entries are stored sequentially and may be evicted.
|
|
13
|
+
# @param max_size [Integer] Maximum entries retained by each new scoped map.
|
|
14
|
+
# @param scope [Symbol] The scope of the LFU map.
|
|
15
|
+
# @return [LFUMap]
|
|
16
|
+
class LFUMap < Abstract::LFUMap
|
|
17
|
+
include Shareable::Tracked
|
|
18
|
+
include Scoped::Tracked
|
|
19
|
+
|
|
20
|
+
State = Data.define(:map, :key_locks)
|
|
21
|
+
private_constant :State
|
|
22
|
+
|
|
23
|
+
protected
|
|
24
|
+
|
|
25
|
+
def internal_map = scoped_value.map
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def freeze_scoped_value(state) = state.map.freeze
|
|
30
|
+
|
|
31
|
+
def new_copied_scoped_value(map)
|
|
32
|
+
locks = Internal::KeyLockMap.new(
|
|
33
|
+
registry_class: Farce::Unshared::Map,
|
|
34
|
+
compare_keys_by_identity: map.compare_keys_by_identity?,
|
|
35
|
+
)
|
|
36
|
+
State.new(map, locks)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def with_key_lock(key, &) = scoped_value.key_locks.synchronize(key, &)
|
|
40
|
+
|
|
41
|
+
def new_scoped_value(
|
|
42
|
+
entries = nil,
|
|
43
|
+
compare_by_identity: false,
|
|
44
|
+
compare_keys_by_identity: compare_by_identity,
|
|
45
|
+
**
|
|
46
|
+
)
|
|
47
|
+
entries = convert_entries(entries)
|
|
48
|
+
map = Internal::LFUMap.new(compare_by_identity:, compare_keys_by_identity:, **)
|
|
49
|
+
locks = Internal::KeyLockMap.new(registry_class: Farce::Unshared::Map, compare_keys_by_identity:)
|
|
50
|
+
entries&.each { map[_1] = _2 }
|
|
51
|
+
State.new(map, locks)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Local
|
|
7
|
+
# A shareable LRU map with independent mutable storage and capacity in each scope.
|
|
8
|
+
#
|
|
9
|
+
# @!method initialize(entries = nil, max_size:, scope: :ractor, **options)
|
|
10
|
+
# @!macro scopes
|
|
11
|
+
# @param entries [Hash, Array<Array(BasicObject, BasicObject)>, Abstract::Map, #each, nil]
|
|
12
|
+
# Initial entries for each new scope. Entries are stored sequentially and may be evicted.
|
|
13
|
+
# @param max_size [Integer] Maximum entries retained by each new scoped map.
|
|
14
|
+
# @param scope [Symbol] The scope of the LRU map.
|
|
15
|
+
# @option options [Boolean] compare_by_identity (false) whether keys and values are compared by identity
|
|
16
|
+
# @option options [Boolean] compare_keys_by_identity (compare_by_identity) whether keys are compared by identity
|
|
17
|
+
# @option options [Boolean] compare_values_by_identity (compare_by_identity)
|
|
18
|
+
# whether values are compared by identity
|
|
19
|
+
# @return [LRUMap]
|
|
20
|
+
class LRUMap < Abstract::LRUMap
|
|
21
|
+
include Shareable::Tracked
|
|
22
|
+
include Scoped::Tracked
|
|
23
|
+
|
|
24
|
+
State = Data.define(:map, :key_locks)
|
|
25
|
+
private_constant :State
|
|
26
|
+
|
|
27
|
+
protected
|
|
28
|
+
|
|
29
|
+
def internal_map = scoped_value.map
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def freeze_scoped_value(state) = state.map.freeze
|
|
34
|
+
|
|
35
|
+
def new_copied_scoped_value(map)
|
|
36
|
+
locks = Internal::KeyLockMap.new(
|
|
37
|
+
registry_class: Farce::Unshared::Map,
|
|
38
|
+
compare_keys_by_identity: map.compare_keys_by_identity?,
|
|
39
|
+
)
|
|
40
|
+
State.new(map, locks)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def with_key_lock(key, &) = scoped_value.key_locks.synchronize(key, &)
|
|
44
|
+
|
|
45
|
+
def new_scoped_value(
|
|
46
|
+
entries = nil,
|
|
47
|
+
compare_by_identity: false,
|
|
48
|
+
compare_keys_by_identity: compare_by_identity,
|
|
49
|
+
**
|
|
50
|
+
)
|
|
51
|
+
entries = convert_entries(entries)
|
|
52
|
+
map = Internal::LRUMap.new(compare_by_identity:, compare_keys_by_identity:, **)
|
|
53
|
+
entries&.each { map[_1] = _2 }
|
|
54
|
+
locks = Internal::KeyLockMap.new(
|
|
55
|
+
registry_class: Farce::Unshared::Map,
|
|
56
|
+
compare_keys_by_identity:,
|
|
57
|
+
)
|
|
58
|
+
State.new(map, locks)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Local
|
|
7
|
+
# A shareable map with independent mutable storage in each scope.
|
|
8
|
+
#
|
|
9
|
+
# @!parse
|
|
10
|
+
# class Map
|
|
11
|
+
# # @!macro map_initialization
|
|
12
|
+
# # Initial entries are reused for each new scope.
|
|
13
|
+
# # @!macro scopes
|
|
14
|
+
# # @param scope [Symbol] The scope of the map. Defaults to `:ractor`.
|
|
15
|
+
# # @return [Map]
|
|
16
|
+
# def initialize(
|
|
17
|
+
# initial_mapping = nil,
|
|
18
|
+
# scope: :ractor,
|
|
19
|
+
# normalize_keys: nil,
|
|
20
|
+
# compare_by_identity: false,
|
|
21
|
+
# compare_keys_by_identity: compare_by_identity,
|
|
22
|
+
# compare_values_by_identity: compare_by_identity
|
|
23
|
+
# )
|
|
24
|
+
# end
|
|
25
|
+
# end
|
|
26
|
+
class Map < Abstract::ConcurrentMap
|
|
27
|
+
include Shareable::Tracked
|
|
28
|
+
include Scoped::Tracked
|
|
29
|
+
|
|
30
|
+
protected
|
|
31
|
+
|
|
32
|
+
def internal_map = scoped_value
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def new_scoped_value(entries = nil, **)
|
|
37
|
+
unless @key_normalizer || Internal::KeyNormalizer.canonical_entries?(entries)
|
|
38
|
+
return Internal::UnsharedMap.new(entries, **)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
map = Internal::UnsharedMap.new(nil, **)
|
|
42
|
+
entries&.each { map[_1] = _2 }
|
|
43
|
+
Internal::KeyNormalizer.wrap_concurrent(map, @key_normalizer)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Local
|
|
7
|
+
# A shareable record with independent field values in each selected scope.
|
|
8
|
+
# Use {Abstract::Molecule.define} to declare named fields.
|
|
9
|
+
# Explicitly supplied atoms keep their own storage and comparison policies.
|
|
10
|
+
class Molecule < Abstract::Molecule
|
|
11
|
+
include Shareable
|
|
12
|
+
|
|
13
|
+
# Create a record class with a default scope for newly created field atoms.
|
|
14
|
+
# @!macro scopes
|
|
15
|
+
# @param fields [Array<Symbol, String>] the field names
|
|
16
|
+
# @param scope [Symbol, nil] the default scope, or nil to inherit
|
|
17
|
+
# @param compare_by_identity [Boolean, nil] the default comparison policy
|
|
18
|
+
# @return [Class<Molecule>]
|
|
19
|
+
def self.define(*fields, scope: nil, **)
|
|
20
|
+
raise ArgumentError, "Invalid scope: #{scope.inspect}" unless scope.nil? || Farce::SCOPES.include?(scope)
|
|
21
|
+
|
|
22
|
+
subclass = super(*fields, **)
|
|
23
|
+
subclass.class_eval "def self.default_scope = #{scope.inspect}", __FILE__, __LINE__ unless scope.nil?
|
|
24
|
+
subclass
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# @return [Symbol] the default scope for new records
|
|
28
|
+
def self.default_scope = :ractor
|
|
29
|
+
|
|
30
|
+
# Initialize fields using this variant's atoms.
|
|
31
|
+
# @!macro scopes
|
|
32
|
+
# @param scope [Symbol] the scope for new field atoms, defaulting to the record class scope
|
|
33
|
+
# @see Abstract::Molecule#initialize
|
|
34
|
+
def initialize(*, scope: self.class.default_scope, **)
|
|
35
|
+
@scope = scope
|
|
36
|
+
super(*, **)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# @return [Symbol] the scope used by newly created field atoms
|
|
40
|
+
attr_reader :scope
|
|
41
|
+
|
|
42
|
+
private def create_atom(_, value) = Atom.new(value, scope:, compare_by_identity: compare_by_identity?)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Local
|
|
7
|
+
# A shareable priority queue with independent mutable storage in each scope.
|
|
8
|
+
class PriorityQueue < Abstract::PriorityQueue
|
|
9
|
+
include Shareable::Unfreezable
|
|
10
|
+
include Scoped
|
|
11
|
+
|
|
12
|
+
# @overload initialize(capacity: nil, default_priority: 0, order: :ascending, scope: :ractor, track_age: false)
|
|
13
|
+
# @!macro scopes
|
|
14
|
+
# @param capacity [Integer, nil] the maximum number of values, or nil for an unbounded queue
|
|
15
|
+
# @param default_priority [BasicObject] the shareable priority used when none is passed to push or try_push
|
|
16
|
+
# @param order [:ascending, :descending] the priority order
|
|
17
|
+
# @param scope [Symbol] the scope of the priority queue
|
|
18
|
+
# @param track_age [Boolean] whether to track enqueue age and queue generations
|
|
19
|
+
# @param fiber_wait [:auto, :io, :block] how scheduled fibers wait on CRuby
|
|
20
|
+
# @return [PriorityQueue]
|
|
21
|
+
def initialize(
|
|
22
|
+
capacity: nil, default_priority: 0, order: :ascending, scope: :ractor,
|
|
23
|
+
track_age: false, fiber_wait: :auto
|
|
24
|
+
)
|
|
25
|
+
unless Ractor.shareable?(default_priority)
|
|
26
|
+
raise Ractor::IsolationError, "default_priority must be Ractor-shareable"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
@order = normalize_order(order)
|
|
30
|
+
@default_priority = default_priority
|
|
31
|
+
@reverse_order = @order == :descending
|
|
32
|
+
super(capacity:, scope:, track_age:, fiber_wait:)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# @return [Symbol] always returns `:local`
|
|
36
|
+
def mode = :local
|
|
37
|
+
|
|
38
|
+
# @api private
|
|
39
|
+
def fiber_wait = internal_signal.fiber_wait
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def eager_scoped_value? = false
|
|
44
|
+
def internal_queue = scoped_value.first
|
|
45
|
+
def internal_signal = scoped_value.last
|
|
46
|
+
|
|
47
|
+
def new_scoped_value(capacity: nil, fiber_wait: :auto, track_age: false)
|
|
48
|
+
signal = Internal::UnsharedSignal.for(fiber_wait)
|
|
49
|
+
[Internal::UnsharedPriorityQueue.new(capacity:, signal:, track_age:), signal]
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Local
|
|
7
|
+
# A shareable queue with independent mutable storage in each scope.
|
|
8
|
+
#
|
|
9
|
+
# @!method initialize(capacity: 1024, track_age: false, scope: :ractor, **options)
|
|
10
|
+
# @!macro scopes
|
|
11
|
+
# @param capacity [Integer, nil] the maximum number of values, or nil for an unbounded queue
|
|
12
|
+
# @param track_age [Boolean] whether to track enqueue age and queue generations
|
|
13
|
+
# @param scope [Symbol] the scope of the queue
|
|
14
|
+
# @option options [:auto, :io, :block] fiber_wait (:auto) how scheduled fibers wait on CRuby
|
|
15
|
+
# @return [Queue]
|
|
16
|
+
class Queue < Abstract::Queue
|
|
17
|
+
include Shareable::Unfreezable
|
|
18
|
+
include Scoped
|
|
19
|
+
|
|
20
|
+
# @return [Symbol] always returns `:local`
|
|
21
|
+
def mode = :local
|
|
22
|
+
|
|
23
|
+
# @api private
|
|
24
|
+
def fiber_wait = internal_queue.fiber_wait
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def internal_queue = scoped_value
|
|
29
|
+
def new_scoped_value(...) = Internal::UnsharedQueue.new(...)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Local
|
|
7
|
+
# Common scope selection and storage for shareable local objects.
|
|
8
|
+
module Scoped
|
|
9
|
+
include Shareable
|
|
10
|
+
|
|
11
|
+
# Freeze the current backing before recording the handle-global state.
|
|
12
|
+
# @api private
|
|
13
|
+
module Tracked
|
|
14
|
+
include Scoped
|
|
15
|
+
|
|
16
|
+
# @!visibility private
|
|
17
|
+
def self.included(base)
|
|
18
|
+
Scoped.included(base)
|
|
19
|
+
super
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def freeze
|
|
23
|
+
return Object.instance_method(:freeze).bind_call(self) unless @farce_freeze_state
|
|
24
|
+
|
|
25
|
+
state = @farce_freeze_state
|
|
26
|
+
if state.respond_to?(:native_flag)
|
|
27
|
+
state.set { freeze_scoped_value(scoped_value) }
|
|
28
|
+
self
|
|
29
|
+
else
|
|
30
|
+
freeze_scoped_value(scoped_value)
|
|
31
|
+
super
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def scoped_value
|
|
38
|
+
value = super
|
|
39
|
+
freeze_scoped_value(value) if frozen?
|
|
40
|
+
value
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
module Map
|
|
45
|
+
def initialize(*arguments, normalize_keys: nil, **)
|
|
46
|
+
restoring = Internal::KeyNormalizer.restoration?(normalize_keys)
|
|
47
|
+
normalizer = Internal::KeyNormalizer.build(normalize_keys, shareable: true)
|
|
48
|
+
|
|
49
|
+
if is_a?(Abstract::ConcurrentMap)
|
|
50
|
+
@key_normalizer = normalizer
|
|
51
|
+
else
|
|
52
|
+
Internal::KeyNormalizer.install(self, normalizer, Internal::KeyNormalizer.operations_for(self))
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
if !is_a?(Abstract::LeaseMap) && !arguments.empty?
|
|
56
|
+
entries = convert_entries(arguments.first)
|
|
57
|
+
if entries && ((normalizer && !restoring) || !entries.is_a?(Hash))
|
|
58
|
+
canonical = Internal::KeyNormalizer.canonical_entries
|
|
59
|
+
entries.each do |key, value|
|
|
60
|
+
key = normalizer.call(key) if normalizer && !restoring
|
|
61
|
+
canonical << [key, value]
|
|
62
|
+
end
|
|
63
|
+
entries = canonical
|
|
64
|
+
end
|
|
65
|
+
arguments = arguments.dup
|
|
66
|
+
arguments[0] = entries
|
|
67
|
+
end
|
|
68
|
+
super(*arguments, **)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
private
|
|
72
|
+
|
|
73
|
+
def install_copied_map(map) = Internal::Storage.scope(scope)[self] = new_copied_scoped_value(map)
|
|
74
|
+
def new_copied_scoped_value(map) = map
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
MANAGER = ModeManager.new
|
|
78
|
+
private_constant :MANAGER, :Map
|
|
79
|
+
|
|
80
|
+
# @!visibility private
|
|
81
|
+
def self.included(base)
|
|
82
|
+
base.include Map if base < Abstract::Map
|
|
83
|
+
super
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# @return [Symbol] The scope used to resolve this object's contents.
|
|
87
|
+
attr_reader :scope
|
|
88
|
+
|
|
89
|
+
# Constructor arguments configure each scope's independent backing object.
|
|
90
|
+
# @!macro scopes
|
|
91
|
+
# @param arguments [Array<BasicObject>] positional arguments for the backing object
|
|
92
|
+
# @param options [Hash{Symbol => BasicObject}] keyword arguments for the backing object
|
|
93
|
+
# @param scope [Symbol] The storage scope. Defaults to :ractor.
|
|
94
|
+
def initialize(*arguments, scope: :ractor, **options)
|
|
95
|
+
initialize_scoped(arguments, options, scope:)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
private
|
|
99
|
+
|
|
100
|
+
def initialize_scoped(arguments, options, scope:, configuration: nil)
|
|
101
|
+
raise ArgumentError, "Invalid scope: #{scope.inspect}" unless Farce::SCOPES.include?(scope)
|
|
102
|
+
|
|
103
|
+
if is_a?(Shareable::Tracked)
|
|
104
|
+
guard = Internal.native_ractors? ? Internal::TransactionFreezeGuard : Internal::Flag
|
|
105
|
+
@farce_freeze_state = guard.new(false)
|
|
106
|
+
end
|
|
107
|
+
@scope = scope
|
|
108
|
+
@configuration = configuration || MANAGER.wrap([arguments.freeze, options.freeze].freeze)
|
|
109
|
+
|
|
110
|
+
Internal::Storage.scope(scope)[self] = new_scoped_value(*arguments, **options) if eager_scoped_value?
|
|
111
|
+
|
|
112
|
+
# Abstract initializers allocate instance variables. Local backing objects
|
|
113
|
+
# live in Storage instead, so initialization ends here.
|
|
114
|
+
Internal::Freeze.publish(self)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def marshal_configuration
|
|
118
|
+
value = Envelope === @configuration ? @configuration.marshal_dump[1] : @configuration
|
|
119
|
+
arguments, options = value
|
|
120
|
+
canonical = Internal::KeyNormalizer.canonical_entries?(arguments.first)
|
|
121
|
+
if canonical
|
|
122
|
+
arguments = arguments.dup
|
|
123
|
+
arguments[0] = arguments[0].to_a.freeze
|
|
124
|
+
value = [arguments.freeze, options].freeze
|
|
125
|
+
end
|
|
126
|
+
[Internal::MarshalSupport.value(value), canonical]
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# @api private
|
|
130
|
+
def marshal_initialize(arguments, options, configuration)
|
|
131
|
+
options = options.dup
|
|
132
|
+
scope = options.delete(:scope)
|
|
133
|
+
if options.key?(:normalize_keys)
|
|
134
|
+
normalizer = Internal::KeyNormalizer.build(options.delete(:normalize_keys), shareable: true)
|
|
135
|
+
if is_a?(Abstract::ConcurrentMap)
|
|
136
|
+
@key_normalizer = normalizer
|
|
137
|
+
else
|
|
138
|
+
Internal::KeyNormalizer.install(self, normalizer, Internal::KeyNormalizer.operations_for(self))
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
original, canonical = configuration
|
|
142
|
+
original = Internal::MarshalSupport.restore_value(original)
|
|
143
|
+
if canonical
|
|
144
|
+
initial, settings = original
|
|
145
|
+
initial = initial.dup
|
|
146
|
+
initial[0] = Internal::KeyNormalizer.canonical_entries.concat(initial[0])
|
|
147
|
+
original = [initial.freeze, settings].freeze
|
|
148
|
+
end
|
|
149
|
+
configuration = MANAGER.wrap(original)
|
|
150
|
+
initialize_scoped(arguments, options, scope:, configuration:)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Subclasses without initial contents can defer backing storage allocation.
|
|
154
|
+
def eager_scoped_value? = true
|
|
155
|
+
def freeze_scoped_value(value) = value.freeze
|
|
156
|
+
def scoped_configuration = MANAGER.unwrap(@configuration)
|
|
157
|
+
|
|
158
|
+
def scoped_value
|
|
159
|
+
Internal::Storage.store_if_absent(self, scope:) do
|
|
160
|
+
arguments, options = scoped_configuration
|
|
161
|
+
new_scoped_value(*arguments, **options)
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Local
|
|
7
|
+
# A shareable set with independent mutable contents in each scope.
|
|
8
|
+
class Set < Farce::Abstract::Set
|
|
9
|
+
include Shareable::Delegated
|
|
10
|
+
|
|
11
|
+
# The scope with independent contents.
|
|
12
|
+
# @return [Symbol] The configured scope name.
|
|
13
|
+
def scope = map_backend.scope
|
|
14
|
+
|
|
15
|
+
private def new_map(...) = Farce::Local::Map.new(...)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|