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,105 @@
|
|
|
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 Counter < Numeric
|
|
9
|
+
attr_reader :initial
|
|
10
|
+
|
|
11
|
+
def initialize(value = 0)
|
|
12
|
+
raise "Counter is already initialized" if defined?(@reference)
|
|
13
|
+
check_frozen!
|
|
14
|
+
raise TypeError, "initial value must be an Integer" unless value.is_a?(Integer)
|
|
15
|
+
@signal = Signal.new
|
|
16
|
+
@initial = value
|
|
17
|
+
@reference = TruffleRuby::AtomicReference.new(value)
|
|
18
|
+
super()
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def get = @reference.get
|
|
22
|
+
|
|
23
|
+
def store(value)
|
|
24
|
+
check_frozen!
|
|
25
|
+
raise TypeError, "value must be an Integer" unless value.is_a?(Integer)
|
|
26
|
+
@reference.set(value)
|
|
27
|
+
@signal.broadcast
|
|
28
|
+
value
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def swap(value)
|
|
32
|
+
check_frozen!
|
|
33
|
+
raise TypeError, "value must be an Integer" unless value.is_a?(Integer)
|
|
34
|
+
@reference.get_and_set(value).tap { @signal.broadcast }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def compare_and_set(expected_value, new_value)
|
|
38
|
+
check_frozen!
|
|
39
|
+
raise TypeError, "expected value must be an Integer" unless expected_value.is_a?(Integer)
|
|
40
|
+
raise TypeError, "replacement value must be an Integer" unless new_value.is_a?(Integer)
|
|
41
|
+
@reference.compare_and_set(expected_value, new_value).tap { @signal.broadcast }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def add(delta = 1)
|
|
45
|
+
check_frozen!
|
|
46
|
+
raise TypeError, "delta must be an Integer" unless delta.is_a?(Integer)
|
|
47
|
+
change(delta)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def subtract(delta = 1)
|
|
51
|
+
check_frozen!
|
|
52
|
+
raise TypeError, "delta must be an Integer" unless delta.is_a?(Integer)
|
|
53
|
+
change(-delta)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def increment(delta = 1)
|
|
57
|
+
check_frozen!
|
|
58
|
+
unless delta.is_a?(Integer)
|
|
59
|
+
delta = Integer(delta)
|
|
60
|
+
check_frozen!
|
|
61
|
+
end
|
|
62
|
+
change(delta)
|
|
63
|
+
self
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def decrement(delta = 1)
|
|
67
|
+
check_frozen!
|
|
68
|
+
unless delta.is_a?(Integer)
|
|
69
|
+
delta = Integer(delta)
|
|
70
|
+
check_frozen!
|
|
71
|
+
end
|
|
72
|
+
change(-delta)
|
|
73
|
+
self
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
alias value get
|
|
77
|
+
alias value= store
|
|
78
|
+
|
|
79
|
+
def change_signal = @signal
|
|
80
|
+
|
|
81
|
+
private
|
|
82
|
+
|
|
83
|
+
def check_frozen!
|
|
84
|
+
raise FrozenError.new("can't modify frozen #{self.class}", receiver: self) if frozen?
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def change(delta)
|
|
88
|
+
loop do
|
|
89
|
+
old_value = @reference.get
|
|
90
|
+
new_value = old_value + delta
|
|
91
|
+
if @reference.compare_and_set(old_value, new_value)
|
|
92
|
+
@signal.broadcast
|
|
93
|
+
return new_value
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def initialize_copy(other)
|
|
99
|
+
@signal = Signal.new
|
|
100
|
+
@initial = other.initial
|
|
101
|
+
@reference = TruffleRuby::AtomicReference.new(other.value)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
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 Flag
|
|
9
|
+
def initialize(value = false) # rubocop:disable Style/OptionalBooleanParameter
|
|
10
|
+
raise "Flag is already initialized" if defined?(@reference)
|
|
11
|
+
check_frozen!
|
|
12
|
+
@reference = TruffleRuby::AtomicReference.new(validate_boolean(value, "initial value"))
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def value = @reference.get
|
|
16
|
+
|
|
17
|
+
def set # rubocop:disable Naming/PredicateMethod
|
|
18
|
+
check_frozen!
|
|
19
|
+
@reference.set(true)
|
|
20
|
+
true
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def unset # rubocop:disable Naming/PredicateMethod
|
|
24
|
+
check_frozen!
|
|
25
|
+
@reference.set(false)
|
|
26
|
+
false
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def store(value)
|
|
30
|
+
check_frozen!
|
|
31
|
+
value = validate_boolean(value, "value")
|
|
32
|
+
@reference.set(value)
|
|
33
|
+
value
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def swap(value)
|
|
37
|
+
check_frozen!
|
|
38
|
+
value = validate_boolean(value, "value")
|
|
39
|
+
@reference.get_and_set(value)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def compare_and_set(expected_value, replacement_value)
|
|
43
|
+
check_frozen!
|
|
44
|
+
expected_value = validate_boolean(expected_value, "expected value")
|
|
45
|
+
replacement_value = validate_boolean(replacement_value, "replacement value")
|
|
46
|
+
@reference.compare_and_set(expected_value, replacement_value)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def toggle
|
|
50
|
+
check_frozen!
|
|
51
|
+
loop do
|
|
52
|
+
current = @reference.get
|
|
53
|
+
replacement = !current
|
|
54
|
+
return replacement if @reference.compare_and_set(current, replacement)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
alias get value
|
|
59
|
+
alias value= store
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
def check_frozen!
|
|
64
|
+
raise FrozenError.new("can't modify frozen #{self.class}", receiver: self) if frozen?
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def validate_boolean(value, name)
|
|
68
|
+
return value if value.equal?(true) || value.equal?(false)
|
|
69
|
+
raise ArgumentError, "#{name} must be true or false"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def initialize_copy(other)
|
|
73
|
+
@reference = TruffleRuby::AtomicReference.new(other.value)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
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
|
+
# Low-level operations shared by native TruffleRuby's ordered arrays.
|
|
9
|
+
# Bound primitive methods protect stored String snapshots and identity
|
|
10
|
+
# checks from user overrides.
|
|
11
|
+
module TruffleOrderedArraySupport
|
|
12
|
+
INTERRUPT_IMMEDIATE = { Exception => :immediate }.freeze
|
|
13
|
+
BASIC_OBJECT_EQUAL = BasicObject.instance_method(:equal?)
|
|
14
|
+
CLASS_ALLOCATE = Class.instance_method(:allocate)
|
|
15
|
+
OBJECT_CLASS = Object.instance_method(:class)
|
|
16
|
+
OBJECT_FREEZE = Object.instance_method(:freeze)
|
|
17
|
+
OBJECT_FROZEN = Object.instance_method(:frozen?)
|
|
18
|
+
OBJECT_INSTANCE_VARIABLES = Object.instance_method(:instance_variables)
|
|
19
|
+
OBJECT_INSTANCE_VARIABLE_GET = Object.instance_method(:instance_variable_get)
|
|
20
|
+
OBJECT_INSTANCE_VARIABLE_SET = Object.instance_method(:instance_variable_set)
|
|
21
|
+
OBJECT_IS_A = Object.instance_method(:is_a?)
|
|
22
|
+
STRING_INITIALIZE_COPY = String.instance_method(:initialize_copy)
|
|
23
|
+
STRING_UMINUS = String.instance_method(:-@)
|
|
24
|
+
|
|
25
|
+
private_constant :BASIC_OBJECT_EQUAL, :CLASS_ALLOCATE, :OBJECT_CLASS, :OBJECT_FREEZE,
|
|
26
|
+
:OBJECT_FROZEN, :OBJECT_INSTANCE_VARIABLES,
|
|
27
|
+
:OBJECT_INSTANCE_VARIABLE_GET, :OBJECT_INSTANCE_VARIABLE_SET,
|
|
28
|
+
:OBJECT_IS_A, :STRING_INITIALIZE_COPY, :STRING_UMINUS
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def primitive_freeze(object) = OBJECT_FREEZE.bind_call(object)
|
|
33
|
+
def primitive_frozen?(object) = OBJECT_FROZEN.bind_call(object)
|
|
34
|
+
def primitive_is_a?(object, klass) = OBJECT_IS_A.bind_call(object, klass)
|
|
35
|
+
def primitive_identical?(left, right) = BASIC_OBJECT_EQUAL.bind_call(left, right)
|
|
36
|
+
|
|
37
|
+
def canonical_ordered_key(key)
|
|
38
|
+
return key unless primitive_is_a?(key, String)
|
|
39
|
+
return STRING_UMINUS.bind_call(key) if
|
|
40
|
+
primitive_identical?(OBJECT_CLASS.bind_call(key), String)
|
|
41
|
+
|
|
42
|
+
snapshot_ordered_key(key)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def snapshot_ordered_key(key)
|
|
46
|
+
return key unless primitive_is_a?(key, String)
|
|
47
|
+
|
|
48
|
+
copy = CLASS_ALLOCATE.bind_call(OBJECT_CLASS.bind_call(key))
|
|
49
|
+
STRING_INITIALIZE_COPY.bind_call(copy, key)
|
|
50
|
+
OBJECT_INSTANCE_VARIABLES.bind_call(key).each do |name|
|
|
51
|
+
value = OBJECT_INSTANCE_VARIABLE_GET.bind_call(key, name)
|
|
52
|
+
OBJECT_INSTANCE_VARIABLE_SET.bind_call(copy, name, value)
|
|
53
|
+
end
|
|
54
|
+
primitive_freeze(copy)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def without_async_interrupts(&)
|
|
58
|
+
Thread.handle_interrupt(INTERRUPT_MASK, &)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def with_interruptible_callbacks(&)
|
|
62
|
+
Thread.handle_interrupt(INTERRUPT_IMMEDIATE, &)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
private_constant :TruffleOrderedArraySupport
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
require "farce/engine/truffleruby/native/ordered_array_support"
|
|
6
|
+
|
|
7
|
+
module Farce
|
|
8
|
+
# @!visibility private
|
|
9
|
+
module Internal # :nodoc: all
|
|
10
|
+
# Synchronized minimum-priority queue for native TruffleRuby. Binary
|
|
11
|
+
# search locates a priority bucket, whose small Array preserves FIFO order.
|
|
12
|
+
class PriorityQueue
|
|
13
|
+
include TruffleOrderedArraySupport
|
|
14
|
+
include Freeze::Unfreezable
|
|
15
|
+
|
|
16
|
+
DEFAULT_CAPACITY = nil
|
|
17
|
+
EMPTY = Object.new.freeze
|
|
18
|
+
INITIALIZATION_LOCK = Mutex.new
|
|
19
|
+
private_constant :DEFAULT_CAPACITY, :EMPTY, :INITIALIZATION_LOCK
|
|
20
|
+
|
|
21
|
+
Bucket = Struct.new(:priority, :items)
|
|
22
|
+
TrackedItem = Struct.new(:value, :enqueued_at)
|
|
23
|
+
private_constant :Bucket, :TrackedItem
|
|
24
|
+
|
|
25
|
+
class State
|
|
26
|
+
attr_accessor :size, :sealed, :closed, :generation, :operation_owner
|
|
27
|
+
attr_reader :buckets, :capacity, :signal, :lock, :tracked_items, :track_age
|
|
28
|
+
|
|
29
|
+
def initialize(capacity:, signal:, lock:, track_age:)
|
|
30
|
+
@buckets = []
|
|
31
|
+
@capacity = capacity
|
|
32
|
+
@signal = signal
|
|
33
|
+
@lock = lock
|
|
34
|
+
@size = 0
|
|
35
|
+
@sealed = false
|
|
36
|
+
@closed = false
|
|
37
|
+
@track_age = track_age
|
|
38
|
+
@tracked_items = [] if track_age
|
|
39
|
+
@generation = 0
|
|
40
|
+
@operation_owner = nil
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
private_constant :State
|
|
44
|
+
|
|
45
|
+
def initialize(capacity: DEFAULT_CAPACITY, signal: nil, track_age: false)
|
|
46
|
+
ensure_initializable!
|
|
47
|
+
capacity = normalize_capacity(capacity)
|
|
48
|
+
signal = normalize_signal(signal)
|
|
49
|
+
prepared = State.new(capacity:, signal:, lock: Lock.new, track_age: track_age ? true : false)
|
|
50
|
+
commit_initialization(prepared)
|
|
51
|
+
end
|
|
52
|
+
private :initialize
|
|
53
|
+
|
|
54
|
+
def initialize_copy(_other)
|
|
55
|
+
raise TypeError, "priority queues cannot be copied"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def push(priority, value)
|
|
59
|
+
state = initialized_state
|
|
60
|
+
with_queue_operation(state) do
|
|
61
|
+
raise_closed if state.closed
|
|
62
|
+
raise_sealed if state.sealed
|
|
63
|
+
next false if state.capacity && state.size >= state.capacity
|
|
64
|
+
|
|
65
|
+
stored = state.track_age ? TrackedItem.new(value, Clock.now) : value
|
|
66
|
+
|
|
67
|
+
index, found = locate_priority(state.buckets, priority)
|
|
68
|
+
if found
|
|
69
|
+
bucket = state.buckets[index]
|
|
70
|
+
prepared_items = bucket.items.dup << stored
|
|
71
|
+
notify_and_commit(state) do
|
|
72
|
+
bucket.items = prepared_items
|
|
73
|
+
state.size += 1
|
|
74
|
+
track_push(state, stored)
|
|
75
|
+
end
|
|
76
|
+
else
|
|
77
|
+
pending = Bucket.new(snapshot_ordered_key(priority), [stored])
|
|
78
|
+
notify_and_commit(state) do
|
|
79
|
+
index, duplicate = with_interruptible_callbacks do
|
|
80
|
+
locate_priority(state.buckets, priority)
|
|
81
|
+
end
|
|
82
|
+
raise "priority comparator changed during insertion" if duplicate
|
|
83
|
+
state.buckets.insert(index, pending)
|
|
84
|
+
state.size += 1
|
|
85
|
+
track_push(state, stored)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
true
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def pop(&fallback)
|
|
93
|
+
pop_endpoint(last: false, fallback:)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def pop_last(&fallback)
|
|
97
|
+
pop_endpoint(last: true, fallback:)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def pop_before(latest_priority, &fallback)
|
|
101
|
+
pop_endpoint(last: false, fallback:, latest_priority:)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def peek(&fallback)
|
|
105
|
+
read_endpoint(:value, last: false, fallback:)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def peek_last(&fallback)
|
|
109
|
+
read_endpoint(:value, last: true, fallback:)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def peek_priority(&fallback)
|
|
113
|
+
read_endpoint(:priority, last: false, fallback:)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def peek_last_priority(&fallback)
|
|
117
|
+
read_endpoint(:priority, last: true, fallback:)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def delete(priority, value)
|
|
121
|
+
delete_value(priority, value, identity: false)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def delete_identity(priority, value)
|
|
125
|
+
delete_value(priority, value, identity: true)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def delete_match(priority, pattern)
|
|
129
|
+
delete_value(priority, pattern, identity: false, match: true)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def size
|
|
133
|
+
state = initialized_state
|
|
134
|
+
with_queue_operation(state) { state.size }
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def empty?
|
|
138
|
+
state = initialized_state
|
|
139
|
+
with_queue_operation(state) { state.size.zero? } # rubocop:disable Style/ZeroLengthPredicate
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def capacity = initialized_state.capacity
|
|
143
|
+
|
|
144
|
+
def clear
|
|
145
|
+
state = initialized_state
|
|
146
|
+
with_queue_operation(state) do
|
|
147
|
+
notify_and_commit(state) do
|
|
148
|
+
state.buckets.clear
|
|
149
|
+
state.generation += 1 if state.track_age && state.size.positive?
|
|
150
|
+
state.size = 0
|
|
151
|
+
state.tracked_items&.clear
|
|
152
|
+
state.closed = true if state.sealed
|
|
153
|
+
end
|
|
154
|
+
self
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def close
|
|
159
|
+
state = initialized_state
|
|
160
|
+
with_queue_operation(state) do
|
|
161
|
+
notify_and_commit(state) do
|
|
162
|
+
state.generation += 1 if state.track_age && !state.closed
|
|
163
|
+
state.sealed = true
|
|
164
|
+
state.closed = true
|
|
165
|
+
end
|
|
166
|
+
self
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def closed?
|
|
171
|
+
state = initialized_state
|
|
172
|
+
with_queue_operation(state) { state.closed }
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def sealed?
|
|
176
|
+
state = initialized_state
|
|
177
|
+
with_queue_operation(state) { state.sealed }
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def age_tracking? = initialized_state.track_age
|
|
181
|
+
|
|
182
|
+
def generation
|
|
183
|
+
state = initialized_state
|
|
184
|
+
with_queue_operation(state) { state.track_age ? state.generation : nil }
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def oldest_enqueued_at
|
|
188
|
+
state = initialized_state
|
|
189
|
+
with_queue_operation(state) { state.tracked_items&.first&.enqueued_at }
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def oldest_age
|
|
193
|
+
timestamp = oldest_enqueued_at
|
|
194
|
+
Clock.now - timestamp if timestamp
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def seal
|
|
198
|
+
state = initialized_state
|
|
199
|
+
with_queue_operation(state) do
|
|
200
|
+
notify_and_commit(state) do
|
|
201
|
+
unless state.sealed
|
|
202
|
+
state.sealed = true
|
|
203
|
+
state.generation += 1 if state.track_age
|
|
204
|
+
end
|
|
205
|
+
state.closed = true if state.size.zero? # rubocop:disable Style/ZeroLengthPredicate
|
|
206
|
+
end
|
|
207
|
+
self
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
private
|
|
212
|
+
|
|
213
|
+
def pop_endpoint(last:, fallback:, latest_priority: UNDEFINED)
|
|
214
|
+
state = initialized_state
|
|
215
|
+
result = with_queue_operation(state) do
|
|
216
|
+
raise_closed if state.closed
|
|
217
|
+
bucket = last ? state.buckets.last : state.buckets.first
|
|
218
|
+
next EMPTY unless bucket
|
|
219
|
+
if !UNDEFINED.equal?(latest_priority) && compare_priorities(bucket.priority, latest_priority).positive?
|
|
220
|
+
next EMPTY
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
stored = bucket.items.first
|
|
224
|
+
prepared_items = bucket.items.drop(1)
|
|
225
|
+
notify_and_commit(state) do
|
|
226
|
+
if prepared_items.empty?
|
|
227
|
+
last ? state.buckets.pop : state.buckets.shift
|
|
228
|
+
else
|
|
229
|
+
bucket.items = prepared_items
|
|
230
|
+
end
|
|
231
|
+
state.size -= 1
|
|
232
|
+
track_remove(state, stored)
|
|
233
|
+
state.closed = true if state.sealed && state.size.zero? # rubocop:disable Style/ZeroLengthPredicate
|
|
234
|
+
end
|
|
235
|
+
tracked_value(state, stored)
|
|
236
|
+
end
|
|
237
|
+
return result unless EMPTY.equal?(result)
|
|
238
|
+
fallback&.call
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
def ensure_initializable!
|
|
242
|
+
raise "priority queue is already initialized" if @state
|
|
243
|
+
raise FrozenError, "can't modify frozen priority queue" if primitive_frozen?(self)
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def commit_initialization(prepared)
|
|
247
|
+
INITIALIZATION_LOCK.synchronize do
|
|
248
|
+
raise "priority queue is already initialized" if @state
|
|
249
|
+
raise FrozenError, "can't modify frozen priority queue" if primitive_frozen?(self)
|
|
250
|
+
|
|
251
|
+
without_async_interrupts do
|
|
252
|
+
@state = prepared
|
|
253
|
+
primitive_freeze(self)
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
self
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def initialized_state
|
|
260
|
+
@state || raise("uninitialized priority queue")
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
def normalize_capacity(capacity)
|
|
264
|
+
return nil if capacity.nil?
|
|
265
|
+
capacity = capacity.to_int unless primitive_is_a?(capacity, Integer)
|
|
266
|
+
raise TypeError, "capacity must be an Integer or nil" unless primitive_is_a?(capacity, Integer)
|
|
267
|
+
raise ArgumentError, "capacity must be positive or nil" unless capacity.positive?
|
|
268
|
+
capacity
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
def normalize_signal(signal)
|
|
272
|
+
return if signal.nil?
|
|
273
|
+
raise TypeError, "signal must respond to #broadcast" unless signal.respond_to?(:broadcast)
|
|
274
|
+
signal
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def with_queue_operation(state)
|
|
278
|
+
current = Fiber.current
|
|
279
|
+
raise ThreadError, "deadlock; recursive priority queue access" if
|
|
280
|
+
primitive_identical?(state.operation_owner, current)
|
|
281
|
+
|
|
282
|
+
state.lock.synchronize do
|
|
283
|
+
without_async_interrupts { state.operation_owner = current }
|
|
284
|
+
yield
|
|
285
|
+
ensure
|
|
286
|
+
without_async_interrupts do
|
|
287
|
+
state.operation_owner = nil if primitive_identical?(state.operation_owner, current)
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def read_endpoint(kind, last:, fallback:)
|
|
293
|
+
state = initialized_state
|
|
294
|
+
result = with_queue_operation(state) do
|
|
295
|
+
raise_closed if state.closed
|
|
296
|
+
bucket = last ? state.buckets.last : state.buckets.first
|
|
297
|
+
next EMPTY unless bucket
|
|
298
|
+
kind == :priority ? bucket.priority : tracked_value(state, bucket.items.first)
|
|
299
|
+
end
|
|
300
|
+
EMPTY.equal?(result) ? fallback&.call : result
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
def delete_value(priority, value, identity:, match: false)
|
|
304
|
+
state = initialized_state
|
|
305
|
+
with_queue_operation(state) do
|
|
306
|
+
raise_closed if state.closed
|
|
307
|
+
bucket_index, found = locate_priority(state.buckets, priority)
|
|
308
|
+
next false unless found
|
|
309
|
+
|
|
310
|
+
bucket = state.buckets[bucket_index]
|
|
311
|
+
item_index = if identity
|
|
312
|
+
bucket.items.index { primitive_identical?(tracked_value(state, it), value) }
|
|
313
|
+
elsif match
|
|
314
|
+
bucket.items.index { value === tracked_value(state, it) } # rubocop:disable Style/CaseEquality
|
|
315
|
+
else
|
|
316
|
+
bucket.items.index { tracked_value(state, it) == value }
|
|
317
|
+
end
|
|
318
|
+
next false unless item_index
|
|
319
|
+
|
|
320
|
+
removed = bucket.items[item_index]
|
|
321
|
+
prepared_items = bucket.items.dup
|
|
322
|
+
prepared_items.delete_at(item_index)
|
|
323
|
+
notify_and_commit(state) do
|
|
324
|
+
if prepared_items.empty?
|
|
325
|
+
state.buckets.delete_at(bucket_index)
|
|
326
|
+
else
|
|
327
|
+
bucket.items = prepared_items
|
|
328
|
+
end
|
|
329
|
+
state.size -= 1
|
|
330
|
+
track_remove(state, removed)
|
|
331
|
+
state.closed = true if state.sealed && state.size.zero? # rubocop:disable Style/ZeroLengthPredicate
|
|
332
|
+
end
|
|
333
|
+
true
|
|
334
|
+
end
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
def locate_priority(buckets, priority)
|
|
338
|
+
low = 0
|
|
339
|
+
high = buckets.length
|
|
340
|
+
while low < high
|
|
341
|
+
middle = (low + high) / 2
|
|
342
|
+
order = compare_priorities(priority, buckets[middle].priority)
|
|
343
|
+
return [middle, true] if order.zero?
|
|
344
|
+
order.negative? ? high = middle : low = middle + 1
|
|
345
|
+
end
|
|
346
|
+
[low, false]
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
def compare_priorities(left, right)
|
|
350
|
+
result = left <=> right
|
|
351
|
+
raise ArgumentError, "priority comparison failed" if result.nil?
|
|
352
|
+
# rb_cmpint calls #> and #< when <=> returns a non-Integer object.
|
|
353
|
+
return 1 if result > 0 # rubocop:disable Style/NumericPredicate
|
|
354
|
+
return -1 if result < 0 # rubocop:disable Style/NumericPredicate
|
|
355
|
+
0
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
def notify_and_commit(state)
|
|
359
|
+
without_async_interrupts do
|
|
360
|
+
with_interruptible_callbacks { state.signal.broadcast } if state.signal
|
|
361
|
+
yield
|
|
362
|
+
end
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
def tracked_value(state, item) = state.track_age ? item.value : item
|
|
366
|
+
|
|
367
|
+
def track_push(state, item)
|
|
368
|
+
return unless state.track_age
|
|
369
|
+
state.tracked_items << item
|
|
370
|
+
state.generation += 1
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
def track_remove(state, item)
|
|
374
|
+
return unless state.track_age
|
|
375
|
+
state.tracked_items.delete(item)
|
|
376
|
+
state.generation += 1
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
def raise_closed
|
|
380
|
+
raise ::Farce::ClosedQueueError, "queue is closed"
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
def raise_sealed
|
|
384
|
+
raise ::Farce::SealedQueueError, "queue is sealed"
|
|
385
|
+
end
|
|
386
|
+
end
|
|
387
|
+
end
|
|
388
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
require "farce/engine/truffleruby/native/unsafe_tree_map"
|
|
6
|
+
|
|
7
|
+
module Farce
|
|
8
|
+
# @!visibility private
|
|
9
|
+
module Internal # :nodoc: all
|
|
10
|
+
# Synchronized native-TruffleRuby map. Storage and ordered operations come
|
|
11
|
+
# from UnsafeTreeMap; this subclass adds coordination and guarded mutability.
|
|
12
|
+
class TreeMap < UnsafeTreeMap
|
|
13
|
+
def transaction_snapshot
|
|
14
|
+
state = initialized_state
|
|
15
|
+
entries, revision = with_map_operation(state, mutation: false) do
|
|
16
|
+
[state.entries.map { Entry.new(it.key, it.value) }, state.revision]
|
|
17
|
+
end
|
|
18
|
+
working = self.class.new
|
|
19
|
+
working.instance_variable_get(:@state).instance_variable_set(:@entries, entries)
|
|
20
|
+
PortableTransaction::TreeEntry.new(self, working, revision, state.lock, :@entries)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def synchronized? = true
|
|
26
|
+
def operation_lock = Lock.new
|
|
27
|
+
def ensure_mutation_still_allowed! = Internal::Freeze.check(self)
|
|
28
|
+
|
|
29
|
+
def with_map_operation(state, mutation:)
|
|
30
|
+
current = Fiber.current
|
|
31
|
+
raise ThreadError, "deadlock; recursive tree map access" if
|
|
32
|
+
primitive_identical?(state.operation_owner, current)
|
|
33
|
+
|
|
34
|
+
state.lock.synchronize do
|
|
35
|
+
ensure_mutation_still_allowed! if mutation
|
|
36
|
+
without_async_interrupts { state.operation_owner = current }
|
|
37
|
+
yield
|
|
38
|
+
ensure
|
|
39
|
+
without_async_interrupts do
|
|
40
|
+
state.operation_owner = nil if primitive_identical?(state.operation_owner, current)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
MutableTreeMap = TreeMap
|
|
47
|
+
|
|
48
|
+
# No Ractors, no problems :)
|
|
49
|
+
ShareableTreeMap = TreeMap
|
|
50
|
+
end
|
|
51
|
+
end
|