farce 0.0.1.alpha2-java

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 (376) 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/lib/farce/_yard/internal.rb +13 -0
  15. data/lib/farce/_yard/macros.rb +61 -0
  16. data/lib/farce/_yard/ractor.rb +46 -0
  17. data/lib/farce/abstract/atom.rb +186 -0
  18. data/lib/farce/abstract/bounded_map.rb +232 -0
  19. data/lib/farce/abstract/collection.rb +151 -0
  20. data/lib/farce/abstract/concurrent_map.rb +381 -0
  21. data/lib/farce/abstract/counter.rb +193 -0
  22. data/lib/farce/abstract/duplicable_map.rb +229 -0
  23. data/lib/farce/abstract/exchanger.rb +26 -0
  24. data/lib/farce/abstract/flag.rb +71 -0
  25. data/lib/farce/abstract/lazy.rb +115 -0
  26. data/lib/farce/abstract/lease.rb +104 -0
  27. data/lib/farce/abstract/lease_map.rb +261 -0
  28. data/lib/farce/abstract/lease_pool.rb +91 -0
  29. data/lib/farce/abstract/lfu_map.rb +20 -0
  30. data/lib/farce/abstract/lru_map.rb +25 -0
  31. data/lib/farce/abstract/map.rb +345 -0
  32. data/lib/farce/abstract/molecule.rb +245 -0
  33. data/lib/farce/abstract/port.rb +74 -0
  34. data/lib/farce/abstract/priority_queue.rb +117 -0
  35. data/lib/farce/abstract/queue.rb +269 -0
  36. data/lib/farce/abstract/scheduler.rb +111 -0
  37. data/lib/farce/abstract/set.rb +910 -0
  38. data/lib/farce/abstract/sorted_set.rb +172 -0
  39. data/lib/farce/abstract/timer_queue.rb +136 -0
  40. data/lib/farce/abstract/tree_map.rb +269 -0
  41. data/lib/farce/abstract/value.rb +68 -0
  42. data/lib/farce/abstract/vector.rb +1126 -0
  43. data/lib/farce/abstract/weak_atom.rb +32 -0
  44. data/lib/farce/abstract/weak_key_map.rb +12 -0
  45. data/lib/farce/abstract/weak_map.rb +13 -0
  46. data/lib/farce/abstract/weak_set.rb +12 -0
  47. data/lib/farce/abstract/weak_value_map.rb +12 -0
  48. data/lib/farce/abstract.rb +17 -0
  49. data/lib/farce/atom.rb +293 -0
  50. data/lib/farce/class_mirror.rb +87 -0
  51. data/lib/farce/clock.rb +121 -0
  52. data/lib/farce/config.rb +229 -0
  53. data/lib/farce/counter.rb +71 -0
  54. data/lib/farce/deduper.rb +122 -0
  55. data/lib/farce/engine/jruby/bounded_map.rb +314 -0
  56. data/lib/farce/engine/jruby/fiber_scheduler.jar +0 -0
  57. data/lib/farce/engine/jruby/fiber_scheduler.rb +119 -0
  58. data/lib/farce/engine/jruby/lease_waiting.rb +19 -0
  59. data/lib/farce/engine/jruby/map.rb +505 -0
  60. data/lib/farce/engine/jruby/mutable_numeric_copy.rb +42 -0
  61. data/lib/farce/engine/jruby/signal.rb +147 -0
  62. data/lib/farce/engine/jruby.rb +63 -0
  63. data/lib/farce/engine/jvm/concurrent_weak_registry.rb +55 -0
  64. data/lib/farce/engine/jvm/counter.rb +102 -0
  65. data/lib/farce/engine/jvm/extension.rb +32 -0
  66. data/lib/farce/engine/jvm/farce.jar +0 -0
  67. data/lib/farce/engine/jvm/flag.rb +79 -0
  68. data/lib/farce/engine/jvm/priority_queue.rb +217 -0
  69. data/lib/farce/engine/jvm/tree_map.rb +350 -0
  70. data/lib/farce/engine/jvm/types.rb +180 -0
  71. data/lib/farce/engine/jvm.rb +19 -0
  72. data/lib/farce/engine/ruby/3.4/fiber_scheduler.rb +20 -0
  73. data/lib/farce/engine/ruby/3.4/port.rb +186 -0
  74. data/lib/farce/engine/ruby/3.4/ractor_methods.rb +26 -0
  75. data/lib/farce/engine/ruby/3.4/ractor_selector.rb +92 -0
  76. data/lib/farce/engine/ruby/3.4/vault.rb +56 -0
  77. data/lib/farce/engine/ruby/4.0/port.rb +19 -0
  78. data/lib/farce/engine/ruby/4.0/ractor_methods.rb +20 -0
  79. data/lib/farce/engine/ruby/4.0/ractor_selector.rb +108 -0
  80. data/lib/farce/engine/ruby/4.0/vault.rb +74 -0
  81. data/lib/farce/engine/ruby/4.1/port.rb +21 -0
  82. data/lib/farce/engine/ruby/4.1/ractor_methods.rb +22 -0
  83. data/lib/farce/engine/ruby/4.1/ractor_selector.rb +25 -0
  84. data/lib/farce/engine/ruby/4.1/vault.rb +5 -0
  85. data/lib/farce/engine/ruby/fiber_scheduler.rb +32 -0
  86. data/lib/farce/engine/ruby/key_lock_map.rb +28 -0
  87. data/lib/farce/engine/ruby/shared/lease.rb +26 -0
  88. data/lib/farce/engine/ruby/shared/lease_pool.rb +24 -0
  89. data/lib/farce/engine/ruby/shared/main_scheduler.rb +9 -0
  90. data/lib/farce/engine/ruby/shared/parallel_scheduler.rb +9 -0
  91. data/lib/farce/engine/ruby/shared/proxy_owner.rb +31 -0
  92. data/lib/farce/engine/ruby/shared/ractor_methods.rb +34 -0
  93. data/lib/farce/engine/ruby/shared/ractor_selector.rb +328 -0
  94. data/lib/farce/engine/ruby/shared/strict_map.rb +13 -0
  95. data/lib/farce/engine/ruby/shared/unshared_vector.rb +14 -0
  96. data/lib/farce/engine/ruby/shared/vault.rb +144 -0
  97. data/lib/farce/engine/ruby/shared/vault_weak_map.rb +336 -0
  98. data/lib/farce/engine/ruby/shared/weak_atom.rb +54 -0
  99. data/lib/farce/engine/ruby/shared/weak_map.rb +413 -0
  100. data/lib/farce/engine/ruby.rb +130 -0
  101. data/lib/farce/engine/shared/atom.rb +10 -0
  102. data/lib/farce/engine/shared/exchanger.rb +130 -0
  103. data/lib/farce/engine/shared/identity_key.rb +22 -0
  104. data/lib/farce/engine/shared/lease.rb +10 -0
  105. data/lib/farce/engine/shared/lease_pool.rb +10 -0
  106. data/lib/farce/engine/shared/main_scheduler.rb +20 -0
  107. data/lib/farce/engine/shared/map_key_coordination.rb +226 -0
  108. data/lib/farce/engine/shared/parallel_scheduler.rb +9 -0
  109. data/lib/farce/engine/shared/port.rb +44 -0
  110. data/lib/farce/engine/shared/portable_bounded_map.rb +619 -0
  111. data/lib/farce/engine/shared/proxy_owner.rb +43 -0
  112. data/lib/farce/engine/shared/queue.rb +233 -0
  113. data/lib/farce/engine/shared/ractor_methods.rb +73 -0
  114. data/lib/farce/engine/shared/rebindable.rb +15 -0
  115. data/lib/farce/engine/shared/strict_atom.rb +73 -0
  116. data/lib/farce/engine/shared/strict_map.rb +117 -0
  117. data/lib/farce/engine/shared/strict_queue_values.rb +27 -0
  118. data/lib/farce/engine/shared/strict_tree_map.rb +56 -0
  119. data/lib/farce/engine/shared/transaction_map_backend.rb +20 -0
  120. data/lib/farce/engine/shared/trie.rb +317 -0
  121. data/lib/farce/engine/shared/trie_builder.rb +199 -0
  122. data/lib/farce/engine/shared/unshareable.rb +14 -0
  123. data/lib/farce/engine/shared/unshared_atom.rb +256 -0
  124. data/lib/farce/engine/shared/unshared_priority_queue.rb +9 -0
  125. data/lib/farce/engine/shared/unshared_queue.rb +18 -0
  126. data/lib/farce/engine/shared/unshared_signal.rb +21 -0
  127. data/lib/farce/engine/shared/unshared_vector.rb +377 -0
  128. data/lib/farce/engine/shared/unshared_weak_atom.rb +30 -0
  129. data/lib/farce/engine/shared/unshared_weak_map.rb +445 -0
  130. data/lib/farce/engine/shared/vault.rb +31 -0
  131. data/lib/farce/engine/shared/vector.rb +83 -0
  132. data/lib/farce/engine/shared/weak_atom/base.rb +189 -0
  133. data/lib/farce/engine/shared/weak_atom.rb +20 -0
  134. data/lib/farce/engine/shared/weak_map/cell.rb +99 -0
  135. data/lib/farce/engine/shared/weak_map/index.rb +249 -0
  136. data/lib/farce/engine/shared/weak_map/lock.rb +80 -0
  137. data/lib/farce/engine/shared/weak_map/reference.rb +33 -0
  138. data/lib/farce/engine/shared.rb +63 -0
  139. data/lib/farce/engine/truffleruby/fiber_scheduler.rb +13 -0
  140. data/lib/farce/engine/truffleruby/lock.rb +121 -0
  141. data/lib/farce/engine/truffleruby/map.rb +656 -0
  142. data/lib/farce/engine/truffleruby/native/counter.rb +105 -0
  143. data/lib/farce/engine/truffleruby/native/flag.rb +77 -0
  144. data/lib/farce/engine/truffleruby/native/ordered_array_support.rb +67 -0
  145. data/lib/farce/engine/truffleruby/native/priority_queue.rb +388 -0
  146. data/lib/farce/engine/truffleruby/native/tree_map.rb +51 -0
  147. data/lib/farce/engine/truffleruby/native/unsafe_tree_map.rb +350 -0
  148. data/lib/farce/engine/truffleruby/signal.rb +77 -0
  149. data/lib/farce/engine/truffleruby.rb +148 -0
  150. data/lib/farce/envelope.rb +335 -0
  151. data/lib/farce/error.rb +35 -0
  152. data/lib/farce/exchanger.rb +41 -0
  153. data/lib/farce/flag.rb +27 -0
  154. data/lib/farce/integrations/active_support/blank.rb +68 -0
  155. data/lib/farce/integrations/active_support/clock.rb +17 -0
  156. data/lib/farce/integrations/active_support/duplicable.rb +78 -0
  157. data/lib/farce/integrations/active_support/map.rb +175 -0
  158. data/lib/farce/integrations/active_support/set.rb +60 -0
  159. data/lib/farce/integrations/active_support/value_serialization.rb +17 -0
  160. data/lib/farce/integrations/active_support/vector.rb +231 -0
  161. data/lib/farce/integrations/active_support.rb +9 -0
  162. data/lib/farce/integrations/activesupport.rb +5 -0
  163. data/lib/farce/integrations/bson.rb +108 -0
  164. data/lib/farce/integrations/cbor.rb +51 -0
  165. data/lib/farce/integrations/concurrent.rb +112 -0
  166. data/lib/farce/integrations/dry-types.rb +5 -0
  167. data/lib/farce/integrations/dry_types.rb +694 -0
  168. data/lib/farce/integrations/json.rb +7 -0
  169. data/lib/farce/integrations/msgpack.rb +112 -0
  170. data/lib/farce/integrations/oj.rb +69 -0
  171. data/lib/farce/integrations/psych.rb +191 -0
  172. data/lib/farce/integrations/ractor-sharing.rb +5 -0
  173. data/lib/farce/integrations/ractor-tmvar.rb +5 -0
  174. data/lib/farce/integrations/ractor_sharing.rb +172 -0
  175. data/lib/farce/integrations/ractor_tmvar.rb +64 -0
  176. data/lib/farce/integrations/shared/to_json.rb +42 -0
  177. data/lib/farce/integrations/sorted_set.rb +11 -0
  178. data/lib/farce/integrations/weakref.rb +38 -0
  179. data/lib/farce/integrations/yajl.rb +10 -0
  180. data/lib/farce/integrations.rb +156 -0
  181. data/lib/farce/internal/_frozen_config.rb +11 -0
  182. data/lib/farce/internal/autoloads.rb +47 -0
  183. data/lib/farce/internal/blocking_priority_queue.rb +122 -0
  184. data/lib/farce/internal/converter.rb +106 -0
  185. data/lib/farce/internal/copyable.rb +31 -0
  186. data/lib/farce/internal/delegation.rb +20 -0
  187. data/lib/farce/internal/external_transaction.rb +59 -0
  188. data/lib/farce/internal/fake_ractor.rb +179 -0
  189. data/lib/farce/internal/freeze.rb +118 -0
  190. data/lib/farce/internal/inspect.rb +157 -0
  191. data/lib/farce/internal/key_lock_map.rb +29 -0
  192. data/lib/farce/internal/key_normalizer.rb +289 -0
  193. data/lib/farce/internal/lease_initialization.rb +115 -0
  194. data/lib/farce/internal/lease_map.rb +441 -0
  195. data/lib/farce/internal/lease_pool_state.rb +228 -0
  196. data/lib/farce/internal/lease_state.rb +342 -0
  197. data/lib/farce/internal/lease_waiting.rb +13 -0
  198. data/lib/farce/internal/managed_queue.rb +26 -0
  199. data/lib/farce/internal/map_value_modes.rb +227 -0
  200. data/lib/farce/internal/marshal_support.rb +227 -0
  201. data/lib/farce/internal/mixin.rb +20 -0
  202. data/lib/farce/internal/mutable_ordered_key_lock_map.rb +63 -0
  203. data/lib/farce/internal/noncopyable.rb +17 -0
  204. data/lib/farce/internal/ordered_key_lock_map.rb +69 -0
  205. data/lib/farce/internal/pool_supervisor.rb +41 -0
  206. data/lib/farce/internal/pool_worker.rb +61 -0
  207. data/lib/farce/internal/portable_transaction/reservation_entry.rb +29 -0
  208. data/lib/farce/internal/portable_transaction/strong_map_entry.rb +137 -0
  209. data/lib/farce/internal/portable_transaction/strong_map_size_entry.rb +44 -0
  210. data/lib/farce/internal/portable_transaction/tree_entry.rb +64 -0
  211. data/lib/farce/internal/portable_transaction.rb +164 -0
  212. data/lib/farce/internal/proxy_owner_notifications.rb +29 -0
  213. data/lib/farce/internal/reservation_waiting.rb +24 -0
  214. data/lib/farce/internal/scheduled_task.rb +48 -0
  215. data/lib/farce/internal/scheduler_io.rb +171 -0
  216. data/lib/farce/internal/scheduler_lifecycle.rb +314 -0
  217. data/lib/farce/internal/select_scheduler.rb +235 -0
  218. data/lib/farce/internal/storage.rb +162 -0
  219. data/lib/farce/internal/strict_lease.rb +30 -0
  220. data/lib/farce/internal/strict_lease_map.rb +20 -0
  221. data/lib/farce/internal/strict_lease_pool.rb +29 -0
  222. data/lib/farce/internal/thread_pool.rb +166 -0
  223. data/lib/farce/internal/transaction_conflict.rb +9 -0
  224. data/lib/farce/internal/transaction_freeze_guard.rb +30 -0
  225. data/lib/farce/internal/transaction_map_snapshot.rb +123 -0
  226. data/lib/farce/internal/undefined.rb +22 -0
  227. data/lib/farce/internal/unshared_lease.rb +29 -0
  228. data/lib/farce/internal/unshared_lease_pool.rb +34 -0
  229. data/lib/farce/internal/unshared_queue_waiting.rb +28 -0
  230. data/lib/farce/internal/value_serialization.rb +13 -0
  231. data/lib/farce/internal/weak_map_value_modes.rb +58 -0
  232. data/lib/farce/internal/weak_mode_manager.rb +26 -0
  233. data/lib/farce/internal.rb +129 -0
  234. data/lib/farce/lazy.rb +100 -0
  235. data/lib/farce/lazy_ref.rb +40 -0
  236. data/lib/farce/lease.rb +28 -0
  237. data/lib/farce/lease_map.rb +34 -0
  238. data/lib/farce/lease_pool.rb +29 -0
  239. data/lib/farce/lfu_map.rb +53 -0
  240. data/lib/farce/local/atom.rb +23 -0
  241. data/lib/farce/local/counter.rb +88 -0
  242. data/lib/farce/local/flag.rb +65 -0
  243. data/lib/farce/local/lazy.rb +38 -0
  244. data/lib/farce/local/lazy_ref.rb +36 -0
  245. data/lib/farce/local/lease.rb +77 -0
  246. data/lib/farce/local/lease_map.rb +80 -0
  247. data/lib/farce/local/lease_pool.rb +38 -0
  248. data/lib/farce/local/lfu_map.rb +55 -0
  249. data/lib/farce/local/lru_map.rb +62 -0
  250. data/lib/farce/local/map.rb +47 -0
  251. data/lib/farce/local/molecule.rb +45 -0
  252. data/lib/farce/local/priority_queue.rb +53 -0
  253. data/lib/farce/local/queue.rb +32 -0
  254. data/lib/farce/local/scoped.rb +166 -0
  255. data/lib/farce/local/set.rb +18 -0
  256. data/lib/farce/local/sorted_set.rb +50 -0
  257. data/lib/farce/local/timer_queue.rb +41 -0
  258. data/lib/farce/local/tree_map.rb +47 -0
  259. data/lib/farce/local/vector.rb +30 -0
  260. data/lib/farce/local/weak_atom.rb +23 -0
  261. data/lib/farce/local/weak_key_map.rb +39 -0
  262. data/lib/farce/local/weak_map.rb +39 -0
  263. data/lib/farce/local/weak_set.rb +18 -0
  264. data/lib/farce/local/weak_value_map.rb +39 -0
  265. data/lib/farce/local.rb +35 -0
  266. data/lib/farce/lock.rb +54 -0
  267. data/lib/farce/lru_map.rb +63 -0
  268. data/lib/farce/map.rb +58 -0
  269. data/lib/farce/mode_manager.rb +142 -0
  270. data/lib/farce/molecule.rb +60 -0
  271. data/lib/farce/mutable.rb +171 -0
  272. data/lib/farce/pool.rb +332 -0
  273. data/lib/farce/port.rb +134 -0
  274. data/lib/farce/priority_queue.rb +70 -0
  275. data/lib/farce/proxy/register.rb +101 -0
  276. data/lib/farce/proxy/supervisor.rb +137 -0
  277. data/lib/farce/proxy/wrapper.rb +49 -0
  278. data/lib/farce/proxy.rb +291 -0
  279. data/lib/farce/queue.rb +60 -0
  280. data/lib/farce/ractor.rb +269 -0
  281. data/lib/farce/read_write_lock.rb +256 -0
  282. data/lib/farce/reference.rb +158 -0
  283. data/lib/farce/resolv/dns.rb +42 -0
  284. data/lib/farce/resolv.rb +85 -0
  285. data/lib/farce/scheduler.rb +536 -0
  286. data/lib/farce/set.rb +39 -0
  287. data/lib/farce/shareable.rb +150 -0
  288. data/lib/farce/signal.rb +97 -0
  289. data/lib/farce/sorted_set.rb +36 -0
  290. data/lib/farce/strict/atom.rb +34 -0
  291. data/lib/farce/strict/counter.rb +10 -0
  292. data/lib/farce/strict/exchanger.rb +25 -0
  293. data/lib/farce/strict/flag.rb +10 -0
  294. data/lib/farce/strict/lazy.rb +26 -0
  295. data/lib/farce/strict/lazy_ref.rb +26 -0
  296. data/lib/farce/strict/lease.rb +27 -0
  297. data/lib/farce/strict/lease_map.rb +33 -0
  298. data/lib/farce/strict/lease_pool.rb +28 -0
  299. data/lib/farce/strict/lfu_map.rb +27 -0
  300. data/lib/farce/strict/lru_map.rb +28 -0
  301. data/lib/farce/strict/map.rb +54 -0
  302. data/lib/farce/strict/molecule.rb +16 -0
  303. data/lib/farce/strict/port.rb +40 -0
  304. data/lib/farce/strict/priority_queue.rb +20 -0
  305. data/lib/farce/strict/queue.rb +17 -0
  306. data/lib/farce/strict/set.rb +14 -0
  307. data/lib/farce/strict/sorted_set.rb +19 -0
  308. data/lib/farce/strict/timer_queue.rb +13 -0
  309. data/lib/farce/strict/tree_map.rb +27 -0
  310. data/lib/farce/strict/vector.rb +24 -0
  311. data/lib/farce/strict/weak_atom.rb +31 -0
  312. data/lib/farce/strict/weak_key_map.rb +49 -0
  313. data/lib/farce/strict/weak_map.rb +49 -0
  314. data/lib/farce/strict/weak_set.rb +14 -0
  315. data/lib/farce/strict/weak_value_map.rb +48 -0
  316. data/lib/farce/strict.rb +28 -0
  317. data/lib/farce/system.rb +40 -0
  318. data/lib/farce/thread_scheduler.rb +70 -0
  319. data/lib/farce/timer_queue.rb +66 -0
  320. data/lib/farce/transaction/atom.rb +73 -0
  321. data/lib/farce/transaction/map.rb +25 -0
  322. data/lib/farce/transaction/map_operations.rb +143 -0
  323. data/lib/farce/transaction/molecule.rb +90 -0
  324. data/lib/farce/transaction/mutable.rb +61 -0
  325. data/lib/farce/transaction/set.rb +17 -0
  326. data/lib/farce/transaction/set_operations.rb +48 -0
  327. data/lib/farce/transaction/sorted_set.rb +18 -0
  328. data/lib/farce/transaction/tree_map.rb +78 -0
  329. data/lib/farce/transaction/vector.rb +139 -0
  330. data/lib/farce/transaction/wrapper.rb +202 -0
  331. data/lib/farce/transaction.rb +343 -0
  332. data/lib/farce/tree_map.rb +56 -0
  333. data/lib/farce/unsafe/lfu_map.rb +36 -0
  334. data/lib/farce/unsafe/lru_map.rb +36 -0
  335. data/lib/farce/unsafe/tree_map.rb +21 -0
  336. data/lib/farce/unsafe.rb +29 -0
  337. data/lib/farce/unshareable.rb +67 -0
  338. data/lib/farce/unshared/atom.rb +24 -0
  339. data/lib/farce/unshared/counter.rb +10 -0
  340. data/lib/farce/unshared/flag.rb +10 -0
  341. data/lib/farce/unshared/lazy.rb +38 -0
  342. data/lib/farce/unshared/lazy_ref.rb +26 -0
  343. data/lib/farce/unshared/lease.rb +27 -0
  344. data/lib/farce/unshared/lease_map.rb +26 -0
  345. data/lib/farce/unshared/lease_pool.rb +25 -0
  346. data/lib/farce/unshared/lfu_map.rb +20 -0
  347. data/lib/farce/unshared/lru_map.rb +20 -0
  348. data/lib/farce/unshared/map.rb +49 -0
  349. data/lib/farce/unshared/molecule.rb +16 -0
  350. data/lib/farce/unshared/priority_queue.rb +16 -0
  351. data/lib/farce/unshared/queue.rb +27 -0
  352. data/lib/farce/unshared/set.rb +14 -0
  353. data/lib/farce/unshared/sorted_set.rb +28 -0
  354. data/lib/farce/unshared/timer_queue.rb +16 -0
  355. data/lib/farce/unshared/tree_map.rb +21 -0
  356. data/lib/farce/unshared/vector.rb +19 -0
  357. data/lib/farce/unshared/weak_atom.rb +31 -0
  358. data/lib/farce/unshared/weak_key_map.rb +44 -0
  359. data/lib/farce/unshared/weak_map.rb +44 -0
  360. data/lib/farce/unshared/weak_set.rb +14 -0
  361. data/lib/farce/unshared/weak_value_map.rb +43 -0
  362. data/lib/farce/unshared.rb +28 -0
  363. data/lib/farce/vector.rb +228 -0
  364. data/lib/farce/version.rb +8 -0
  365. data/lib/farce/walker/definitions.rb +186 -0
  366. data/lib/farce/walker/modification.rb +355 -0
  367. data/lib/farce/walker.rb +319 -0
  368. data/lib/farce/weak_atom.rb +121 -0
  369. data/lib/farce/weak_key_map.rb +31 -0
  370. data/lib/farce/weak_map.rb +33 -0
  371. data/lib/farce/weak_ref.rb +67 -0
  372. data/lib/farce/weak_set.rb +82 -0
  373. data/lib/farce/weak_value.rb +195 -0
  374. data/lib/farce/weak_value_map.rb +32 -0
  375. data/lib/farce.rb +519 -0
  376. metadata +420 -0
