farce 0.0.1.alpha2-x86-linux-gnu

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (423) hide show
  1. checksums.yaml +7 -0
  2. data/CODE_OF_CONDUCT.md +26 -0
  3. data/CONTRIBUTING.md +71 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +1524 -0
  6. data/SECURITY.md +10 -0
  7. data/docs/benchmarks.md +185 -0
  8. data/docs/gems/dry-types.md +290 -0
  9. data/docs/gems/msgpack.md +70 -0
  10. data/docs/gems/ractor-shim.md +63 -0
  11. data/docs/modes.md +628 -0
  12. data/docs/scopes.md +649 -0
  13. data/docs/variants.md +346 -0
  14. data/ext/ext_helper.rb +20 -0
  15. data/ext/farce/README.md +21 -0
  16. data/ext/farce/atom.c +1023 -0
  17. data/ext/farce/bounded_map.c +1683 -0
  18. data/ext/farce/containers.h +77 -0
  19. data/ext/farce/counter.c +399 -0
  20. data/ext/farce/darwin.c +100 -0
  21. data/ext/farce/depend +12 -0
  22. data/ext/farce/dict.c +1523 -0
  23. data/ext/farce/dict.h +152 -0
  24. data/ext/farce/drivers.c +237 -0
  25. data/ext/farce/exchanger.c +299 -0
  26. data/ext/farce/extconf.rb +99 -0
  27. data/ext/farce/farce.c +359 -0
  28. data/ext/farce/flag.c +288 -0
  29. data/ext/farce/io.c +338 -0
  30. data/ext/farce/lock.c +510 -0
  31. data/ext/farce/map.c +2240 -0
  32. data/ext/farce/priority_queue.c +2056 -0
  33. data/ext/farce/queue.c +1059 -0
  34. data/ext/farce/reactor.c +820 -0
  35. data/ext/farce/reactor.h +103 -0
  36. data/ext/farce/shareable.h +31 -0
  37. data/ext/farce/signal.c +350 -0
  38. data/ext/farce/transaction.c +354 -0
  39. data/ext/farce/transaction.h +40 -0
  40. data/ext/farce/tree_map.c +1953 -0
  41. data/ext/farce/trie.c +2020 -0
  42. data/ext/farce/unshareable.c +155 -0
  43. data/ext/farce/unshared_io_pool.h +234 -0
  44. data/ext/farce/unshared_signal.c +263 -0
  45. data/ext/farce/unshared_wait.h +193 -0
  46. data/ext/farce/unsupported.c +6 -0
  47. data/ext/farce/vector.c +1195 -0
  48. data/ext/farce/weak_map.c +1714 -0
  49. data/ext/java/org/farce/BoundedMap.java +394 -0
  50. data/ext/java/org/farce/FiberScheduler.java +141 -0
  51. data/ext/java/org/farce/PriorityKey.java +45 -0
  52. data/ext/java/org/farce/PriorityQueue.java +373 -0
  53. data/ext/java/org/farce/QueueSignal.java +28 -0
  54. data/ext/rebind/README.md +14 -0
  55. data/ext/rebind/extconf.rb +10 -0
  56. data/ext/rebind/rebind.c +186 -0
  57. data/lib/farce/_yard/internal.rb +13 -0
  58. data/lib/farce/_yard/macros.rb +61 -0
  59. data/lib/farce/_yard/ractor.rb +46 -0
  60. data/lib/farce/abstract/atom.rb +186 -0
  61. data/lib/farce/abstract/bounded_map.rb +232 -0
  62. data/lib/farce/abstract/collection.rb +151 -0
  63. data/lib/farce/abstract/concurrent_map.rb +381 -0
  64. data/lib/farce/abstract/counter.rb +193 -0
  65. data/lib/farce/abstract/duplicable_map.rb +229 -0
  66. data/lib/farce/abstract/exchanger.rb +26 -0
  67. data/lib/farce/abstract/flag.rb +71 -0
  68. data/lib/farce/abstract/lazy.rb +115 -0
  69. data/lib/farce/abstract/lease.rb +104 -0
  70. data/lib/farce/abstract/lease_map.rb +261 -0
  71. data/lib/farce/abstract/lease_pool.rb +91 -0
  72. data/lib/farce/abstract/lfu_map.rb +20 -0
  73. data/lib/farce/abstract/lru_map.rb +25 -0
  74. data/lib/farce/abstract/map.rb +345 -0
  75. data/lib/farce/abstract/molecule.rb +245 -0
  76. data/lib/farce/abstract/port.rb +74 -0
  77. data/lib/farce/abstract/priority_queue.rb +117 -0
  78. data/lib/farce/abstract/queue.rb +269 -0
  79. data/lib/farce/abstract/scheduler.rb +111 -0
  80. data/lib/farce/abstract/set.rb +910 -0
  81. data/lib/farce/abstract/sorted_set.rb +172 -0
  82. data/lib/farce/abstract/timer_queue.rb +136 -0
  83. data/lib/farce/abstract/tree_map.rb +269 -0
  84. data/lib/farce/abstract/value.rb +68 -0
  85. data/lib/farce/abstract/vector.rb +1126 -0
  86. data/lib/farce/abstract/weak_atom.rb +32 -0
  87. data/lib/farce/abstract/weak_key_map.rb +12 -0
  88. data/lib/farce/abstract/weak_map.rb +13 -0
  89. data/lib/farce/abstract/weak_set.rb +12 -0
  90. data/lib/farce/abstract/weak_value_map.rb +12 -0
  91. data/lib/farce/abstract.rb +17 -0
  92. data/lib/farce/atom.rb +293 -0
  93. data/lib/farce/class_mirror.rb +87 -0
  94. data/lib/farce/clock.rb +121 -0
  95. data/lib/farce/config.rb +229 -0
  96. data/lib/farce/counter.rb +71 -0
  97. data/lib/farce/deduper.rb +122 -0
  98. data/lib/farce/engine/jruby/bounded_map.rb +314 -0
  99. data/lib/farce/engine/jruby/fiber_scheduler.jar +0 -0
  100. data/lib/farce/engine/jruby/fiber_scheduler.rb +119 -0
  101. data/lib/farce/engine/jruby/lease_waiting.rb +19 -0
  102. data/lib/farce/engine/jruby/map.rb +505 -0
  103. data/lib/farce/engine/jruby/mutable_numeric_copy.rb +42 -0
  104. data/lib/farce/engine/jruby/signal.rb +147 -0
  105. data/lib/farce/engine/jruby.rb +63 -0
  106. data/lib/farce/engine/jvm/concurrent_weak_registry.rb +55 -0
  107. data/lib/farce/engine/jvm/counter.rb +102 -0
  108. data/lib/farce/engine/jvm/extension.rb +32 -0
  109. data/lib/farce/engine/jvm/farce.jar +0 -0
  110. data/lib/farce/engine/jvm/flag.rb +79 -0
  111. data/lib/farce/engine/jvm/priority_queue.rb +217 -0
  112. data/lib/farce/engine/jvm/tree_map.rb +350 -0
  113. data/lib/farce/engine/jvm/types.rb +180 -0
  114. data/lib/farce/engine/jvm.rb +19 -0
  115. data/lib/farce/engine/ruby/3.4/farce.so +0 -0
  116. data/lib/farce/engine/ruby/3.4/fiber_scheduler.rb +20 -0
  117. data/lib/farce/engine/ruby/3.4/port.rb +186 -0
  118. data/lib/farce/engine/ruby/3.4/ractor_methods.rb +26 -0
  119. data/lib/farce/engine/ruby/3.4/ractor_selector.rb +92 -0
  120. data/lib/farce/engine/ruby/3.4/rebind.so +0 -0
  121. data/lib/farce/engine/ruby/3.4/vault.rb +56 -0
  122. data/lib/farce/engine/ruby/4.0/farce.so +0 -0
  123. data/lib/farce/engine/ruby/4.0/port.rb +19 -0
  124. data/lib/farce/engine/ruby/4.0/ractor_methods.rb +20 -0
  125. data/lib/farce/engine/ruby/4.0/ractor_selector.rb +108 -0
  126. data/lib/farce/engine/ruby/4.0/rebind.so +0 -0
  127. data/lib/farce/engine/ruby/4.0/vault.rb +74 -0
  128. data/lib/farce/engine/ruby/4.1/port.rb +21 -0
  129. data/lib/farce/engine/ruby/4.1/ractor_methods.rb +22 -0
  130. data/lib/farce/engine/ruby/4.1/ractor_selector.rb +25 -0
  131. data/lib/farce/engine/ruby/4.1/vault.rb +5 -0
  132. data/lib/farce/engine/ruby/fiber_scheduler.rb +32 -0
  133. data/lib/farce/engine/ruby/key_lock_map.rb +28 -0
  134. data/lib/farce/engine/ruby/shared/lease.rb +26 -0
  135. data/lib/farce/engine/ruby/shared/lease_pool.rb +24 -0
  136. data/lib/farce/engine/ruby/shared/main_scheduler.rb +9 -0
  137. data/lib/farce/engine/ruby/shared/parallel_scheduler.rb +9 -0
  138. data/lib/farce/engine/ruby/shared/proxy_owner.rb +31 -0
  139. data/lib/farce/engine/ruby/shared/ractor_methods.rb +34 -0
  140. data/lib/farce/engine/ruby/shared/ractor_selector.rb +328 -0
  141. data/lib/farce/engine/ruby/shared/strict_map.rb +13 -0
  142. data/lib/farce/engine/ruby/shared/unshared_vector.rb +14 -0
  143. data/lib/farce/engine/ruby/shared/vault.rb +144 -0
  144. data/lib/farce/engine/ruby/shared/vault_weak_map.rb +336 -0
  145. data/lib/farce/engine/ruby/shared/weak_atom.rb +54 -0
  146. data/lib/farce/engine/ruby/shared/weak_map.rb +413 -0
  147. data/lib/farce/engine/ruby.rb +130 -0
  148. data/lib/farce/engine/shared/atom.rb +10 -0
  149. data/lib/farce/engine/shared/exchanger.rb +130 -0
  150. data/lib/farce/engine/shared/identity_key.rb +22 -0
  151. data/lib/farce/engine/shared/lease.rb +10 -0
  152. data/lib/farce/engine/shared/lease_pool.rb +10 -0
  153. data/lib/farce/engine/shared/main_scheduler.rb +20 -0
  154. data/lib/farce/engine/shared/map_key_coordination.rb +226 -0
  155. data/lib/farce/engine/shared/parallel_scheduler.rb +9 -0
  156. data/lib/farce/engine/shared/port.rb +44 -0
  157. data/lib/farce/engine/shared/portable_bounded_map.rb +619 -0
  158. data/lib/farce/engine/shared/proxy_owner.rb +43 -0
  159. data/lib/farce/engine/shared/queue.rb +233 -0
  160. data/lib/farce/engine/shared/ractor_methods.rb +73 -0
  161. data/lib/farce/engine/shared/rebindable.rb +15 -0
  162. data/lib/farce/engine/shared/strict_atom.rb +73 -0
  163. data/lib/farce/engine/shared/strict_map.rb +117 -0
  164. data/lib/farce/engine/shared/strict_queue_values.rb +27 -0
  165. data/lib/farce/engine/shared/strict_tree_map.rb +56 -0
  166. data/lib/farce/engine/shared/transaction_map_backend.rb +20 -0
  167. data/lib/farce/engine/shared/trie.rb +317 -0
  168. data/lib/farce/engine/shared/trie_builder.rb +199 -0
  169. data/lib/farce/engine/shared/unshareable.rb +14 -0
  170. data/lib/farce/engine/shared/unshared_atom.rb +256 -0
  171. data/lib/farce/engine/shared/unshared_priority_queue.rb +9 -0
  172. data/lib/farce/engine/shared/unshared_queue.rb +18 -0
  173. data/lib/farce/engine/shared/unshared_signal.rb +21 -0
  174. data/lib/farce/engine/shared/unshared_vector.rb +377 -0
  175. data/lib/farce/engine/shared/unshared_weak_atom.rb +30 -0
  176. data/lib/farce/engine/shared/unshared_weak_map.rb +445 -0
  177. data/lib/farce/engine/shared/vault.rb +31 -0
  178. data/lib/farce/engine/shared/vector.rb +83 -0
  179. data/lib/farce/engine/shared/weak_atom/base.rb +189 -0
  180. data/lib/farce/engine/shared/weak_atom.rb +20 -0
  181. data/lib/farce/engine/shared/weak_map/cell.rb +99 -0
  182. data/lib/farce/engine/shared/weak_map/index.rb +249 -0
  183. data/lib/farce/engine/shared/weak_map/lock.rb +80 -0
  184. data/lib/farce/engine/shared/weak_map/reference.rb +33 -0
  185. data/lib/farce/engine/shared.rb +63 -0
  186. data/lib/farce/engine/truffleruby/fiber_scheduler.rb +13 -0
  187. data/lib/farce/engine/truffleruby/lock.rb +121 -0
  188. data/lib/farce/engine/truffleruby/map.rb +656 -0
  189. data/lib/farce/engine/truffleruby/native/counter.rb +105 -0
  190. data/lib/farce/engine/truffleruby/native/flag.rb +77 -0
  191. data/lib/farce/engine/truffleruby/native/ordered_array_support.rb +67 -0
  192. data/lib/farce/engine/truffleruby/native/priority_queue.rb +388 -0
  193. data/lib/farce/engine/truffleruby/native/tree_map.rb +51 -0
  194. data/lib/farce/engine/truffleruby/native/unsafe_tree_map.rb +350 -0
  195. data/lib/farce/engine/truffleruby/signal.rb +77 -0
  196. data/lib/farce/engine/truffleruby.rb +148 -0
  197. data/lib/farce/envelope.rb +335 -0
  198. data/lib/farce/error.rb +35 -0
  199. data/lib/farce/exchanger.rb +41 -0
  200. data/lib/farce/flag.rb +27 -0
  201. data/lib/farce/integrations/active_support/blank.rb +68 -0
  202. data/lib/farce/integrations/active_support/clock.rb +17 -0
  203. data/lib/farce/integrations/active_support/duplicable.rb +78 -0
  204. data/lib/farce/integrations/active_support/map.rb +175 -0
  205. data/lib/farce/integrations/active_support/set.rb +60 -0
  206. data/lib/farce/integrations/active_support/value_serialization.rb +17 -0
  207. data/lib/farce/integrations/active_support/vector.rb +231 -0
  208. data/lib/farce/integrations/active_support.rb +9 -0
  209. data/lib/farce/integrations/activesupport.rb +5 -0
  210. data/lib/farce/integrations/bson.rb +108 -0
  211. data/lib/farce/integrations/cbor.rb +51 -0
  212. data/lib/farce/integrations/concurrent.rb +112 -0
  213. data/lib/farce/integrations/dry-types.rb +5 -0
  214. data/lib/farce/integrations/dry_types.rb +694 -0
  215. data/lib/farce/integrations/json.rb +7 -0
  216. data/lib/farce/integrations/msgpack.rb +112 -0
  217. data/lib/farce/integrations/oj.rb +69 -0
  218. data/lib/farce/integrations/psych.rb +191 -0
  219. data/lib/farce/integrations/ractor-sharing.rb +5 -0
  220. data/lib/farce/integrations/ractor-tmvar.rb +5 -0
  221. data/lib/farce/integrations/ractor_sharing.rb +172 -0
  222. data/lib/farce/integrations/ractor_tmvar.rb +64 -0
  223. data/lib/farce/integrations/shared/to_json.rb +42 -0
  224. data/lib/farce/integrations/sorted_set.rb +11 -0
  225. data/lib/farce/integrations/weakref.rb +38 -0
  226. data/lib/farce/integrations/yajl.rb +10 -0
  227. data/lib/farce/integrations.rb +156 -0
  228. data/lib/farce/internal/_frozen_config.rb +11 -0
  229. data/lib/farce/internal/autoloads.rb +47 -0
  230. data/lib/farce/internal/blocking_priority_queue.rb +122 -0
  231. data/lib/farce/internal/converter.rb +106 -0
  232. data/lib/farce/internal/copyable.rb +31 -0
  233. data/lib/farce/internal/delegation.rb +20 -0
  234. data/lib/farce/internal/external_transaction.rb +59 -0
  235. data/lib/farce/internal/fake_ractor.rb +179 -0
  236. data/lib/farce/internal/freeze.rb +118 -0
  237. data/lib/farce/internal/inspect.rb +157 -0
  238. data/lib/farce/internal/key_lock_map.rb +29 -0
  239. data/lib/farce/internal/key_normalizer.rb +289 -0
  240. data/lib/farce/internal/lease_initialization.rb +115 -0
  241. data/lib/farce/internal/lease_map.rb +441 -0
  242. data/lib/farce/internal/lease_pool_state.rb +228 -0
  243. data/lib/farce/internal/lease_state.rb +342 -0
  244. data/lib/farce/internal/lease_waiting.rb +13 -0
  245. data/lib/farce/internal/managed_queue.rb +26 -0
  246. data/lib/farce/internal/map_value_modes.rb +227 -0
  247. data/lib/farce/internal/marshal_support.rb +227 -0
  248. data/lib/farce/internal/mixin.rb +20 -0
  249. data/lib/farce/internal/mutable_ordered_key_lock_map.rb +63 -0
  250. data/lib/farce/internal/noncopyable.rb +17 -0
  251. data/lib/farce/internal/ordered_key_lock_map.rb +69 -0
  252. data/lib/farce/internal/pool_supervisor.rb +41 -0
  253. data/lib/farce/internal/pool_worker.rb +61 -0
  254. data/lib/farce/internal/portable_transaction/reservation_entry.rb +29 -0
  255. data/lib/farce/internal/portable_transaction/strong_map_entry.rb +137 -0
  256. data/lib/farce/internal/portable_transaction/strong_map_size_entry.rb +44 -0
  257. data/lib/farce/internal/portable_transaction/tree_entry.rb +64 -0
  258. data/lib/farce/internal/portable_transaction.rb +164 -0
  259. data/lib/farce/internal/proxy_owner_notifications.rb +29 -0
  260. data/lib/farce/internal/reservation_waiting.rb +24 -0
  261. data/lib/farce/internal/scheduled_task.rb +48 -0
  262. data/lib/farce/internal/scheduler_io.rb +171 -0
  263. data/lib/farce/internal/scheduler_lifecycle.rb +314 -0
  264. data/lib/farce/internal/select_scheduler.rb +235 -0
  265. data/lib/farce/internal/storage.rb +162 -0
  266. data/lib/farce/internal/strict_lease.rb +30 -0
  267. data/lib/farce/internal/strict_lease_map.rb +20 -0
  268. data/lib/farce/internal/strict_lease_pool.rb +29 -0
  269. data/lib/farce/internal/thread_pool.rb +166 -0
  270. data/lib/farce/internal/transaction_conflict.rb +9 -0
  271. data/lib/farce/internal/transaction_freeze_guard.rb +30 -0
  272. data/lib/farce/internal/transaction_map_snapshot.rb +123 -0
  273. data/lib/farce/internal/undefined.rb +22 -0
  274. data/lib/farce/internal/unshared_lease.rb +29 -0
  275. data/lib/farce/internal/unshared_lease_pool.rb +34 -0
  276. data/lib/farce/internal/unshared_queue_waiting.rb +28 -0
  277. data/lib/farce/internal/value_serialization.rb +13 -0
  278. data/lib/farce/internal/weak_map_value_modes.rb +58 -0
  279. data/lib/farce/internal/weak_mode_manager.rb +26 -0
  280. data/lib/farce/internal.rb +129 -0
  281. data/lib/farce/lazy.rb +100 -0
  282. data/lib/farce/lazy_ref.rb +40 -0
  283. data/lib/farce/lease.rb +28 -0
  284. data/lib/farce/lease_map.rb +34 -0
  285. data/lib/farce/lease_pool.rb +29 -0
  286. data/lib/farce/lfu_map.rb +53 -0
  287. data/lib/farce/local/atom.rb +23 -0
  288. data/lib/farce/local/counter.rb +88 -0
  289. data/lib/farce/local/flag.rb +65 -0
  290. data/lib/farce/local/lazy.rb +38 -0
  291. data/lib/farce/local/lazy_ref.rb +36 -0
  292. data/lib/farce/local/lease.rb +77 -0
  293. data/lib/farce/local/lease_map.rb +80 -0
  294. data/lib/farce/local/lease_pool.rb +38 -0
  295. data/lib/farce/local/lfu_map.rb +55 -0
  296. data/lib/farce/local/lru_map.rb +62 -0
  297. data/lib/farce/local/map.rb +47 -0
  298. data/lib/farce/local/molecule.rb +45 -0
  299. data/lib/farce/local/priority_queue.rb +53 -0
  300. data/lib/farce/local/queue.rb +32 -0
  301. data/lib/farce/local/scoped.rb +166 -0
  302. data/lib/farce/local/set.rb +18 -0
  303. data/lib/farce/local/sorted_set.rb +50 -0
  304. data/lib/farce/local/timer_queue.rb +41 -0
  305. data/lib/farce/local/tree_map.rb +47 -0
  306. data/lib/farce/local/vector.rb +30 -0
  307. data/lib/farce/local/weak_atom.rb +23 -0
  308. data/lib/farce/local/weak_key_map.rb +39 -0
  309. data/lib/farce/local/weak_map.rb +39 -0
  310. data/lib/farce/local/weak_set.rb +18 -0
  311. data/lib/farce/local/weak_value_map.rb +39 -0
  312. data/lib/farce/local.rb +35 -0
  313. data/lib/farce/lock.rb +54 -0
  314. data/lib/farce/lru_map.rb +63 -0
  315. data/lib/farce/map.rb +58 -0
  316. data/lib/farce/mode_manager.rb +142 -0
  317. data/lib/farce/molecule.rb +60 -0
  318. data/lib/farce/mutable.rb +171 -0
  319. data/lib/farce/pool.rb +332 -0
  320. data/lib/farce/port.rb +134 -0
  321. data/lib/farce/priority_queue.rb +70 -0
  322. data/lib/farce/proxy/register.rb +101 -0
  323. data/lib/farce/proxy/supervisor.rb +137 -0
  324. data/lib/farce/proxy/wrapper.rb +49 -0
  325. data/lib/farce/proxy.rb +291 -0
  326. data/lib/farce/queue.rb +60 -0
  327. data/lib/farce/ractor.rb +269 -0
  328. data/lib/farce/read_write_lock.rb +256 -0
  329. data/lib/farce/reference.rb +158 -0
  330. data/lib/farce/resolv/dns.rb +42 -0
  331. data/lib/farce/resolv.rb +85 -0
  332. data/lib/farce/scheduler.rb +536 -0
  333. data/lib/farce/set.rb +39 -0
  334. data/lib/farce/shareable.rb +150 -0
  335. data/lib/farce/signal.rb +97 -0
  336. data/lib/farce/sorted_set.rb +36 -0
  337. data/lib/farce/strict/atom.rb +34 -0
  338. data/lib/farce/strict/counter.rb +10 -0
  339. data/lib/farce/strict/exchanger.rb +25 -0
  340. data/lib/farce/strict/flag.rb +10 -0
  341. data/lib/farce/strict/lazy.rb +26 -0
  342. data/lib/farce/strict/lazy_ref.rb +26 -0
  343. data/lib/farce/strict/lease.rb +27 -0
  344. data/lib/farce/strict/lease_map.rb +33 -0
  345. data/lib/farce/strict/lease_pool.rb +28 -0
  346. data/lib/farce/strict/lfu_map.rb +27 -0
  347. data/lib/farce/strict/lru_map.rb +28 -0
  348. data/lib/farce/strict/map.rb +54 -0
  349. data/lib/farce/strict/molecule.rb +16 -0
  350. data/lib/farce/strict/port.rb +40 -0
  351. data/lib/farce/strict/priority_queue.rb +20 -0
  352. data/lib/farce/strict/queue.rb +17 -0
  353. data/lib/farce/strict/set.rb +14 -0
  354. data/lib/farce/strict/sorted_set.rb +19 -0
  355. data/lib/farce/strict/timer_queue.rb +13 -0
  356. data/lib/farce/strict/tree_map.rb +27 -0
  357. data/lib/farce/strict/vector.rb +24 -0
  358. data/lib/farce/strict/weak_atom.rb +31 -0
  359. data/lib/farce/strict/weak_key_map.rb +49 -0
  360. data/lib/farce/strict/weak_map.rb +49 -0
  361. data/lib/farce/strict/weak_set.rb +14 -0
  362. data/lib/farce/strict/weak_value_map.rb +48 -0
  363. data/lib/farce/strict.rb +28 -0
  364. data/lib/farce/system.rb +40 -0
  365. data/lib/farce/thread_scheduler.rb +70 -0
  366. data/lib/farce/timer_queue.rb +66 -0
  367. data/lib/farce/transaction/atom.rb +73 -0
  368. data/lib/farce/transaction/map.rb +25 -0
  369. data/lib/farce/transaction/map_operations.rb +143 -0
  370. data/lib/farce/transaction/molecule.rb +90 -0
  371. data/lib/farce/transaction/mutable.rb +61 -0
  372. data/lib/farce/transaction/set.rb +17 -0
  373. data/lib/farce/transaction/set_operations.rb +48 -0
  374. data/lib/farce/transaction/sorted_set.rb +18 -0
  375. data/lib/farce/transaction/tree_map.rb +78 -0
  376. data/lib/farce/transaction/vector.rb +139 -0
  377. data/lib/farce/transaction/wrapper.rb +202 -0
  378. data/lib/farce/transaction.rb +343 -0
  379. data/lib/farce/tree_map.rb +56 -0
  380. data/lib/farce/unsafe/lfu_map.rb +36 -0
  381. data/lib/farce/unsafe/lru_map.rb +36 -0
  382. data/lib/farce/unsafe/tree_map.rb +21 -0
  383. data/lib/farce/unsafe.rb +29 -0
  384. data/lib/farce/unshareable.rb +67 -0
  385. data/lib/farce/unshared/atom.rb +24 -0
  386. data/lib/farce/unshared/counter.rb +10 -0
  387. data/lib/farce/unshared/flag.rb +10 -0
  388. data/lib/farce/unshared/lazy.rb +38 -0
  389. data/lib/farce/unshared/lazy_ref.rb +26 -0
  390. data/lib/farce/unshared/lease.rb +27 -0
  391. data/lib/farce/unshared/lease_map.rb +26 -0
  392. data/lib/farce/unshared/lease_pool.rb +25 -0
  393. data/lib/farce/unshared/lfu_map.rb +20 -0
  394. data/lib/farce/unshared/lru_map.rb +20 -0
  395. data/lib/farce/unshared/map.rb +49 -0
  396. data/lib/farce/unshared/molecule.rb +16 -0
  397. data/lib/farce/unshared/priority_queue.rb +16 -0
  398. data/lib/farce/unshared/queue.rb +27 -0
  399. data/lib/farce/unshared/set.rb +14 -0
  400. data/lib/farce/unshared/sorted_set.rb +28 -0
  401. data/lib/farce/unshared/timer_queue.rb +16 -0
  402. data/lib/farce/unshared/tree_map.rb +21 -0
  403. data/lib/farce/unshared/vector.rb +19 -0
  404. data/lib/farce/unshared/weak_atom.rb +31 -0
  405. data/lib/farce/unshared/weak_key_map.rb +44 -0
  406. data/lib/farce/unshared/weak_map.rb +44 -0
  407. data/lib/farce/unshared/weak_set.rb +14 -0
  408. data/lib/farce/unshared/weak_value_map.rb +43 -0
  409. data/lib/farce/unshared.rb +28 -0
  410. data/lib/farce/vector.rb +228 -0
  411. data/lib/farce/version.rb +8 -0
  412. data/lib/farce/walker/definitions.rb +186 -0
  413. data/lib/farce/walker/modification.rb +355 -0
  414. data/lib/farce/walker.rb +319 -0
  415. data/lib/farce/weak_atom.rb +121 -0
  416. data/lib/farce/weak_key_map.rb +31 -0
  417. data/lib/farce/weak_map.rb +33 -0
  418. data/lib/farce/weak_ref.rb +67 -0
  419. data/lib/farce/weak_set.rb +82 -0
  420. data/lib/farce/weak_value.rb +195 -0
  421. data/lib/farce/weak_value_map.rb +32 -0
  422. data/lib/farce.rb +519 -0
  423. 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