farce 0.0.1.alpha2-x86_64-linux-gnu
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CODE_OF_CONDUCT.md +26 -0
- data/CONTRIBUTING.md +71 -0
- data/MIT-LICENSE +20 -0
- data/README.md +1524 -0
- data/SECURITY.md +10 -0
- data/docs/benchmarks.md +185 -0
- data/docs/gems/dry-types.md +290 -0
- data/docs/gems/msgpack.md +70 -0
- data/docs/gems/ractor-shim.md +63 -0
- data/docs/modes.md +628 -0
- data/docs/scopes.md +649 -0
- data/docs/variants.md +346 -0
- data/ext/ext_helper.rb +20 -0
- data/ext/farce/README.md +21 -0
- data/ext/farce/atom.c +1023 -0
- data/ext/farce/bounded_map.c +1683 -0
- data/ext/farce/containers.h +77 -0
- data/ext/farce/counter.c +399 -0
- data/ext/farce/darwin.c +100 -0
- data/ext/farce/depend +12 -0
- data/ext/farce/dict.c +1523 -0
- data/ext/farce/dict.h +152 -0
- data/ext/farce/drivers.c +237 -0
- data/ext/farce/exchanger.c +299 -0
- data/ext/farce/extconf.rb +99 -0
- data/ext/farce/farce.c +359 -0
- data/ext/farce/flag.c +288 -0
- data/ext/farce/io.c +338 -0
- data/ext/farce/lock.c +510 -0
- data/ext/farce/map.c +2240 -0
- data/ext/farce/priority_queue.c +2056 -0
- data/ext/farce/queue.c +1059 -0
- data/ext/farce/reactor.c +820 -0
- data/ext/farce/reactor.h +103 -0
- data/ext/farce/shareable.h +31 -0
- data/ext/farce/signal.c +350 -0
- data/ext/farce/transaction.c +354 -0
- data/ext/farce/transaction.h +40 -0
- data/ext/farce/tree_map.c +1953 -0
- data/ext/farce/trie.c +2020 -0
- data/ext/farce/unshareable.c +155 -0
- data/ext/farce/unshared_io_pool.h +234 -0
- data/ext/farce/unshared_signal.c +263 -0
- data/ext/farce/unshared_wait.h +193 -0
- data/ext/farce/unsupported.c +6 -0
- data/ext/farce/vector.c +1195 -0
- data/ext/farce/weak_map.c +1714 -0
- data/ext/java/org/farce/BoundedMap.java +394 -0
- data/ext/java/org/farce/FiberScheduler.java +141 -0
- data/ext/java/org/farce/PriorityKey.java +45 -0
- data/ext/java/org/farce/PriorityQueue.java +373 -0
- data/ext/java/org/farce/QueueSignal.java +28 -0
- data/ext/rebind/README.md +14 -0
- data/ext/rebind/extconf.rb +10 -0
- data/ext/rebind/rebind.c +186 -0
- data/lib/farce/_yard/internal.rb +13 -0
- data/lib/farce/_yard/macros.rb +61 -0
- data/lib/farce/_yard/ractor.rb +46 -0
- data/lib/farce/abstract/atom.rb +186 -0
- data/lib/farce/abstract/bounded_map.rb +232 -0
- data/lib/farce/abstract/collection.rb +151 -0
- data/lib/farce/abstract/concurrent_map.rb +381 -0
- data/lib/farce/abstract/counter.rb +193 -0
- data/lib/farce/abstract/duplicable_map.rb +229 -0
- data/lib/farce/abstract/exchanger.rb +26 -0
- data/lib/farce/abstract/flag.rb +71 -0
- data/lib/farce/abstract/lazy.rb +115 -0
- data/lib/farce/abstract/lease.rb +104 -0
- data/lib/farce/abstract/lease_map.rb +261 -0
- data/lib/farce/abstract/lease_pool.rb +91 -0
- data/lib/farce/abstract/lfu_map.rb +20 -0
- data/lib/farce/abstract/lru_map.rb +25 -0
- data/lib/farce/abstract/map.rb +345 -0
- data/lib/farce/abstract/molecule.rb +245 -0
- data/lib/farce/abstract/port.rb +74 -0
- data/lib/farce/abstract/priority_queue.rb +117 -0
- data/lib/farce/abstract/queue.rb +269 -0
- data/lib/farce/abstract/scheduler.rb +111 -0
- data/lib/farce/abstract/set.rb +910 -0
- data/lib/farce/abstract/sorted_set.rb +172 -0
- data/lib/farce/abstract/timer_queue.rb +136 -0
- data/lib/farce/abstract/tree_map.rb +269 -0
- data/lib/farce/abstract/value.rb +68 -0
- data/lib/farce/abstract/vector.rb +1126 -0
- data/lib/farce/abstract/weak_atom.rb +32 -0
- data/lib/farce/abstract/weak_key_map.rb +12 -0
- data/lib/farce/abstract/weak_map.rb +13 -0
- data/lib/farce/abstract/weak_set.rb +12 -0
- data/lib/farce/abstract/weak_value_map.rb +12 -0
- data/lib/farce/abstract.rb +17 -0
- data/lib/farce/atom.rb +293 -0
- data/lib/farce/class_mirror.rb +87 -0
- data/lib/farce/clock.rb +121 -0
- data/lib/farce/config.rb +229 -0
- data/lib/farce/counter.rb +71 -0
- data/lib/farce/deduper.rb +122 -0
- data/lib/farce/engine/jruby/bounded_map.rb +314 -0
- data/lib/farce/engine/jruby/fiber_scheduler.jar +0 -0
- data/lib/farce/engine/jruby/fiber_scheduler.rb +119 -0
- data/lib/farce/engine/jruby/lease_waiting.rb +19 -0
- data/lib/farce/engine/jruby/map.rb +505 -0
- data/lib/farce/engine/jruby/mutable_numeric_copy.rb +42 -0
- data/lib/farce/engine/jruby/signal.rb +147 -0
- data/lib/farce/engine/jruby.rb +63 -0
- data/lib/farce/engine/jvm/concurrent_weak_registry.rb +55 -0
- data/lib/farce/engine/jvm/counter.rb +102 -0
- data/lib/farce/engine/jvm/extension.rb +32 -0
- data/lib/farce/engine/jvm/farce.jar +0 -0
- data/lib/farce/engine/jvm/flag.rb +79 -0
- data/lib/farce/engine/jvm/priority_queue.rb +217 -0
- data/lib/farce/engine/jvm/tree_map.rb +350 -0
- data/lib/farce/engine/jvm/types.rb +180 -0
- data/lib/farce/engine/jvm.rb +19 -0
- data/lib/farce/engine/ruby/3.4/farce.so +0 -0
- data/lib/farce/engine/ruby/3.4/fiber_scheduler.rb +20 -0
- data/lib/farce/engine/ruby/3.4/port.rb +186 -0
- data/lib/farce/engine/ruby/3.4/ractor_methods.rb +26 -0
- data/lib/farce/engine/ruby/3.4/ractor_selector.rb +92 -0
- data/lib/farce/engine/ruby/3.4/rebind.so +0 -0
- data/lib/farce/engine/ruby/3.4/vault.rb +56 -0
- data/lib/farce/engine/ruby/4.0/farce.so +0 -0
- data/lib/farce/engine/ruby/4.0/port.rb +19 -0
- data/lib/farce/engine/ruby/4.0/ractor_methods.rb +20 -0
- data/lib/farce/engine/ruby/4.0/ractor_selector.rb +108 -0
- data/lib/farce/engine/ruby/4.0/rebind.so +0 -0
- data/lib/farce/engine/ruby/4.0/vault.rb +74 -0
- data/lib/farce/engine/ruby/4.1/port.rb +21 -0
- data/lib/farce/engine/ruby/4.1/ractor_methods.rb +22 -0
- data/lib/farce/engine/ruby/4.1/ractor_selector.rb +25 -0
- data/lib/farce/engine/ruby/4.1/vault.rb +5 -0
- data/lib/farce/engine/ruby/fiber_scheduler.rb +32 -0
- data/lib/farce/engine/ruby/key_lock_map.rb +28 -0
- data/lib/farce/engine/ruby/shared/lease.rb +26 -0
- data/lib/farce/engine/ruby/shared/lease_pool.rb +24 -0
- data/lib/farce/engine/ruby/shared/main_scheduler.rb +9 -0
- data/lib/farce/engine/ruby/shared/parallel_scheduler.rb +9 -0
- data/lib/farce/engine/ruby/shared/proxy_owner.rb +31 -0
- data/lib/farce/engine/ruby/shared/ractor_methods.rb +34 -0
- data/lib/farce/engine/ruby/shared/ractor_selector.rb +328 -0
- data/lib/farce/engine/ruby/shared/strict_map.rb +13 -0
- data/lib/farce/engine/ruby/shared/unshared_vector.rb +14 -0
- data/lib/farce/engine/ruby/shared/vault.rb +144 -0
- data/lib/farce/engine/ruby/shared/vault_weak_map.rb +336 -0
- data/lib/farce/engine/ruby/shared/weak_atom.rb +54 -0
- data/lib/farce/engine/ruby/shared/weak_map.rb +413 -0
- data/lib/farce/engine/ruby.rb +130 -0
- data/lib/farce/engine/shared/atom.rb +10 -0
- data/lib/farce/engine/shared/exchanger.rb +130 -0
- data/lib/farce/engine/shared/identity_key.rb +22 -0
- data/lib/farce/engine/shared/lease.rb +10 -0
- data/lib/farce/engine/shared/lease_pool.rb +10 -0
- data/lib/farce/engine/shared/main_scheduler.rb +20 -0
- data/lib/farce/engine/shared/map_key_coordination.rb +226 -0
- data/lib/farce/engine/shared/parallel_scheduler.rb +9 -0
- data/lib/farce/engine/shared/port.rb +44 -0
- data/lib/farce/engine/shared/portable_bounded_map.rb +619 -0
- data/lib/farce/engine/shared/proxy_owner.rb +43 -0
- data/lib/farce/engine/shared/queue.rb +233 -0
- data/lib/farce/engine/shared/ractor_methods.rb +73 -0
- data/lib/farce/engine/shared/rebindable.rb +15 -0
- data/lib/farce/engine/shared/strict_atom.rb +73 -0
- data/lib/farce/engine/shared/strict_map.rb +117 -0
- data/lib/farce/engine/shared/strict_queue_values.rb +27 -0
- data/lib/farce/engine/shared/strict_tree_map.rb +56 -0
- data/lib/farce/engine/shared/transaction_map_backend.rb +20 -0
- data/lib/farce/engine/shared/trie.rb +317 -0
- data/lib/farce/engine/shared/trie_builder.rb +199 -0
- data/lib/farce/engine/shared/unshareable.rb +14 -0
- data/lib/farce/engine/shared/unshared_atom.rb +256 -0
- data/lib/farce/engine/shared/unshared_priority_queue.rb +9 -0
- data/lib/farce/engine/shared/unshared_queue.rb +18 -0
- data/lib/farce/engine/shared/unshared_signal.rb +21 -0
- data/lib/farce/engine/shared/unshared_vector.rb +377 -0
- data/lib/farce/engine/shared/unshared_weak_atom.rb +30 -0
- data/lib/farce/engine/shared/unshared_weak_map.rb +445 -0
- data/lib/farce/engine/shared/vault.rb +31 -0
- data/lib/farce/engine/shared/vector.rb +83 -0
- data/lib/farce/engine/shared/weak_atom/base.rb +189 -0
- data/lib/farce/engine/shared/weak_atom.rb +20 -0
- data/lib/farce/engine/shared/weak_map/cell.rb +99 -0
- data/lib/farce/engine/shared/weak_map/index.rb +249 -0
- data/lib/farce/engine/shared/weak_map/lock.rb +80 -0
- data/lib/farce/engine/shared/weak_map/reference.rb +33 -0
- data/lib/farce/engine/shared.rb +63 -0
- data/lib/farce/engine/truffleruby/fiber_scheduler.rb +13 -0
- data/lib/farce/engine/truffleruby/lock.rb +121 -0
- data/lib/farce/engine/truffleruby/map.rb +656 -0
- data/lib/farce/engine/truffleruby/native/counter.rb +105 -0
- data/lib/farce/engine/truffleruby/native/flag.rb +77 -0
- data/lib/farce/engine/truffleruby/native/ordered_array_support.rb +67 -0
- data/lib/farce/engine/truffleruby/native/priority_queue.rb +388 -0
- data/lib/farce/engine/truffleruby/native/tree_map.rb +51 -0
- data/lib/farce/engine/truffleruby/native/unsafe_tree_map.rb +350 -0
- data/lib/farce/engine/truffleruby/signal.rb +77 -0
- data/lib/farce/engine/truffleruby.rb +148 -0
- data/lib/farce/envelope.rb +335 -0
- data/lib/farce/error.rb +35 -0
- data/lib/farce/exchanger.rb +41 -0
- data/lib/farce/flag.rb +27 -0
- data/lib/farce/integrations/active_support/blank.rb +68 -0
- data/lib/farce/integrations/active_support/clock.rb +17 -0
- data/lib/farce/integrations/active_support/duplicable.rb +78 -0
- data/lib/farce/integrations/active_support/map.rb +175 -0
- data/lib/farce/integrations/active_support/set.rb +60 -0
- data/lib/farce/integrations/active_support/value_serialization.rb +17 -0
- data/lib/farce/integrations/active_support/vector.rb +231 -0
- data/lib/farce/integrations/active_support.rb +9 -0
- data/lib/farce/integrations/activesupport.rb +5 -0
- data/lib/farce/integrations/bson.rb +108 -0
- data/lib/farce/integrations/cbor.rb +51 -0
- data/lib/farce/integrations/concurrent.rb +112 -0
- data/lib/farce/integrations/dry-types.rb +5 -0
- data/lib/farce/integrations/dry_types.rb +694 -0
- data/lib/farce/integrations/json.rb +7 -0
- data/lib/farce/integrations/msgpack.rb +112 -0
- data/lib/farce/integrations/oj.rb +69 -0
- data/lib/farce/integrations/psych.rb +191 -0
- data/lib/farce/integrations/ractor-sharing.rb +5 -0
- data/lib/farce/integrations/ractor-tmvar.rb +5 -0
- data/lib/farce/integrations/ractor_sharing.rb +172 -0
- data/lib/farce/integrations/ractor_tmvar.rb +64 -0
- data/lib/farce/integrations/shared/to_json.rb +42 -0
- data/lib/farce/integrations/sorted_set.rb +11 -0
- data/lib/farce/integrations/weakref.rb +38 -0
- data/lib/farce/integrations/yajl.rb +10 -0
- data/lib/farce/integrations.rb +156 -0
- data/lib/farce/internal/_frozen_config.rb +11 -0
- data/lib/farce/internal/autoloads.rb +47 -0
- data/lib/farce/internal/blocking_priority_queue.rb +122 -0
- data/lib/farce/internal/converter.rb +106 -0
- data/lib/farce/internal/copyable.rb +31 -0
- data/lib/farce/internal/delegation.rb +20 -0
- data/lib/farce/internal/external_transaction.rb +59 -0
- data/lib/farce/internal/fake_ractor.rb +179 -0
- data/lib/farce/internal/freeze.rb +118 -0
- data/lib/farce/internal/inspect.rb +157 -0
- data/lib/farce/internal/key_lock_map.rb +29 -0
- data/lib/farce/internal/key_normalizer.rb +289 -0
- data/lib/farce/internal/lease_initialization.rb +115 -0
- data/lib/farce/internal/lease_map.rb +441 -0
- data/lib/farce/internal/lease_pool_state.rb +228 -0
- data/lib/farce/internal/lease_state.rb +342 -0
- data/lib/farce/internal/lease_waiting.rb +13 -0
- data/lib/farce/internal/managed_queue.rb +26 -0
- data/lib/farce/internal/map_value_modes.rb +227 -0
- data/lib/farce/internal/marshal_support.rb +227 -0
- data/lib/farce/internal/mixin.rb +20 -0
- data/lib/farce/internal/mutable_ordered_key_lock_map.rb +63 -0
- data/lib/farce/internal/noncopyable.rb +17 -0
- data/lib/farce/internal/ordered_key_lock_map.rb +69 -0
- data/lib/farce/internal/pool_supervisor.rb +41 -0
- data/lib/farce/internal/pool_worker.rb +61 -0
- data/lib/farce/internal/portable_transaction/reservation_entry.rb +29 -0
- data/lib/farce/internal/portable_transaction/strong_map_entry.rb +137 -0
- data/lib/farce/internal/portable_transaction/strong_map_size_entry.rb +44 -0
- data/lib/farce/internal/portable_transaction/tree_entry.rb +64 -0
- data/lib/farce/internal/portable_transaction.rb +164 -0
- data/lib/farce/internal/proxy_owner_notifications.rb +29 -0
- data/lib/farce/internal/reservation_waiting.rb +24 -0
- data/lib/farce/internal/scheduled_task.rb +48 -0
- data/lib/farce/internal/scheduler_io.rb +171 -0
- data/lib/farce/internal/scheduler_lifecycle.rb +314 -0
- data/lib/farce/internal/select_scheduler.rb +235 -0
- data/lib/farce/internal/storage.rb +162 -0
- data/lib/farce/internal/strict_lease.rb +30 -0
- data/lib/farce/internal/strict_lease_map.rb +20 -0
- data/lib/farce/internal/strict_lease_pool.rb +29 -0
- data/lib/farce/internal/thread_pool.rb +166 -0
- data/lib/farce/internal/transaction_conflict.rb +9 -0
- data/lib/farce/internal/transaction_freeze_guard.rb +30 -0
- data/lib/farce/internal/transaction_map_snapshot.rb +123 -0
- data/lib/farce/internal/undefined.rb +22 -0
- data/lib/farce/internal/unshared_lease.rb +29 -0
- data/lib/farce/internal/unshared_lease_pool.rb +34 -0
- data/lib/farce/internal/unshared_queue_waiting.rb +28 -0
- data/lib/farce/internal/value_serialization.rb +13 -0
- data/lib/farce/internal/weak_map_value_modes.rb +58 -0
- data/lib/farce/internal/weak_mode_manager.rb +26 -0
- data/lib/farce/internal.rb +129 -0
- data/lib/farce/lazy.rb +100 -0
- data/lib/farce/lazy_ref.rb +40 -0
- data/lib/farce/lease.rb +28 -0
- data/lib/farce/lease_map.rb +34 -0
- data/lib/farce/lease_pool.rb +29 -0
- data/lib/farce/lfu_map.rb +53 -0
- data/lib/farce/local/atom.rb +23 -0
- data/lib/farce/local/counter.rb +88 -0
- data/lib/farce/local/flag.rb +65 -0
- data/lib/farce/local/lazy.rb +38 -0
- data/lib/farce/local/lazy_ref.rb +36 -0
- data/lib/farce/local/lease.rb +77 -0
- data/lib/farce/local/lease_map.rb +80 -0
- data/lib/farce/local/lease_pool.rb +38 -0
- data/lib/farce/local/lfu_map.rb +55 -0
- data/lib/farce/local/lru_map.rb +62 -0
- data/lib/farce/local/map.rb +47 -0
- data/lib/farce/local/molecule.rb +45 -0
- data/lib/farce/local/priority_queue.rb +53 -0
- data/lib/farce/local/queue.rb +32 -0
- data/lib/farce/local/scoped.rb +166 -0
- data/lib/farce/local/set.rb +18 -0
- data/lib/farce/local/sorted_set.rb +50 -0
- data/lib/farce/local/timer_queue.rb +41 -0
- data/lib/farce/local/tree_map.rb +47 -0
- data/lib/farce/local/vector.rb +30 -0
- data/lib/farce/local/weak_atom.rb +23 -0
- data/lib/farce/local/weak_key_map.rb +39 -0
- data/lib/farce/local/weak_map.rb +39 -0
- data/lib/farce/local/weak_set.rb +18 -0
- data/lib/farce/local/weak_value_map.rb +39 -0
- data/lib/farce/local.rb +35 -0
- data/lib/farce/lock.rb +54 -0
- data/lib/farce/lru_map.rb +63 -0
- data/lib/farce/map.rb +58 -0
- data/lib/farce/mode_manager.rb +142 -0
- data/lib/farce/molecule.rb +60 -0
- data/lib/farce/mutable.rb +171 -0
- data/lib/farce/pool.rb +332 -0
- data/lib/farce/port.rb +134 -0
- data/lib/farce/priority_queue.rb +70 -0
- data/lib/farce/proxy/register.rb +101 -0
- data/lib/farce/proxy/supervisor.rb +137 -0
- data/lib/farce/proxy/wrapper.rb +49 -0
- data/lib/farce/proxy.rb +291 -0
- data/lib/farce/queue.rb +60 -0
- data/lib/farce/ractor.rb +269 -0
- data/lib/farce/read_write_lock.rb +256 -0
- data/lib/farce/reference.rb +158 -0
- data/lib/farce/resolv/dns.rb +42 -0
- data/lib/farce/resolv.rb +85 -0
- data/lib/farce/scheduler.rb +536 -0
- data/lib/farce/set.rb +39 -0
- data/lib/farce/shareable.rb +150 -0
- data/lib/farce/signal.rb +97 -0
- data/lib/farce/sorted_set.rb +36 -0
- data/lib/farce/strict/atom.rb +34 -0
- data/lib/farce/strict/counter.rb +10 -0
- data/lib/farce/strict/exchanger.rb +25 -0
- data/lib/farce/strict/flag.rb +10 -0
- data/lib/farce/strict/lazy.rb +26 -0
- data/lib/farce/strict/lazy_ref.rb +26 -0
- data/lib/farce/strict/lease.rb +27 -0
- data/lib/farce/strict/lease_map.rb +33 -0
- data/lib/farce/strict/lease_pool.rb +28 -0
- data/lib/farce/strict/lfu_map.rb +27 -0
- data/lib/farce/strict/lru_map.rb +28 -0
- data/lib/farce/strict/map.rb +54 -0
- data/lib/farce/strict/molecule.rb +16 -0
- data/lib/farce/strict/port.rb +40 -0
- data/lib/farce/strict/priority_queue.rb +20 -0
- data/lib/farce/strict/queue.rb +17 -0
- data/lib/farce/strict/set.rb +14 -0
- data/lib/farce/strict/sorted_set.rb +19 -0
- data/lib/farce/strict/timer_queue.rb +13 -0
- data/lib/farce/strict/tree_map.rb +27 -0
- data/lib/farce/strict/vector.rb +24 -0
- data/lib/farce/strict/weak_atom.rb +31 -0
- data/lib/farce/strict/weak_key_map.rb +49 -0
- data/lib/farce/strict/weak_map.rb +49 -0
- data/lib/farce/strict/weak_set.rb +14 -0
- data/lib/farce/strict/weak_value_map.rb +48 -0
- data/lib/farce/strict.rb +28 -0
- data/lib/farce/system.rb +40 -0
- data/lib/farce/thread_scheduler.rb +70 -0
- data/lib/farce/timer_queue.rb +66 -0
- data/lib/farce/transaction/atom.rb +73 -0
- data/lib/farce/transaction/map.rb +25 -0
- data/lib/farce/transaction/map_operations.rb +143 -0
- data/lib/farce/transaction/molecule.rb +90 -0
- data/lib/farce/transaction/mutable.rb +61 -0
- data/lib/farce/transaction/set.rb +17 -0
- data/lib/farce/transaction/set_operations.rb +48 -0
- data/lib/farce/transaction/sorted_set.rb +18 -0
- data/lib/farce/transaction/tree_map.rb +78 -0
- data/lib/farce/transaction/vector.rb +139 -0
- data/lib/farce/transaction/wrapper.rb +202 -0
- data/lib/farce/transaction.rb +343 -0
- data/lib/farce/tree_map.rb +56 -0
- data/lib/farce/unsafe/lfu_map.rb +36 -0
- data/lib/farce/unsafe/lru_map.rb +36 -0
- data/lib/farce/unsafe/tree_map.rb +21 -0
- data/lib/farce/unsafe.rb +29 -0
- data/lib/farce/unshareable.rb +67 -0
- data/lib/farce/unshared/atom.rb +24 -0
- data/lib/farce/unshared/counter.rb +10 -0
- data/lib/farce/unshared/flag.rb +10 -0
- data/lib/farce/unshared/lazy.rb +38 -0
- data/lib/farce/unshared/lazy_ref.rb +26 -0
- data/lib/farce/unshared/lease.rb +27 -0
- data/lib/farce/unshared/lease_map.rb +26 -0
- data/lib/farce/unshared/lease_pool.rb +25 -0
- data/lib/farce/unshared/lfu_map.rb +20 -0
- data/lib/farce/unshared/lru_map.rb +20 -0
- data/lib/farce/unshared/map.rb +49 -0
- data/lib/farce/unshared/molecule.rb +16 -0
- data/lib/farce/unshared/priority_queue.rb +16 -0
- data/lib/farce/unshared/queue.rb +27 -0
- data/lib/farce/unshared/set.rb +14 -0
- data/lib/farce/unshared/sorted_set.rb +28 -0
- data/lib/farce/unshared/timer_queue.rb +16 -0
- data/lib/farce/unshared/tree_map.rb +21 -0
- data/lib/farce/unshared/vector.rb +19 -0
- data/lib/farce/unshared/weak_atom.rb +31 -0
- data/lib/farce/unshared/weak_key_map.rb +44 -0
- data/lib/farce/unshared/weak_map.rb +44 -0
- data/lib/farce/unshared/weak_set.rb +14 -0
- data/lib/farce/unshared/weak_value_map.rb +43 -0
- data/lib/farce/unshared.rb +28 -0
- data/lib/farce/vector.rb +228 -0
- data/lib/farce/version.rb +8 -0
- data/lib/farce/walker/definitions.rb +186 -0
- data/lib/farce/walker/modification.rb +355 -0
- data/lib/farce/walker.rb +319 -0
- data/lib/farce/weak_atom.rb +121 -0
- data/lib/farce/weak_key_map.rb +31 -0
- data/lib/farce/weak_map.rb +33 -0
- data/lib/farce/weak_ref.rb +67 -0
- data/lib/farce/weak_set.rb +82 -0
- data/lib/farce/weak_value.rb +195 -0
- data/lib/farce/weak_value_map.rb +32 -0
- data/lib/farce.rb +519 -0
- metadata +468 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
# @!visibility private
|
|
7
|
+
module Internal # :nodoc: all
|
|
8
|
+
class UnsharedAtom
|
|
9
|
+
TIMED_OUT = Object.new.freeze
|
|
10
|
+
private_constant :TIMED_OUT
|
|
11
|
+
|
|
12
|
+
def initialize(value = nil, compare_by_identity: false)
|
|
13
|
+
if compare_by_identity != true && compare_by_identity != false
|
|
14
|
+
raise ArgumentError, "compare_by_identity must be a boolean"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
@value = value
|
|
18
|
+
@compare_by_identity = compare_by_identity
|
|
19
|
+
@mutex = Mutex.new
|
|
20
|
+
@signal = ConditionVariable.new
|
|
21
|
+
@updating = false
|
|
22
|
+
@updating_fiber = nil
|
|
23
|
+
@updating_thread = nil
|
|
24
|
+
@version = 0
|
|
25
|
+
@farce_frozen = false
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @api private
|
|
29
|
+
def transaction_snapshot
|
|
30
|
+
PortableTransaction.snapshot(self, :atom)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def value = @mutex.synchronize { @value }
|
|
34
|
+
|
|
35
|
+
def freeze
|
|
36
|
+
@mutex.synchronize { @farce_frozen = true }
|
|
37
|
+
self
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def frozen? = @mutex.synchronize { @farce_frozen }
|
|
41
|
+
|
|
42
|
+
def get(timeout: nil, &fallback)
|
|
43
|
+
result = with_available_value(timeout) { @value }
|
|
44
|
+
timed_out(result, fallback)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def store(new_value, timeout: nil, &fallback)
|
|
48
|
+
check_frozen!
|
|
49
|
+
result = with_available_value(timeout) do
|
|
50
|
+
check_frozen_locked!
|
|
51
|
+
@value = new_value
|
|
52
|
+
changed!
|
|
53
|
+
new_value
|
|
54
|
+
end
|
|
55
|
+
timed_out(result, fallback)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def swap(new_value, timeout: nil, &fallback)
|
|
59
|
+
check_frozen!
|
|
60
|
+
result = with_available_value(timeout) do
|
|
61
|
+
check_frozen_locked!
|
|
62
|
+
old_value = @value
|
|
63
|
+
@value = new_value
|
|
64
|
+
changed!
|
|
65
|
+
old_value
|
|
66
|
+
end
|
|
67
|
+
timed_out(result, fallback)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def store_if_absent(timeout: nil, &update)
|
|
71
|
+
raise LocalJumpError, "no block given" unless update
|
|
72
|
+
check_frozen!
|
|
73
|
+
deadline = timeout_deadline(timeout)
|
|
74
|
+
|
|
75
|
+
current = reserve(deadline) do
|
|
76
|
+
return @value unless @value.nil?
|
|
77
|
+
end
|
|
78
|
+
return if TIMED_OUT.equal?(current)
|
|
79
|
+
|
|
80
|
+
update_reserved(&update)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def compare_and_set(expected, new_value, timeout: nil)
|
|
84
|
+
check_frozen!
|
|
85
|
+
current = reserve(timeout_deadline(timeout))
|
|
86
|
+
return false if TIMED_OUT.equal?(current)
|
|
87
|
+
|
|
88
|
+
matched = false
|
|
89
|
+
begin
|
|
90
|
+
matches = values_equal?(current, expected)
|
|
91
|
+
check_frozen!
|
|
92
|
+
matched = matches
|
|
93
|
+
ensure
|
|
94
|
+
finish_update(new_value, changed: matched)
|
|
95
|
+
end
|
|
96
|
+
matched
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def update(timeout: nil)
|
|
100
|
+
raise LocalJumpError, "no block given" unless block_given?
|
|
101
|
+
check_frozen!
|
|
102
|
+
deadline = timeout_deadline(timeout)
|
|
103
|
+
|
|
104
|
+
current = reserve(deadline)
|
|
105
|
+
return if TIMED_OUT.equal?(current)
|
|
106
|
+
|
|
107
|
+
update_reserved { yield(current) }
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def upsert(initial_value, timeout: nil)
|
|
111
|
+
raise LocalJumpError, "no block given" unless block_given?
|
|
112
|
+
check_frozen!
|
|
113
|
+
deadline = timeout_deadline(timeout)
|
|
114
|
+
|
|
115
|
+
current = reserve(deadline) do
|
|
116
|
+
next unless @value.nil?
|
|
117
|
+
|
|
118
|
+
@value = initial_value
|
|
119
|
+
changed!
|
|
120
|
+
return initial_value
|
|
121
|
+
end
|
|
122
|
+
return if TIMED_OUT.equal?(current)
|
|
123
|
+
|
|
124
|
+
update_reserved { yield(current) }
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def wait_until_changed(expected, timeout: nil, &fallback)
|
|
128
|
+
deadline = timeout_deadline(timeout)
|
|
129
|
+
|
|
130
|
+
loop do
|
|
131
|
+
current, version = @mutex.synchronize { [@value, @version] }
|
|
132
|
+
return current unless values_equal?(current, expected)
|
|
133
|
+
|
|
134
|
+
result = @mutex.synchronize do
|
|
135
|
+
next unless @version == version
|
|
136
|
+
reject_update_wait! if @updating
|
|
137
|
+
TIMED_OUT unless wait_for_signal(deadline)
|
|
138
|
+
end
|
|
139
|
+
return timed_out(result, fallback) if TIMED_OUT.equal?(result)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def wait_until_non_nil(timeout: nil, &) = wait_until_changed(nil, timeout:, &)
|
|
144
|
+
def compare_by_identity? = @compare_by_identity
|
|
145
|
+
|
|
146
|
+
alias value= store
|
|
147
|
+
|
|
148
|
+
private
|
|
149
|
+
|
|
150
|
+
def with_available_value(timeout)
|
|
151
|
+
deadline = timeout_deadline(timeout)
|
|
152
|
+
|
|
153
|
+
@mutex.synchronize do
|
|
154
|
+
while @updating
|
|
155
|
+
reject_update_wait!
|
|
156
|
+
return TIMED_OUT unless wait_for_signal(deadline)
|
|
157
|
+
end
|
|
158
|
+
yield
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def reserve(deadline)
|
|
163
|
+
@mutex.synchronize do
|
|
164
|
+
while @updating
|
|
165
|
+
reject_update_wait!
|
|
166
|
+
return TIMED_OUT unless wait_for_signal(deadline)
|
|
167
|
+
end
|
|
168
|
+
check_frozen_locked!
|
|
169
|
+
yield if block_given?
|
|
170
|
+
@updating = true
|
|
171
|
+
@updating_fiber = Fiber.current
|
|
172
|
+
@updating_thread = Thread.current
|
|
173
|
+
@value
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def update_reserved
|
|
178
|
+
changed = false
|
|
179
|
+
begin
|
|
180
|
+
result = yield
|
|
181
|
+
check_frozen!
|
|
182
|
+
changed = true
|
|
183
|
+
result
|
|
184
|
+
ensure
|
|
185
|
+
finish_update(result, changed:)
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def finish_update(value, changed:)
|
|
190
|
+
@mutex.synchronize do
|
|
191
|
+
@value = value if changed
|
|
192
|
+
@version += 1 if changed
|
|
193
|
+
@updating = false
|
|
194
|
+
@updating_fiber = nil
|
|
195
|
+
@updating_thread = nil
|
|
196
|
+
@signal.broadcast
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def changed!
|
|
201
|
+
@version += 1
|
|
202
|
+
@signal.broadcast
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def check_frozen!
|
|
206
|
+
@mutex.synchronize { check_frozen_locked! }
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def check_frozen_locked!
|
|
210
|
+
return unless @farce_frozen
|
|
211
|
+
|
|
212
|
+
raise FrozenError.new("can't modify frozen #{self.class}", receiver: self)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def timeout_deadline(timeout)
|
|
216
|
+
return unless timeout
|
|
217
|
+
|
|
218
|
+
timeout = Float(timeout)
|
|
219
|
+
raise ArgumentError, "timeout must be non-negative" if timeout.negative?
|
|
220
|
+
raise ArgumentError, "timeout must be finite" if timeout.infinite?
|
|
221
|
+
raise ArgumentError, "timeout must be a number" if timeout.nan?
|
|
222
|
+
|
|
223
|
+
Clock.now + timeout
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def wait_for_signal(deadline)
|
|
227
|
+
return @signal.wait(@mutex) unless deadline
|
|
228
|
+
|
|
229
|
+
remaining = deadline - Clock.now
|
|
230
|
+
return false unless remaining.positive?
|
|
231
|
+
|
|
232
|
+
@signal.wait(@mutex, remaining)
|
|
233
|
+
true
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def reject_update_wait!
|
|
237
|
+
raise ThreadError, "deadlock; recursive atom access during an update" if @updating_fiber.equal?(Fiber.current)
|
|
238
|
+
|
|
239
|
+
scheduler = Fiber.scheduler if Fiber.respond_to?(:scheduler)
|
|
240
|
+
return unless @updating_thread.equal?(Thread.current) && !scheduler
|
|
241
|
+
|
|
242
|
+
raise ThreadError, "deadlock; atom update is owned by another unscheduled fiber"
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def timed_out(result, fallback)
|
|
246
|
+
return result unless TIMED_OUT.equal?(result)
|
|
247
|
+
fallback&.call
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def values_equal?(left, right)
|
|
251
|
+
return left == right unless compare_by_identity?
|
|
252
|
+
left.equal?(right)
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
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 Internal # :nodoc: all
|
|
7
|
+
class UnsharedQueue < Queue
|
|
8
|
+
def initialize(capacity: 1024, fiber_wait: :auto, track_age: false)
|
|
9
|
+
raise ArgumentError, "fiber_wait must be :auto, :io, or :block" unless %i[auto io block].include?(fiber_wait)
|
|
10
|
+
super(capacity:, track_age:)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def fiber_wait = :auto
|
|
14
|
+
|
|
15
|
+
private def check_value(_item); end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
module Internal
|
|
7
|
+
class UnsharedSignal < Signal
|
|
8
|
+
def self.for(mode)
|
|
9
|
+
raise ArgumentError, "fiber_wait must be :auto, :io, or :block" unless %i[auto io block].include?(mode)
|
|
10
|
+
new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Alternative engines keep their existing scheduler coordination.
|
|
14
|
+
# @api private
|
|
15
|
+
def fiber_wait = :auto
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
UnsharedIOSignal = UnsharedSignal
|
|
19
|
+
UnsharedBlockSignal = UnsharedSignal
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
module Farce
|
|
6
|
+
# @!visibility private
|
|
7
|
+
module Internal # :nodoc: all
|
|
8
|
+
class UnsharedVector
|
|
9
|
+
def initialize(source = nil, compare_by_identity: false)
|
|
10
|
+
validate_boolean(compare_by_identity, "compare_by_identity")
|
|
11
|
+
raise TypeError, "source must be an Array" unless source.nil? || source.is_a?(Array)
|
|
12
|
+
|
|
13
|
+
@values = source ? Array.new(source) : []
|
|
14
|
+
@compare_by_identity = compare_by_identity
|
|
15
|
+
@mutex = Mutex.new
|
|
16
|
+
@signal = Signal.new
|
|
17
|
+
@updating = false
|
|
18
|
+
@farce_frozen = false
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @api private
|
|
22
|
+
def transaction_snapshot
|
|
23
|
+
PortableTransaction.snapshot(self, :vector)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def freeze
|
|
27
|
+
@mutex.synchronize { @farce_frozen = true }
|
|
28
|
+
self
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def frozen? = @mutex.synchronize { @farce_frozen }
|
|
32
|
+
|
|
33
|
+
def size = @mutex.synchronize { @values.size }
|
|
34
|
+
|
|
35
|
+
def snapshot = @mutex.synchronize { @values.dup }
|
|
36
|
+
|
|
37
|
+
def each
|
|
38
|
+
return enum_for(__method__) { size } unless block_given?
|
|
39
|
+
|
|
40
|
+
limit = size
|
|
41
|
+
index = 0
|
|
42
|
+
while index < limit
|
|
43
|
+
value = @mutex.synchronize do
|
|
44
|
+
return self if index >= @values.size
|
|
45
|
+
@values[index]
|
|
46
|
+
end
|
|
47
|
+
yield value
|
|
48
|
+
index += 1
|
|
49
|
+
end
|
|
50
|
+
self
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def reverse_each
|
|
54
|
+
return enum_for(__method__) { size } unless block_given?
|
|
55
|
+
|
|
56
|
+
index = size
|
|
57
|
+
while index.positive?
|
|
58
|
+
value = @mutex.synchronize do
|
|
59
|
+
index = @values.size if index > @values.size
|
|
60
|
+
index -= 1
|
|
61
|
+
return self if index.negative?
|
|
62
|
+
@values[index]
|
|
63
|
+
end
|
|
64
|
+
yield value
|
|
65
|
+
end
|
|
66
|
+
self
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def fetch(index)
|
|
70
|
+
index = convert_index(index)
|
|
71
|
+
found = true
|
|
72
|
+
value = @mutex.synchronize { @values.fetch(index) { found = false } }
|
|
73
|
+
return value if found
|
|
74
|
+
return yield(index) if block_given?
|
|
75
|
+
|
|
76
|
+
raise IndexError, "index #{index} outside of vector bounds"
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def [](index)
|
|
80
|
+
index = convert_index(index)
|
|
81
|
+
@mutex.synchronize { @values[index] }
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def []=(index, value)
|
|
85
|
+
check_frozen!
|
|
86
|
+
index = convert_index(index)
|
|
87
|
+
_, result = with_available(nil) do
|
|
88
|
+
check_frozen_locked!
|
|
89
|
+
store_value(index, value)
|
|
90
|
+
end
|
|
91
|
+
result
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def get(index, timeout: nil)
|
|
95
|
+
index = convert_index(index)
|
|
96
|
+
completed, result = with_available(timeout_deadline(timeout)) { @values[index] }
|
|
97
|
+
result if completed
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def store(index, value, timeout: nil)
|
|
101
|
+
check_frozen!
|
|
102
|
+
index = convert_index(index)
|
|
103
|
+
completed, result = with_available(timeout_deadline(timeout)) do
|
|
104
|
+
check_frozen_locked!
|
|
105
|
+
store_value(index, value)
|
|
106
|
+
end
|
|
107
|
+
completed ? result : false
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def clear
|
|
111
|
+
check_frozen!
|
|
112
|
+
with_available(nil) do
|
|
113
|
+
check_frozen_locked!
|
|
114
|
+
@values.clear
|
|
115
|
+
changed!
|
|
116
|
+
end
|
|
117
|
+
self
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def push(value, timeout: nil)
|
|
121
|
+
check_frozen!
|
|
122
|
+
completed, = with_available(timeout_deadline(timeout)) do
|
|
123
|
+
check_frozen_locked!
|
|
124
|
+
@values.push(value)
|
|
125
|
+
changed!
|
|
126
|
+
end
|
|
127
|
+
completed ? self : false
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def pop(timeout: nil)
|
|
131
|
+
check_frozen!
|
|
132
|
+
completed, result = with_available(timeout_deadline(timeout)) do
|
|
133
|
+
check_frozen_locked!
|
|
134
|
+
next if @values.empty?
|
|
135
|
+
|
|
136
|
+
value = @values.pop
|
|
137
|
+
changed!
|
|
138
|
+
value
|
|
139
|
+
end
|
|
140
|
+
result if completed
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def swap(index, replacement, timeout: nil)
|
|
144
|
+
check_frozen!
|
|
145
|
+
index = convert_index(index)
|
|
146
|
+
completed, result = with_available(timeout_deadline(timeout)) do
|
|
147
|
+
check_frozen_locked!
|
|
148
|
+
index = assignment_index(index)
|
|
149
|
+
previous = @values[index]
|
|
150
|
+
@values[index] = replacement
|
|
151
|
+
changed!
|
|
152
|
+
previous
|
|
153
|
+
end
|
|
154
|
+
result if completed
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def store_if_absent(index, timeout: nil)
|
|
158
|
+
raise LocalJumpError, "no block given" unless block_given?
|
|
159
|
+
check_frozen!
|
|
160
|
+
|
|
161
|
+
index = convert_index(index)
|
|
162
|
+
completed, reservation = reserve(timeout_deadline(timeout)) do
|
|
163
|
+
normalized = assignment_index(index)
|
|
164
|
+
current = @values[normalized]
|
|
165
|
+
if current.nil?
|
|
166
|
+
@updating = true
|
|
167
|
+
[:store, normalized]
|
|
168
|
+
else
|
|
169
|
+
[:existing, current]
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
return unless completed
|
|
173
|
+
return reservation.last if reservation.first == :existing
|
|
174
|
+
|
|
175
|
+
_, normalized = reservation
|
|
176
|
+
result = yield
|
|
177
|
+
check_frozen!
|
|
178
|
+
@mutex.synchronize { @values[normalized] = result }
|
|
179
|
+
result
|
|
180
|
+
ensure
|
|
181
|
+
finish_update if reservation&.first == :store
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def compare_and_set(index, expected, replacement, timeout: nil)
|
|
185
|
+
check_frozen!
|
|
186
|
+
index = convert_index(index)
|
|
187
|
+
completed, reservation = reserve(timeout_deadline(timeout)) do
|
|
188
|
+
normalized = lookup_index(index)
|
|
189
|
+
next unless normalized
|
|
190
|
+
|
|
191
|
+
@updating = true
|
|
192
|
+
[normalized, @values[normalized]]
|
|
193
|
+
end
|
|
194
|
+
return false unless completed && reservation
|
|
195
|
+
|
|
196
|
+
normalized, current = reservation
|
|
197
|
+
matches = values_equal?(current, expected)
|
|
198
|
+
check_frozen!
|
|
199
|
+
@mutex.synchronize { @values[normalized] = replacement if matches }
|
|
200
|
+
matches
|
|
201
|
+
ensure
|
|
202
|
+
finish_update if reservation
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def upsert(index, initial, timeout: nil)
|
|
206
|
+
raise LocalJumpError, "no block given" unless block_given?
|
|
207
|
+
check_frozen!
|
|
208
|
+
|
|
209
|
+
index = convert_index(index)
|
|
210
|
+
completed, reservation = reserve(timeout_deadline(timeout)) do
|
|
211
|
+
normalized = assignment_index(index)
|
|
212
|
+
current = @values[normalized]
|
|
213
|
+
if current.nil?
|
|
214
|
+
@values[normalized] = initial
|
|
215
|
+
changed!
|
|
216
|
+
[:stored, initial]
|
|
217
|
+
else
|
|
218
|
+
@updating = true
|
|
219
|
+
[:update, normalized, current]
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
return unless completed
|
|
223
|
+
return reservation.last if reservation.first == :stored
|
|
224
|
+
|
|
225
|
+
_, normalized, current = reservation
|
|
226
|
+
result = yield(current)
|
|
227
|
+
check_frozen!
|
|
228
|
+
@mutex.synchronize { @values[normalized] = result }
|
|
229
|
+
result
|
|
230
|
+
ensure
|
|
231
|
+
finish_update if reservation&.first == :update
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def update(index, timeout: nil)
|
|
235
|
+
raise LocalJumpError, "no block given" unless block_given?
|
|
236
|
+
check_frozen!
|
|
237
|
+
|
|
238
|
+
index = convert_index(index)
|
|
239
|
+
completed, reservation = reserve(timeout_deadline(timeout)) do
|
|
240
|
+
normalized = assignment_index(index)
|
|
241
|
+
@updating = true
|
|
242
|
+
[normalized, @values[normalized]]
|
|
243
|
+
end
|
|
244
|
+
return unless completed
|
|
245
|
+
|
|
246
|
+
normalized, current = reservation
|
|
247
|
+
result = yield(current)
|
|
248
|
+
check_frozen!
|
|
249
|
+
@mutex.synchronize { @values[normalized] = result }
|
|
250
|
+
result
|
|
251
|
+
ensure
|
|
252
|
+
finish_update if reservation
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
def wait_until_changed(index, expected, timeout: nil)
|
|
256
|
+
wait_for_value(convert_index(index), expected, timeout_deadline(timeout), non_nil: false)
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def wait_until_non_nil(index, timeout: nil)
|
|
260
|
+
wait_for_value(convert_index(index), nil, timeout_deadline(timeout), non_nil: true)
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
def compare_by_identity? = @compare_by_identity
|
|
264
|
+
|
|
265
|
+
private
|
|
266
|
+
|
|
267
|
+
def store_value(index, value)
|
|
268
|
+
@values[assignment_index(index)] = value
|
|
269
|
+
changed!
|
|
270
|
+
value
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
def with_available(deadline)
|
|
274
|
+
while true
|
|
275
|
+
generation = @signal.generation
|
|
276
|
+
completed, result = @mutex.synchronize do
|
|
277
|
+
@updating ? [false, nil] : [true, yield]
|
|
278
|
+
end
|
|
279
|
+
return [true, result] if completed
|
|
280
|
+
return [false, nil] unless wait_for_signal(generation, deadline)
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def reserve(deadline)
|
|
285
|
+
while true
|
|
286
|
+
generation = @signal.generation
|
|
287
|
+
completed, result = @mutex.synchronize do
|
|
288
|
+
if @updating
|
|
289
|
+
[false, nil]
|
|
290
|
+
else
|
|
291
|
+
check_frozen_locked!
|
|
292
|
+
[true, yield]
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
return [true, result] if completed
|
|
296
|
+
return [false, nil] unless wait_for_signal(generation, deadline)
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
def finish_update
|
|
301
|
+
@mutex.synchronize { @updating = false }
|
|
302
|
+
changed!
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
def changed! = @signal.broadcast
|
|
306
|
+
|
|
307
|
+
def check_frozen!
|
|
308
|
+
@mutex.synchronize { check_frozen_locked! }
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
def check_frozen_locked!
|
|
312
|
+
return unless @farce_frozen
|
|
313
|
+
|
|
314
|
+
raise FrozenError.new("can't modify frozen #{self.class}", receiver: self)
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
def wait_for_value(index, expected, deadline, non_nil:)
|
|
318
|
+
while true
|
|
319
|
+
generation = @signal.generation
|
|
320
|
+
current = @mutex.synchronize { @values[index] }
|
|
321
|
+
ready = non_nil ? !current.nil? : !values_equal?(current, expected)
|
|
322
|
+
return current if ready
|
|
323
|
+
return unless wait_for_signal(generation, deadline)
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
def wait_for_signal(generation, deadline)
|
|
328
|
+
return @signal.wait(generation) unless deadline
|
|
329
|
+
|
|
330
|
+
remaining = deadline - Clock.now
|
|
331
|
+
return false unless remaining.positive?
|
|
332
|
+
!@signal.wait(generation, timeout: remaining).nil?
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
def timeout_deadline(timeout)
|
|
336
|
+
return if timeout.nil?
|
|
337
|
+
|
|
338
|
+
timeout = Float(timeout)
|
|
339
|
+
if !timeout.finite? || timeout.negative?
|
|
340
|
+
raise ArgumentError, "timeout must be a finite, non-negative number or nil"
|
|
341
|
+
end
|
|
342
|
+
Clock.now + timeout
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
def lookup_index(index)
|
|
346
|
+
index += @values.size if index.negative?
|
|
347
|
+
index if index >= 0 && index < @values.size
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
def assignment_index(index)
|
|
351
|
+
return index unless index.negative?
|
|
352
|
+
|
|
353
|
+
normalized = @values.size + index
|
|
354
|
+
return normalized unless normalized.negative?
|
|
355
|
+
raise IndexError, "index #{index} too small for vector; minimum: -#{@values.size}"
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
def convert_index(index)
|
|
359
|
+
return index if index.is_a?(Integer)
|
|
360
|
+
|
|
361
|
+
raise TypeError, "no implicit conversion of #{index.class} into Integer" unless index.respond_to?(:to_int)
|
|
362
|
+
converted = index.to_int
|
|
363
|
+
return converted if converted.is_a?(Integer)
|
|
364
|
+
raise TypeError, "can't convert #{index.class} to Integer"
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
def validate_boolean(value, name)
|
|
368
|
+
return if value.equal?(true) || value.equal?(false)
|
|
369
|
+
raise ArgumentError, "#{name} must be true or false"
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
def values_equal?(left, right)
|
|
373
|
+
compare_by_identity? ? left.equal?(right) : left == right
|
|
374
|
+
end
|
|
375
|
+
end
|
|
376
|
+
end
|
|
377
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
require "farce/engine/shared/weak_atom/base"
|
|
6
|
+
require "farce/engine/shared/weak_map/reference"
|
|
7
|
+
|
|
8
|
+
module Farce
|
|
9
|
+
# @!visibility private
|
|
10
|
+
module Internal # :nodoc: all
|
|
11
|
+
class UnsharedWeakAtom < WeakAtomBase
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def initialize_storage(value)
|
|
15
|
+
@mutex = Mutex.new
|
|
16
|
+
@reference = UnsharedWeakMapWeakReference.for(value)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def read_value = @mutex.synchronize { @reference.read.last }
|
|
20
|
+
|
|
21
|
+
def write_value(value)
|
|
22
|
+
@mutex.synchronize do
|
|
23
|
+
@reference = UnsharedWeakMapWeakReference.for(value)
|
|
24
|
+
@changes.update { |generation| generation + 1 }
|
|
25
|
+
end
|
|
26
|
+
nil
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|