@@ -0,0 +1,350 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ require "farce/engine/jvm/types"
6
+
7
+ module Farce
8
+ # @!visibility private
9
+ module Internal # :nodoc: all
10
+ module JVMTreeMapBackend
11
+ Key = Struct.new(:key, :mutation_owner)
12
+ Value = Data.define(:value)
13
+ KEY_COMPARATOR = JVMContainers.comparator do |left, right|
14
+ next 0 if left.equal?(right)
15
+
16
+ comparison = JVMContainers.compare(left.key, right.key)
17
+ owner = left.mutation_owner || right.mutation_owner
18
+ raise FrozenError, "can't modify frozen #{owner.class}" if owner&.__send__(:mutation_frozen?)
19
+ comparison
20
+ end
21
+
22
+ INITIALIZATION_LOCK = Mutex.new
23
+ State = Struct.new(:tree, :revision)
24
+ private_constant :Key, :Value, :KEY_COMPARATOR, :INITIALIZATION_LOCK, :State
25
+
26
+ def initialize(entries = nil)
27
+ check_uninitialized
28
+
29
+ parsed_entries = coerce_entries(entries)
30
+ check_uninitialized
31
+ guard = JVMOperationGuard.new(synchronized: synchronized?, label: "tree map")
32
+ state = build_state(parsed_entries)
33
+
34
+ if synchronized?
35
+ guard.synchronize { publish_initialization(guard, state) }
36
+ else
37
+ publish_initialization(guard, state)
38
+ end
39
+ end
40
+
41
+ # Adapt the existing Java lock only for transaction participants.
42
+ TransactionLock = Struct.new(:lock) do
43
+ def try_lock = lock.tryLock
44
+ def unlock = lock.unlock
45
+ end
46
+ private_constant :TransactionLock
47
+
48
+ def transaction_snapshot
49
+ raise TypeError, "unsafe tree maps do not support transactions" unless synchronized?
50
+ tree, revision = access { [JVMContainers::TreeMap.new(@state.tree), @state.revision] }
51
+ working = self.class.new
52
+ working.instance_variable_get(:@state).tree = tree
53
+ lock = TransactionLock.new(@guard.instance_variable_get(:@lock))
54
+ PortableTransaction::TreeEntry.new(self, working, revision, lock, :tree)
55
+ end
56
+
57
+ def prepare_key(key) = canonical_key(key)
58
+
59
+ def freeze
60
+ state = @freeze_state
61
+ return super unless synchronized? && state
62
+
63
+ state.set
64
+ self
65
+ end
66
+
67
+ def frozen?
68
+ state = @freeze_state
69
+ synchronized? && state ? state.value : super
70
+ end
71
+
72
+ def [](key)
73
+ key = canonical_key(key)
74
+ access do
75
+ wrapped = JVMContainers.nullable(@state.tree.get(Key.new(key)))
76
+ wrapped&.value
77
+ end
78
+ end
79
+
80
+ def fetch(*arguments)
81
+ unless arguments.length.between?(1, 2)
82
+ raise ArgumentError, "wrong number of arguments (given #{arguments.length}, expected 1..2)"
83
+ end
84
+
85
+ original_key, default = arguments
86
+ key = canonical_key(original_key)
87
+ default_given = arguments.length == 2
88
+ warn "block supersedes default value argument", uplevel: 1 if block_given? && default_given
89
+ wrapped = access { JVMContainers.nullable(@state.tree.get(Key.new(key))) }
90
+ return wrapped.value if wrapped
91
+ return yield(original_key) if block_given?
92
+ return default if default_given
93
+
94
+ raise KeyError.new(
95
+ "key not found: #{original_key.inspect}",
96
+ receiver: self,
97
+ key: original_key,
98
+ )
99
+ end
100
+
101
+ def key?(key)
102
+ key = canonical_key(key)
103
+ access { !JVMContainers.nullable(@state.tree.get(Key.new(key))).nil? }
104
+ end
105
+
106
+ def getkey(key)
107
+ key = canonical_key(key)
108
+ access do
109
+ probe = Key.new(key)
110
+ entry = JVMContainers.nullable(@state.tree.ceilingEntry(probe))
111
+ next unless entry && KEY_COMPARATOR.compare(probe, entry.getKey).zero?
112
+
113
+ entry.getKey.key
114
+ end
115
+ end
116
+
117
+ def each
118
+ return enum_for(__method__) { size } unless block_given?
119
+
120
+ entries = access do
121
+ snapshot = []
122
+ iterator = @state.tree.entrySet.iterator
123
+ while iterator.hasNext
124
+ entry = iterator.next
125
+ snapshot << [entry.getKey.key, entry.getValue.value]
126
+ end
127
+ snapshot
128
+ end
129
+ entries.each { yield it }
130
+ self
131
+ end
132
+
133
+ def each_live
134
+ return enum_for(__method__) { size } unless block_given?
135
+
136
+ iterator = nil
137
+ last_key = nil
138
+ revision = nil
139
+ started = false
140
+ loop do
141
+ pair = access do
142
+ current = @state.revision
143
+ if !started || revision != current
144
+ entries = started ? @state.tree.tailMap(Key.new(last_key), false).entrySet : @state.tree.entrySet
145
+ iterator = entries.iterator
146
+ end
147
+ next unless iterator.hasNext
148
+
149
+ entry = iterator.next
150
+ last_key = entry.getKey.key
151
+ revision = current
152
+ [last_key, entry.getValue.value]
153
+ end
154
+ break unless pair
155
+ started = true
156
+ yield pair
157
+ end
158
+ self
159
+ end
160
+
161
+ def []=(key, value)
162
+ key = canonical_key(key)
163
+ access do
164
+ check_local_frozen
165
+ wrapped_key = mutation_key(key)
166
+ begin
167
+ @state.tree.put(wrapped_key, Value.new(value))
168
+ @state.revision += 1
169
+ ensure
170
+ Thread.handle_interrupt(INTERRUPT_MASK) do
171
+ wrapped_key.mutation_owner = nil
172
+ end
173
+ end
174
+ value
175
+ end
176
+ end
177
+
178
+ def delete(key)
179
+ key = canonical_key(key)
180
+ access do
181
+ check_local_frozen
182
+ wrapped = JVMContainers.nullable(@state.tree.remove(mutation_key(key)))
183
+ @state.revision += 1 if wrapped
184
+ wrapped&.value
185
+ end
186
+ end
187
+
188
+ def first_key
189
+ access do
190
+ entry = JVMContainers.nullable(@state.tree.firstEntry)
191
+ entry&.getKey&.key
192
+ end
193
+ end
194
+
195
+ def last_key
196
+ access do
197
+ entry = JVMContainers.nullable(@state.tree.lastEntry)
198
+ entry&.getKey&.key
199
+ end
200
+ end
201
+
202
+ def shift
203
+ access do
204
+ check_local_frozen
205
+ iterator = @state.tree.entrySet.iterator
206
+ next nil unless iterator.hasNext
207
+
208
+ entry = iterator.next
209
+ result = [entry.getKey.key, entry.getValue.value]
210
+ iterator.remove
211
+ @state.revision += 1
212
+ result
213
+ end
214
+ end
215
+
216
+ def pop
217
+ access do
218
+ check_local_frozen
219
+ iterator = @state.tree.descendingMap.entrySet.iterator
220
+ next nil unless iterator.hasNext
221
+
222
+ entry = iterator.next
223
+ result = [entry.getKey.key, entry.getValue.value]
224
+ iterator.remove
225
+ @state.revision += 1
226
+ result
227
+ end
228
+ end
229
+
230
+ def size = access { @state.tree.size }
231
+
232
+ alias length size
233
+
234
+ def empty? = access { @state.tree.isEmpty }
235
+
236
+ def clear
237
+ access do
238
+ check_local_frozen
239
+ unless @state.tree.isEmpty
240
+ @state.tree.clear
241
+ @state.revision += 1
242
+ end
243
+ end
244
+ self
245
+ end
246
+
247
+ def initialize_copy(_other)
248
+ raise TypeError, "tree maps cannot be copied"
249
+ end
250
+
251
+ private
252
+
253
+ def publish_initialization(guard, state)
254
+ INITIALIZATION_LOCK.synchronize do
255
+ Thread.handle_interrupt(INTERRUPT_MASK) do
256
+ raise "tree map is already initialized" if defined?(@state)
257
+ raise FrozenError, "can't modify frozen #{self.class}" if
258
+ JVMContainers.frozen_object?(self)
259
+
260
+ @state = state
261
+ @guard = guard
262
+ @freeze_state = Flag.new(false) if synchronized?
263
+ JVMContainers.freeze_object(self) if synchronized?
264
+ end
265
+ end
266
+ end
267
+
268
+ def access(&)
269
+ raise "tree map is not initialized" unless defined?(@guard) && @guard
270
+
271
+ @guard.synchronize(&)
272
+ end
273
+
274
+ def synchronized? = false
275
+
276
+ def check_local_frozen
277
+ raise FrozenError, "can't modify frozen #{self.class}" if mutation_frozen?
278
+ end
279
+
280
+ def mutation_frozen? = synchronized? ? frozen? : JVMContainers.frozen_object?(self)
281
+
282
+ def mutation_key(key)
283
+ Key.new(key, self)
284
+ end
285
+
286
+ def canonical_key(key)
287
+ JVMContainers.string?(key) ? JVMContainers.canonical_string(key) : key
288
+ end
289
+
290
+ def build_state(entries)
291
+ tree = JVMContainers::TreeMap.new(KEY_COMPARATOR)
292
+ entries&.each do |key, value|
293
+ check_uninitialized
294
+
295
+ stored_key = canonical_key(key)
296
+ check_uninitialized
297
+
298
+ wrapped_key = Key.new(stored_key, self)
299
+ begin
300
+ tree.put(wrapped_key, Value.new(value))
301
+ ensure
302
+ Thread.handle_interrupt(INTERRUPT_MASK) do
303
+ wrapped_key.mutation_owner = nil
304
+ end
305
+ end
306
+ check_uninitialized
307
+ end
308
+ State.new(tree, 0)
309
+ end
310
+
311
+ def check_uninitialized
312
+ raise "tree map is already initialized" if defined?(@state)
313
+ raise FrozenError, "can't modify frozen #{self.class}" if JVMContainers.frozen_object?(self)
314
+ end
315
+
316
+ def coerce_entries(entries)
317
+ return if entries.nil?
318
+ return entries if JVMContainers.is_a?(entries, Hash)
319
+
320
+ hash = entries.to_hash if entries.respond_to?(:to_hash)
321
+ return hash if JVMContainers.is_a?(hash, Hash)
322
+
323
+ raise TypeError, "entries must be a Hash or respond to #to_hash"
324
+ end
325
+ end
326
+
327
+ # Explicit unsynchronized JVM implementation.
328
+ class UnsafeTreeMap
329
+ include JVMTreeMapBackend
330
+ end
331
+
332
+ # Default JVM implementation: ordinary TreeMap under a coarse lock. The
333
+ # object itself is frozen, while its guarded Java backing map remains the
334
+ # controlled mutation boundary.
335
+ class TreeMap
336
+ include JVMTreeMapBackend
337
+
338
+ private
339
+
340
+ def synchronized? = true
341
+ end
342
+
343
+ MutableTreeMap = TreeMap
344
+
345
+ # No Ractors, no problems :)
346
+ ShareableTreeMap = TreeMap
347
+
348
+ private_constant :JVMTreeMapBackend
349
+ end
350
+ end
@@ -0,0 +1,180 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ # Loaded only by JRuby and TruffleRuby in JVM mode. The two runtimes expose
6
+ # different Java interop namespaces, so the rest of the container code goes
7
+ # through this deliberately small bridge.
8
+
9
+ module Farce
10
+ # @!visibility private
11
+ module Internal # :nodoc: all
12
+ module JVMContainers
13
+ CLASS_ALLOCATE_METHOD = Class.instance_method(:allocate)
14
+ BASIC_OBJECT_EQUAL_METHOD = BasicObject.instance_method(:equal?)
15
+ OBJECT_CLASS_METHOD = Object.instance_method(:class)
16
+ OBJECT_FREEZE_METHOD = Object.instance_method(:freeze)
17
+ OBJECT_FROZEN_METHOD = Object.instance_method(:frozen?)
18
+ OBJECT_ID_METHOD = BasicObject.instance_method(:__id__)
19
+ OBJECT_INSTANCE_VARIABLES_METHOD = Object.instance_method(:instance_variables)
20
+ OBJECT_INSTANCE_VARIABLE_GET_METHOD = Object.instance_method(:instance_variable_get)
21
+ OBJECT_INSTANCE_VARIABLE_SET_METHOD = Object.instance_method(:instance_variable_set)
22
+ OBJECT_IS_A_METHOD = Object.instance_method(:is_a?)
23
+ STRING_INITIALIZE_COPY_METHOD = String.instance_method(:initialize_copy)
24
+
25
+ if RUBY_ENGINE == "jruby"
26
+ ConcurrentHashMap = Java::JavaUtilConcurrent::ConcurrentHashMap
27
+ TreeMap = Java::JavaUtil::TreeMap
28
+ ArrayDeque = Java::JavaUtil::ArrayDeque
29
+ AtomicBoolean = Java::JavaUtilConcurrentAtomic::AtomicBoolean
30
+ AtomicLong = Java::JavaUtilConcurrentAtomic::AtomicLong
31
+ Comparator = Java::JavaUtil::Comparator
32
+ ReentrantLock = Java::JavaUtilConcurrentLocks::ReentrantLock
33
+ else
34
+ ConcurrentHashMap = Java.type("java.util.concurrent.ConcurrentHashMap")
35
+ TreeMap = Java.type("java.util.TreeMap")
36
+ ArrayDeque = Java.type("java.util.ArrayDeque")
37
+ AtomicBoolean = Java.type("java.util.concurrent.atomic.AtomicBoolean")
38
+ AtomicLong = Java.type("java.util.concurrent.atomic.AtomicLong")
39
+ Comparator = Java.type("java.util.Comparator")
40
+ ReentrantLock = Java.type("java.util.concurrent.locks.ReentrantLock")
41
+ end
42
+
43
+ module_function
44
+
45
+ def compare(left, right)
46
+ comparison = left <=> right
47
+ raise ArgumentError, "comparison failed" if comparison.nil?
48
+
49
+ # Match rb_cmpint: comparator results only need ordering against zero,
50
+ # they need not implement Numeric's #positive?/#negative?.
51
+ return 1 if comparison > 0 # rubocop:disable Style/NumericPredicate
52
+ return -1 if comparison < 0 # rubocop:disable Style/NumericPredicate
53
+
54
+ 0
55
+ end
56
+
57
+ # Passing a Ruby lambda through this Java method produces a concrete SAM
58
+ # proxy. This avoids TruffleRuby choosing TreeMap's Map constructor when
59
+ # a bare Ruby lambda could also look map-like to polyglot interop.
60
+ def comparator(&block) = Comparator.nullsFirst(block)
61
+
62
+ # TruffleRuby represents a Java null as Polyglot::ForeignNull. It reports
63
+ # nil? but is not the VM's Qnil, so safe navigation still invokes methods
64
+ # on it. Always normalize Java-returned nullable references explicitly.
65
+ def nullable(value) = value.nil? ? nil : value
66
+
67
+ # Call BasicObject's primitive directly so a payload cannot destabilize
68
+ # the cancellation index by overriding #__id__.
69
+ def identity_token(value) = OBJECT_ID_METHOD.bind_call(value)
70
+
71
+ # Identity deletion is part of the container contract, so it must not
72
+ # dispatch an overridable payload #equal?.
73
+ def identical?(left, right) = BASIC_OBJECT_EQUAL_METHOD.bind_call(left, right)
74
+
75
+ # Match rb_obj_freeze rather than dispatching to an overridable Ruby
76
+ # method while an initialized shared container is being published.
77
+ def freeze_object(value) = OBJECT_FREEZE_METHOD.bind_call(value)
78
+
79
+ # Frozen local containers must remain immutable even when a subclass
80
+ # overrides #frozen? and lies about the VM's object flag.
81
+ def frozen_object?(value) = OBJECT_FROZEN_METHOD.bind_call(value)
82
+
83
+ def is_a?(value, klass) = OBJECT_IS_A_METHOD.bind_call(value, klass)
84
+
85
+ def string?(value) = is_a?(value, String)
86
+
87
+ # Match String#-@ for ordinary Strings without dispatching an override.
88
+ # String subclasses retain the explicit primitive snapshot path because
89
+ # JRuby and TruffleRuby differ from CRuby around subclass #freeze hooks.
90
+ def canonical_string(value)
91
+ klass = OBJECT_CLASS_METHOD.bind_call(value)
92
+ return -value if identical?(klass, String)
93
+
94
+ copy_frozen_string(value)
95
+ end
96
+
97
+ # Preserve String subclasses and their comparison methods while
98
+ # bypassing overridable #dup, #initialize_copy, #class, and #freeze.
99
+ # This mirrors the primitive String snapshot used by native containers.
100
+ def copy_frozen_string(value)
101
+ klass = OBJECT_CLASS_METHOD.bind_call(value)
102
+ copy = CLASS_ALLOCATE_METHOD.bind_call(klass)
103
+ STRING_INITIALIZE_COPY_METHOD.bind_call(copy, value)
104
+ OBJECT_INSTANCE_VARIABLES_METHOD.bind_call(value).each do |name|
105
+ instance_value = OBJECT_INSTANCE_VARIABLE_GET_METHOD.bind_call(value, name)
106
+ OBJECT_INSTANCE_VARIABLE_SET_METHOD.bind_call(copy, name, instance_value)
107
+ end
108
+ freeze_object(copy)
109
+ end
110
+ end
111
+
112
+ class JVMOperationGuard
113
+ def initialize(synchronized:, label:, recursive_error: nil)
114
+ @lock = JVMContainers::ReentrantLock.new if synchronized
115
+ @label = label
116
+ @owner = nil
117
+ @recursive_error = recursive_error || (synchronized ? ThreadError : RuntimeError)
118
+ end
119
+
120
+ def synchronize(&)
121
+ # JRuby exposes a distinct Ruby Thread wrapper to sibling Fibers on the
122
+ # same Java thread. Normalize it before checking logical ownership so a
123
+ # reentrant Java lock cannot admit a sibling while callbacks hold state.
124
+ current = Internal.storage_thread(Thread.current)
125
+ if JVMContainers.identical?(@owner, current)
126
+ message = @recursive_error == ThreadError ? "recursive #{@label} access" :
127
+ "container cannot be modified during comparison"
128
+ raise @recursive_error, message
129
+ end
130
+
131
+ if @lock
132
+ synchronize_locked(current, &)
133
+ else
134
+ begin
135
+ @owner = current
136
+ yield
137
+ ensure
138
+ Thread.handle_interrupt(INTERRUPT_MASK) { @owner = nil }
139
+ end
140
+ end
141
+ end
142
+
143
+ private
144
+
145
+ # Querying the Java lock in ensure closes the tiny async-exception gap
146
+ # between ReentrantLock#lock returning and Ruby recording ownership.
147
+ # A cancellation while waiting sees false; one after acquisition always
148
+ # releases the lock, even if it arrived before @owner was assigned.
149
+ def synchronize_locked(current)
150
+ acquired = @lock.tryLock
151
+ unless acquired
152
+ # A blocking Java lock can strand the backing thread that must run the
153
+ # lock owner. CRuby uses a scheduler-aware native gate; JVM engines do
154
+ # not promise that extension, so fail safely on the contended path.
155
+ raise ThreadError, "shared JVM container contention cannot block a scheduled Fiber" if scheduled_fiber?
156
+
157
+ @lock.lock
158
+ end
159
+ @owner = current
160
+ yield
161
+ ensure
162
+ Thread.handle_interrupt(INTERRUPT_MASK) do
163
+ if @lock.isHeldByCurrentThread
164
+ @owner = nil
165
+ @lock.unlock
166
+ end
167
+ end
168
+ end
169
+
170
+ def scheduled_fiber?
171
+ return false unless Fiber.respond_to?(:scheduler)
172
+ return false if Fiber.current.respond_to?(:blocking?) && Fiber.current.blocking?
173
+
174
+ scheduler = Fiber.current_scheduler if Fiber.respond_to?(:current_scheduler)
175
+ scheduler ||= Fiber.scheduler
176
+ !scheduler.nil?
177
+ end
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ # Common atomic and ordered-container loader for JRuby and TruffleRuby in JVM mode.
6
+
7
+ module Farce
8
+ # @!visibility private
9
+ module Internal # :nodoc: all
10
+ autoload :ConcurrentWeakRegistry, "farce/engine/jvm/concurrent_weak_registry"
11
+ autoload :Counter, "farce/engine/jvm/counter"
12
+ autoload :Flag, "farce/engine/jvm/flag"
13
+ autoload :UnsafeTreeMap, "farce/engine/jvm/tree_map"
14
+ autoload :PriorityQueue, "farce/engine/jvm/priority_queue"
15
+ autoload :ShareableTreeMap, "farce/engine/jvm/tree_map"
16
+ autoload :TreeMap, "farce/engine/jvm/tree_map"
17
+ autoload :MutableTreeMap, "farce/engine/jvm/tree_map"
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ # shareable_constant_value: literal
3
+ # warn_indent: true
4
+
5
+ module Farce
6
+ module Internal
7
+ class FiberScheduler
8
+ # Ruby 3.4 can strand a control Ractor started alongside scheduled workers.
9
+ # Start it before admitting fibers. Ruby 4.x creates the selector lazily.
10
+ module RactorSelectorSetup
11
+ def initialize(...)
12
+ RactorSelector.current
13
+ super
14
+ end
15
+ end
16
+ private_constant :RactorSelectorSetup
17
+ prepend RactorSelectorSetup
18
+ end
19
+ end
20
+ end