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,317 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
require "farce/internal/copyable"
|
|
6
|
+
require "farce/shareable"
|
|
7
|
+
require "farce/strict"
|
|
8
|
+
|
|
9
|
+
module Farce
|
|
10
|
+
# @!visibility private
|
|
11
|
+
module Internal # :nodoc: all
|
|
12
|
+
# Portable immutable backend for {Farce::Strict::Trie}.
|
|
13
|
+
class PortableTrie
|
|
14
|
+
attr_reader :stats
|
|
15
|
+
|
|
16
|
+
EMPTY_CAPTURES = [].freeze
|
|
17
|
+
EMPTY_NAMED_CAPTURES = {}.freeze
|
|
18
|
+
|
|
19
|
+
class Node
|
|
20
|
+
EMPTY_STATIC = {}.freeze
|
|
21
|
+
|
|
22
|
+
attr_reader :dynamic, :dynamic_index, :fast_static, :static, :static_depth, :stride, :tokens
|
|
23
|
+
|
|
24
|
+
def initialize
|
|
25
|
+
@static = {}
|
|
26
|
+
@dynamic = []
|
|
27
|
+
@dynamic_index = {}
|
|
28
|
+
@tokens = []
|
|
29
|
+
@fast_static = nil
|
|
30
|
+
@static_depth = 0
|
|
31
|
+
@stride = 1
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def measure_static_depth
|
|
35
|
+
@static_depth =
|
|
36
|
+
if @dynamic.empty? && @tokens.empty? && !@static.empty?
|
|
37
|
+
1 + @static.each_value.map(&:static_depth).min
|
|
38
|
+
else
|
|
39
|
+
0
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def optimize
|
|
44
|
+
return if @static_depth <= 1
|
|
45
|
+
|
|
46
|
+
@stride = @static_depth
|
|
47
|
+
frontier = [[nil, self]]
|
|
48
|
+
@stride.times do
|
|
49
|
+
next_frontier = []
|
|
50
|
+
frontier.each do |prefix, node|
|
|
51
|
+
if node.static.length == 1
|
|
52
|
+
character, child = node.static.first
|
|
53
|
+
prefix = prefix ? prefix << character : String.new(character)
|
|
54
|
+
next_frontier << [prefix, child]
|
|
55
|
+
else
|
|
56
|
+
node.static.each do |character, child|
|
|
57
|
+
next_prefix = prefix ? prefix + character : String.new(character)
|
|
58
|
+
next_frontier << [next_prefix, child]
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
frontier = next_frontier
|
|
63
|
+
end
|
|
64
|
+
@fast_static = frontier.to_h { |prefix, node| [prefix.freeze, node] }.freeze
|
|
65
|
+
@static = EMPTY_STATIC
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def freeze
|
|
69
|
+
@static.freeze
|
|
70
|
+
@dynamic.each(&:freeze)
|
|
71
|
+
@dynamic.freeze
|
|
72
|
+
@dynamic_index = nil
|
|
73
|
+
@tokens.freeze
|
|
74
|
+
super
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
private_constant :Node
|
|
78
|
+
|
|
79
|
+
def initialize(entries, tokens)
|
|
80
|
+
validate_array!(entries, "entries")
|
|
81
|
+
validate_array!(tokens, "tokens")
|
|
82
|
+
validate_tokens!(tokens)
|
|
83
|
+
|
|
84
|
+
@tokens = Array.new(tokens).freeze
|
|
85
|
+
@root = Node.new
|
|
86
|
+
nodes = [@root]
|
|
87
|
+
static_edges = 0
|
|
88
|
+
regexp_edges = 0
|
|
89
|
+
|
|
90
|
+
Array.new(entries).each do |entry|
|
|
91
|
+
validate_array!(entry, "entry")
|
|
92
|
+
raise ArgumentError, "entry must contain parts and a token ID" unless entry.length == 2
|
|
93
|
+
|
|
94
|
+
parts, token_id = entry
|
|
95
|
+
validate_array!(parts, "parts")
|
|
96
|
+
unless token_id.is_a?(Integer) && token_id >= 0 && token_id < @tokens.length
|
|
97
|
+
raise ArgumentError, "token ID is out of range: #{token_id.inspect}"
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
node = @root
|
|
101
|
+
Array.new(parts).each do |part|
|
|
102
|
+
case part
|
|
103
|
+
when String
|
|
104
|
+
literal = String.new(part)
|
|
105
|
+
validate_encoding!(literal, "edge")
|
|
106
|
+
literal.each_char do |character|
|
|
107
|
+
child = node.static[character]
|
|
108
|
+
unless child
|
|
109
|
+
child = Node.new
|
|
110
|
+
node.static[character.freeze] = child
|
|
111
|
+
nodes << child
|
|
112
|
+
static_edges += 1
|
|
113
|
+
end
|
|
114
|
+
node = child
|
|
115
|
+
end
|
|
116
|
+
when Regexp
|
|
117
|
+
key = regexp_key(part)
|
|
118
|
+
child = node.dynamic_index[key]
|
|
119
|
+
unless child
|
|
120
|
+
child = Node.new
|
|
121
|
+
node.dynamic << [anchor(part), child]
|
|
122
|
+
node.dynamic_index[key] = child
|
|
123
|
+
nodes << child
|
|
124
|
+
regexp_edges += 1
|
|
125
|
+
end
|
|
126
|
+
node = child
|
|
127
|
+
else
|
|
128
|
+
raise TypeError, "edge must be a String or Regexp, got #{part.class}"
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
node.tokens << token_id
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
nodes.reverse_each(&:measure_static_depth)
|
|
135
|
+
frontier = [@root]
|
|
136
|
+
until frontier.empty?
|
|
137
|
+
node = frontier.pop
|
|
138
|
+
node.optimize
|
|
139
|
+
(node.fast_static || node.static).each_value { |child| frontier << child }
|
|
140
|
+
node.dynamic.each { |edge| frontier << edge.last }
|
|
141
|
+
end
|
|
142
|
+
nodes.each(&:freeze)
|
|
143
|
+
@stats = {
|
|
144
|
+
nodes: nodes.length,
|
|
145
|
+
static_edges:,
|
|
146
|
+
regexp_edges:,
|
|
147
|
+
native_regexp_edges: 0,
|
|
148
|
+
ruby_regexp_edges: regexp_edges,
|
|
149
|
+
}.freeze
|
|
150
|
+
freeze
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def match(input) = find(input, all: false, peek: false)
|
|
154
|
+
def match_all(input) = find(input, all: true, peek: false)
|
|
155
|
+
def peek(input) = find(input, all: false, peek: true)
|
|
156
|
+
def peek_all(input) = find(input, all: true, peek: true)
|
|
157
|
+
|
|
158
|
+
def each_match(input, &block)
|
|
159
|
+
return enum_for(__method__, input) unless block
|
|
160
|
+
|
|
161
|
+
each_result(input, peek: false, deduplicate: true, &block)
|
|
162
|
+
self
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def each_peek(input, &block)
|
|
166
|
+
return enum_for(__method__, input) unless block
|
|
167
|
+
|
|
168
|
+
each_result(input, peek: true, deduplicate: true, &block)
|
|
169
|
+
self
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
private
|
|
173
|
+
|
|
174
|
+
def anchor(regexp)
|
|
175
|
+
compile_regexp("\\G(?:#{regexp.source})", regexp)
|
|
176
|
+
rescue RegexpError
|
|
177
|
+
compile_regexp("\\G(?:#{regexp.source}\n)", regexp)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def compile_regexp(source, regexp)
|
|
181
|
+
if regexp.respond_to?(:timeout)
|
|
182
|
+
Regexp.new(source, regexp.options, timeout: regexp.timeout).freeze
|
|
183
|
+
else
|
|
184
|
+
Regexp.new(source, regexp.options).freeze
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def regexp_key(regexp)
|
|
189
|
+
timeout = regexp.timeout if regexp.respond_to?(:timeout)
|
|
190
|
+
[regexp.source, regexp.options, regexp.encoding, timeout].freeze
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def validate_array!(value, name)
|
|
194
|
+
raise TypeError, "#{name} must be an Array" unless value.is_a?(Array)
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def validate_tokens!(tokens)
|
|
198
|
+
seen = {}.compare_by_identity
|
|
199
|
+
tokens.each do |token|
|
|
200
|
+
raise Ractor::IsolationError, "token is not Ractor-shareable" unless Ractor.shareable?(token)
|
|
201
|
+
raise ArgumentError, "tokens must be unique by identity" if seen.key?(token)
|
|
202
|
+
|
|
203
|
+
seen[token] = true
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def validate_encoding!(string, label)
|
|
208
|
+
return if string.valid_encoding?
|
|
209
|
+
|
|
210
|
+
raise ArgumentError, "#{label} has an invalid #{string.encoding} byte sequence"
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def find(input, all:, peek:)
|
|
214
|
+
results = [] if all
|
|
215
|
+
each_result(input, peek:, deduplicate: all) do |token, captures, named, suffix|
|
|
216
|
+
tuple = [token, captures, named, suffix]
|
|
217
|
+
return tuple unless all
|
|
218
|
+
|
|
219
|
+
results << tuple
|
|
220
|
+
end
|
|
221
|
+
all ? results : nil
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def each_result(input, peek:, deduplicate:)
|
|
225
|
+
raise TypeError, "input must be a String" unless input.is_a?(String)
|
|
226
|
+
input = String.new(input)
|
|
227
|
+
validate_encoding!(input, "input")
|
|
228
|
+
|
|
229
|
+
input_length = input.length
|
|
230
|
+
seen = {} if deduplicate
|
|
231
|
+
stack = [[@root, 0, EMPTY_CAPTURES, EMPTY_NAMED_CAPTURES, 0, 0]]
|
|
232
|
+
|
|
233
|
+
until stack.empty?
|
|
234
|
+
node, position, captures, named, phase, index = stack.pop
|
|
235
|
+
case phase
|
|
236
|
+
when 0
|
|
237
|
+
stack << [node, position, captures, named, 1, 0]
|
|
238
|
+
if node.fast_static
|
|
239
|
+
key = input[position, node.stride]
|
|
240
|
+
if key && (child = node.fast_static[key])
|
|
241
|
+
stack << [child, position + node.stride, captures, named, 0, 0]
|
|
242
|
+
end
|
|
243
|
+
elsif position < input_length && (child = node.static[input[position]])
|
|
244
|
+
stack << [child, position + 1, captures, named, 0, 0]
|
|
245
|
+
end
|
|
246
|
+
when 1
|
|
247
|
+
if index < node.dynamic.length
|
|
248
|
+
regexp, child = node.dynamic[index]
|
|
249
|
+
stack << [node, position, captures, named, 1, index + 1]
|
|
250
|
+
if (matched = regexp.match(input, position))
|
|
251
|
+
stack << [
|
|
252
|
+
child,
|
|
253
|
+
matched.end(0),
|
|
254
|
+
captures + matched.captures,
|
|
255
|
+
merge_named_captures(named, matched.named_captures),
|
|
256
|
+
0,
|
|
257
|
+
0
|
|
258
|
+
]
|
|
259
|
+
end
|
|
260
|
+
elsif (peek || position == input_length) && !node.tokens.empty?
|
|
261
|
+
node.tokens.each do |token_id|
|
|
262
|
+
next if deduplicate && seen.key?(token_id)
|
|
263
|
+
|
|
264
|
+
seen[token_id] = true if deduplicate
|
|
265
|
+
yield(
|
|
266
|
+
@tokens.fetch(token_id),
|
|
267
|
+
captures.map { |value| value&.dup },
|
|
268
|
+
copy_named_captures(named),
|
|
269
|
+
input[position..] || +""
|
|
270
|
+
)
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def merge_named_captures(base, additions)
|
|
278
|
+
return base if additions.empty?
|
|
279
|
+
|
|
280
|
+
merged = base.dup
|
|
281
|
+
additions.each do |name, value|
|
|
282
|
+
unless merged.key?(name)
|
|
283
|
+
merged[name] = value
|
|
284
|
+
next
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
previous = merged[name]
|
|
288
|
+
merged[name] = previous.is_a?(Array) ? previous + [value] : [previous, value]
|
|
289
|
+
end
|
|
290
|
+
merged
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def copy_named_captures(named)
|
|
294
|
+
named.to_h do |name, value|
|
|
295
|
+
copied = if value.is_a?(Array)
|
|
296
|
+
value.map { |element| element&.dup }
|
|
297
|
+
else
|
|
298
|
+
value&.dup
|
|
299
|
+
end
|
|
300
|
+
[name.dup, copied]
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
module Strict
|
|
307
|
+
unless const_defined?(:Trie, false)
|
|
308
|
+
# Portable implementation used on JRuby and TruffleRuby.
|
|
309
|
+
class Trie < Internal::PortableTrie
|
|
310
|
+
include Internal::Copyable
|
|
311
|
+
include Shareable::Immutable
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
require "farce/engine/shared/trie_builder"
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
# warn_indent: true
|
|
4
|
+
|
|
5
|
+
require "farce/internal/copyable"
|
|
6
|
+
require "farce/shareable"
|
|
7
|
+
|
|
8
|
+
module Farce
|
|
9
|
+
module Strict
|
|
10
|
+
# An immutable Ractor-shareable trie for String and Regexp chains.
|
|
11
|
+
#
|
|
12
|
+
# Build a trie with {.build} or {Builder}. Published tries do not change.
|
|
13
|
+
# A reusable builder can publish additional independent snapshots.
|
|
14
|
+
#
|
|
15
|
+
# Static edges take precedence over regexp edges. Regexp edges retain their
|
|
16
|
+
# insertion order. `peek` searches descendants before returning a shorter
|
|
17
|
+
# terminal match. A regexp edge is atomic. Later edges cannot make a regexp
|
|
18
|
+
# choose a different endpoint.
|
|
19
|
+
#
|
|
20
|
+
# Tokens must already be Ractor-shareable. They are stored and returned
|
|
21
|
+
# unchanged. Equal but different token objects remain separate. Reusing the
|
|
22
|
+
# same token object produces at most one result per lookup.
|
|
23
|
+
#
|
|
24
|
+
# Each result is `[token, positional_captures, named_captures, suffix]`.
|
|
25
|
+
# Exact matches have an empty suffix. Capture arrays, hashes, strings, and
|
|
26
|
+
# suffixes are new mutable objects for each result. A capture string may
|
|
27
|
+
# be shared between the positional and named views within one result.
|
|
28
|
+
#
|
|
29
|
+
# Input and literal edges retain Ruby String encoding behavior. Invalid byte
|
|
30
|
+
# sequences are rejected. ASCII-8BIT strings provide binary matching.
|
|
31
|
+
# Incompatible literal encodings do not match. Regexp encoding errors retain
|
|
32
|
+
# Ruby's ordinary behavior.
|
|
33
|
+
#
|
|
34
|
+
# `dup` and `clone` return frozen, Ractor-shareable matchers with the same
|
|
35
|
+
# immutable graph and token objects. This also applies to
|
|
36
|
+
# `clone(freeze: false)`.
|
|
37
|
+
#
|
|
38
|
+
# @example Build and match a trie
|
|
39
|
+
# routes = Farce::Strict::Trie.build do |builder|
|
|
40
|
+
# builder.add(["/users/", /(?<id>\d+)/], :user)
|
|
41
|
+
# end
|
|
42
|
+
#
|
|
43
|
+
# routes.match("/users/12")
|
|
44
|
+
# # => [:user, ["12"], { "id" => "12" }, ""]
|
|
45
|
+
#
|
|
46
|
+
# @!method match(input)
|
|
47
|
+
# Return the first exact match.
|
|
48
|
+
# @param input [String]
|
|
49
|
+
# @return [Array(Object, Array<String, nil>, Hash{String => Object}, String), nil]
|
|
50
|
+
#
|
|
51
|
+
# @!method match_all(input)
|
|
52
|
+
# Return every exact match in traversal order.
|
|
53
|
+
# @param input [String]
|
|
54
|
+
# @return [Array<Array>]
|
|
55
|
+
#
|
|
56
|
+
# @!method peek(input)
|
|
57
|
+
# Return the first prefix match.
|
|
58
|
+
# @param input [String]
|
|
59
|
+
# @return [Array(Object, Array<String, nil>, Hash{String => Object}, String), nil]
|
|
60
|
+
#
|
|
61
|
+
# @!method peek_all(input)
|
|
62
|
+
# Return every prefix match in traversal order.
|
|
63
|
+
# @param input [String]
|
|
64
|
+
# @return [Array<Array>]
|
|
65
|
+
#
|
|
66
|
+
# @!method each_match(input)
|
|
67
|
+
# Yield each exact match without first collecting every result.
|
|
68
|
+
# Each yield has four arguments: token, positional captures, named
|
|
69
|
+
# captures, and suffix.
|
|
70
|
+
# @param input [String]
|
|
71
|
+
# @yieldparam token [Object]
|
|
72
|
+
# @yieldparam positional_captures [Array<String, nil>]
|
|
73
|
+
# @yieldparam named_captures [Hash{String => Object}]
|
|
74
|
+
# @yieldparam suffix [String]
|
|
75
|
+
# @return [Trie, Enumerator] self after normal exhaustion, or an Enumerator
|
|
76
|
+
# when no block is given
|
|
77
|
+
#
|
|
78
|
+
# @!method each_peek(input)
|
|
79
|
+
# Yield each prefix match without first collecting every result.
|
|
80
|
+
# Each yield has four arguments: token, positional captures, named
|
|
81
|
+
# captures, and suffix.
|
|
82
|
+
# @param input [String]
|
|
83
|
+
# @yieldparam token [Object]
|
|
84
|
+
# @yieldparam positional_captures [Array<String, nil>]
|
|
85
|
+
# @yieldparam named_captures [Hash{String => Object}]
|
|
86
|
+
# @yieldparam suffix [String]
|
|
87
|
+
# @return [Trie, Enumerator] self after normal exhaustion, or an Enumerator
|
|
88
|
+
# when no block is given
|
|
89
|
+
class Trie
|
|
90
|
+
include Internal::MarshalSupport::Reject
|
|
91
|
+
include Internal::Copyable unless ancestors.include?(Internal::Copyable)
|
|
92
|
+
include Shareable::Immutable unless ancestors.include?(Shareable::Immutable)
|
|
93
|
+
|
|
94
|
+
# Collects entries and publishes immutable {Trie} snapshots.
|
|
95
|
+
class Builder
|
|
96
|
+
# Create an empty builder.
|
|
97
|
+
def initialize
|
|
98
|
+
@entries = []
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# @api private
|
|
102
|
+
def marshal_dump
|
|
103
|
+
entries = @entries.map { |parts, token| [parts, Internal::MarshalSupport.value(token)] }
|
|
104
|
+
[1, entries, frozen?]
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# @api private
|
|
108
|
+
def marshal_load(data)
|
|
109
|
+
entries, frozen = Internal::MarshalSupport.payload(data, 2)
|
|
110
|
+
initialize
|
|
111
|
+
entries.each { |parts, token| add(parts, Internal::MarshalSupport.restore_value(token)) }
|
|
112
|
+
freeze if frozen
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Add a String and Regexp chain.
|
|
116
|
+
#
|
|
117
|
+
# Literal strings are copied immediately. The token is not copied or
|
|
118
|
+
# frozen and must already be Ractor-shareable. A published trie retains
|
|
119
|
+
# a plain semantic copy of each regexp, not caller-owned regexp state.
|
|
120
|
+
#
|
|
121
|
+
# @param parts [Array<String, Regexp>] ordered matcher edges
|
|
122
|
+
# @param token [Object] the object returned for a match
|
|
123
|
+
# @return [Builder] self
|
|
124
|
+
# @raise [TypeError] if parts or one of its elements has the wrong type
|
|
125
|
+
# @raise [ArgumentError] if a literal has an invalid byte sequence
|
|
126
|
+
# @raise [Ractor::IsolationError] if token is not Ractor-shareable
|
|
127
|
+
def add(parts, token)
|
|
128
|
+
raise TypeError, "parts must be an Array" unless parts.is_a?(Array)
|
|
129
|
+
raise Ractor::IsolationError, "token is not Ractor-shareable" unless Ractor.shareable?(token)
|
|
130
|
+
|
|
131
|
+
snapshot = Array.new(parts).map do |part|
|
|
132
|
+
case part
|
|
133
|
+
when String
|
|
134
|
+
snapshot_literal(part)
|
|
135
|
+
when Regexp
|
|
136
|
+
part
|
|
137
|
+
else
|
|
138
|
+
raise TypeError, "edge must be a String or Regexp, got #{part.class}"
|
|
139
|
+
end
|
|
140
|
+
end.freeze
|
|
141
|
+
|
|
142
|
+
@entries << [snapshot, token].freeze
|
|
143
|
+
self
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Publish an immutable snapshot of the current entries.
|
|
147
|
+
#
|
|
148
|
+
# Subsequent changes to the builder do not affect the returned trie.
|
|
149
|
+
#
|
|
150
|
+
# @return [Trie]
|
|
151
|
+
def build
|
|
152
|
+
tokens = []
|
|
153
|
+
token_ids = {}.compare_by_identity
|
|
154
|
+
entries = @entries.map do |parts, token|
|
|
155
|
+
unless token_ids.key?(token)
|
|
156
|
+
token_ids[token] = tokens.length
|
|
157
|
+
tokens << token
|
|
158
|
+
end
|
|
159
|
+
[parts.dup.freeze, token_ids.fetch(token)].freeze
|
|
160
|
+
end.freeze
|
|
161
|
+
|
|
162
|
+
Trie.send(:build_entries, entries, tokens.freeze)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
private
|
|
166
|
+
|
|
167
|
+
def snapshot_literal(part)
|
|
168
|
+
literal = String.new(part)
|
|
169
|
+
raise ArgumentError, "edge has an invalid #{literal.encoding} byte sequence" unless literal.valid_encoding?
|
|
170
|
+
|
|
171
|
+
literal.freeze
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def initialize_copy(other)
|
|
175
|
+
super
|
|
176
|
+
@entries = other.instance_variable_get(:@entries).dup
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
class << self
|
|
181
|
+
# Build an immutable trie.
|
|
182
|
+
#
|
|
183
|
+
# @yieldparam builder [Builder]
|
|
184
|
+
# @return [Trie]
|
|
185
|
+
def build
|
|
186
|
+
builder = Builder.new
|
|
187
|
+
yield builder if block_given?
|
|
188
|
+
builder.build
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
private
|
|
192
|
+
|
|
193
|
+
def build_entries(entries, tokens) = new(entries, tokens)
|
|
194
|
+
|
|
195
|
+
private :new
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
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
|
+
module Unshareable
|
|
9
|
+
def pin_to_current_ractor(object) = object
|
|
10
|
+
def prevent_copyable(object) = object
|
|
11
|
+
def prevent_shareable(object) = object
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|